Skip to content

Commit f1da381

Browse files
committed
graph/db+sqldb: impl IsPublicNode
Which lets us run `TestNodeIsPublic` against our SQL DB backends. Note that we need to tweak the tests a little bit so that `AddLightningNode` for the same node is always called with a newer LastUpdate time else it will fail the SQL constraint that only allows the upsert if the update is newer than the persisted one.
1 parent acae165 commit f1da381

File tree

5 files changed

+90
-9
lines changed

5 files changed

+90
-9
lines changed

graph/db/graph_test.go

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,11 @@ var (
7373
)
7474

7575
func createLightningNode(priv *btcec.PrivateKey) *models.LightningNode {
76-
updateTime := prand.Int63()
77-
7876
pub := priv.PubKey().SerializeCompressed()
7977
n := &models.LightningNode{
8078
HaveNodeAnnouncement: true,
8179
AuthSigBytes: testSig.Serialize(),
82-
LastUpdate: time.Unix(updateTime, 0),
80+
LastUpdate: time.Unix(nextUpdateTime(), 0),
8381
Color: color.RGBA{1, 2, 3, 0},
8482
Alias: "kek" + hex.EncodeToString(pub),
8583
Features: testFeatures,
@@ -3439,6 +3437,20 @@ func TestNodePruningUpdateIndexDeletion(t *testing.T) {
34393437
}
34403438
}
34413439

3440+
var (
3441+
updateTime = prand.Int63()
3442+
updateTimeMu sync.Mutex
3443+
)
3444+
3445+
func nextUpdateTime() int64 {
3446+
updateTimeMu.Lock()
3447+
defer updateTimeMu.Unlock()
3448+
3449+
updateTime++
3450+
3451+
return updateTime
3452+
}
3453+
34423454
// TestNodeIsPublic ensures that we properly detect nodes that are seen as
34433455
// public within the network graph.
34443456
func TestNodeIsPublic(t *testing.T) {
@@ -3453,19 +3465,19 @@ func TestNodeIsPublic(t *testing.T) {
34533465
// We'll need to create a separate database and channel graph for each
34543466
// participant to replicate real-world scenarios (private edges being in
34553467
// some graphs but not others, etc.).
3456-
aliceGraph := MakeTestGraph(t)
3468+
aliceGraph := MakeTestGraphNew(t)
34573469
aliceNode := createTestVertex(t)
34583470
if err := aliceGraph.SetSourceNode(ctx, aliceNode); err != nil {
34593471
t.Fatalf("unable to set source node: %v", err)
34603472
}
34613473

3462-
bobGraph := MakeTestGraph(t)
3474+
bobGraph := MakeTestGraphNew(t)
34633475
bobNode := createTestVertex(t)
34643476
if err := bobGraph.SetSourceNode(ctx, bobNode); err != nil {
34653477
t.Fatalf("unable to set source node: %v", err)
34663478
}
34673479

3468-
carolGraph := MakeTestGraph(t)
3480+
carolGraph := MakeTestGraphNew(t)
34693481
carolNode := createTestVertex(t)
34703482
if err := carolGraph.SetSourceNode(ctx, carolNode); err != nil {
34713483
t.Fatalf("unable to set source node: %v", err)
@@ -3481,13 +3493,13 @@ func TestNodeIsPublic(t *testing.T) {
34813493
graphs := []*ChannelGraph{aliceGraph, bobGraph, carolGraph}
34823494
for _, graph := range graphs {
34833495
for _, node := range nodes {
3496+
node.LastUpdate = time.Unix(nextUpdateTime(), 0)
34843497
err := graph.AddLightningNode(ctx, node)
34853498
require.NoError(t, err)
34863499
}
34873500
for _, edge := range edges {
3488-
if err := graph.AddChannelEdge(ctx, edge); err != nil {
3489-
t.Fatalf("unable to add edge: %v", err)
3490-
}
3501+
err := graph.AddChannelEdge(ctx, edge)
3502+
require.NoError(t, err)
34913503
}
34923504
}
34933505

graph/db/sql_store.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ type SQLQueries interface {
6262
GetNodesByLastUpdateRange(ctx context.Context, arg sqlc.GetNodesByLastUpdateRangeParams) ([]sqlc.Node, error)
6363
ListNodesPaginated(ctx context.Context, arg sqlc.ListNodesPaginatedParams) ([]sqlc.Node, error)
6464
ListNodeIDsAndPubKeys(ctx context.Context, arg sqlc.ListNodeIDsAndPubKeysParams) ([]sqlc.ListNodeIDsAndPubKeysRow, error)
65+
IsPublicV1Node(ctx context.Context, pubKey []byte) (bool, error)
6566
DeleteNodeByPubKey(ctx context.Context, arg sqlc.DeleteNodeByPubKeyParams) (sql.Result, error)
6667

6768
GetExtraNodeTypes(ctx context.Context, nodeID int64) ([]sqlc.NodeExtraType, error)
@@ -1990,6 +1991,29 @@ func (s *SQLStore) ChannelID(chanPoint *wire.OutPoint) (uint64, error) {
19901991
return channelID, nil
19911992
}
19921993

1994+
// IsPublicNode is a helper method that determines whether the node with the
1995+
// given public key is seen as a public node in the graph from the graph's
1996+
// source node's point of view.
1997+
//
1998+
// NOTE: part of the V1Store interface.
1999+
func (s *SQLStore) IsPublicNode(pubKey [33]byte) (bool, error) {
2000+
ctx := context.TODO()
2001+
2002+
var isPublic bool
2003+
err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
2004+
var err error
2005+
isPublic, err = db.IsPublicV1Node(ctx, pubKey[:])
2006+
2007+
return err
2008+
}, sqldb.NoOpReset)
2009+
if err != nil {
2010+
return false, fmt.Errorf("unable to check if node is "+
2011+
"public: %w", err)
2012+
}
2013+
2014+
return isPublic, nil
2015+
}
2016+
19932017
// FetchChanInfos returns the set of channel edges that correspond to the passed
19942018
// channel ID's. If an edge is the query is unknown to the database, it will
19952019
// skipped and the result will contain only those edges that exist at the time

sqldb/sqlc/graph.sql.go

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sqldb/sqlc/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sqldb/sqlc/queries/graph.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,24 @@ WHERE version = $1 AND id > $2
4747
ORDER BY id
4848
LIMIT $3;
4949

50+
-- name: IsPublicV1Node :one
51+
SELECT EXISTS (
52+
SELECT 1
53+
FROM channels c
54+
JOIN nodes n ON n.id = c.node_id_1 OR n.id = c.node_id_2
55+
-- NOTE: we hard-code the version here since the clauses
56+
-- here that determine if a node is public is specific
57+
-- to the V1 gossip protocol. In V1, a node is public
58+
-- if it has a public channel and a public channel is one
59+
-- where we have the set of signatures of the channel
60+
-- announcement. It is enough to just check that we have
61+
-- one of the signatures since we only ever set them
62+
-- together.
63+
WHERE c.version = 1
64+
AND c.bitcoin_1_signature IS NOT NULL
65+
AND n.pub_key = $1
66+
);
67+
5068
-- name: DeleteNodeByPubKey :execresult
5169
DELETE FROM nodes
5270
WHERE pub_key = $1

0 commit comments

Comments
 (0)