diff --git a/graph/builder.go b/graph/builder.go index 91040dd08..f9ce63eb8 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -874,7 +874,7 @@ func (b *Builder) assertNodeAnnFreshness(ctx context.Context, node route.Vertex, // node announcements, we will ignore such nodes. If we do know about // this node, check that this update brings info newer than what we // already have. - lastUpdate, exists, err := b.cfg.Graph.HasNode(ctx, node) + lastUpdate, exists, err := b.cfg.Graph.HasV1Node(ctx, node) if err != nil { return fmt.Errorf("unable to query for the "+ "existence of node: %w", err) diff --git a/graph/db/graph.go b/graph/db/graph.go index 13b9af300..e9bd4aafb 100644 --- a/graph/db/graph.go +++ b/graph/db/graph.go @@ -664,10 +664,19 @@ func (c *ChannelGraph) FetchNode(ctx context.Context, return c.db.FetchNode(ctx, nodePub) } -// HasNode determines if the graph has a vertex identified by the target node. -func (c *ChannelGraph) HasNode(ctx context.Context, +// HasV1Node determines if the graph has a vertex identified by the target node +// in the V1 graph. +func (c *ChannelGraph) HasV1Node(ctx context.Context, nodePub [33]byte) (time.Time, bool, error) { + return c.db.HasV1Node(ctx, nodePub) +} + +// HasNode determines if the graph has a vertex identified by the target node +// in the V1 graph. +func (c *ChannelGraph) HasNode(ctx context.Context, nodePub [33]byte) (bool, + error) { + return c.db.HasNode(ctx, nodePub) } diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go index 89729944c..c147b09fd 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -138,7 +138,7 @@ func TestNodeInsertionAndDeletion(t *testing.T) { dbNode, err := graph.FetchNode(ctx, testPub) require.NoError(t, err, "unable to locate node") - _, exists, err := graph.HasNode(ctx, dbNode.PubKeyBytes) + exists, err := graph.HasNode(ctx, dbNode.PubKeyBytes) require.NoError(t, err) require.True(t, exists) @@ -309,7 +309,7 @@ func TestPartialNode(t *testing.T) { dbNode2, err := graph.FetchNode(ctx, pubKey2) require.NoError(t, err) - _, exists, err := graph.HasNode(ctx, dbNode1.PubKeyBytes) + exists, err := graph.HasNode(ctx, dbNode1.PubKeyBytes) require.NoError(t, err) require.True(t, exists) @@ -318,7 +318,7 @@ func TestPartialNode(t *testing.T) { expectedNode1 := models.NewV1ShellNode(pubKey1) compareNodes(t, expectedNode1, dbNode1) - _, exists, err = graph.HasNode(ctx, dbNode2.PubKeyBytes) + exists, err = graph.HasNode(ctx, dbNode2.PubKeyBytes) require.NoError(t, err) require.True(t, exists) diff --git a/graph/db/interfaces.go b/graph/db/interfaces.go index 20408c904..59172833e 100644 --- a/graph/db/interfaces.go +++ b/graph/db/interfaces.go @@ -119,12 +119,19 @@ type Store interface { //nolint:interfacebloat FetchNode(ctx context.Context, nodePub route.Vertex) (*models.Node, error) + // HasV1Node determines if the graph has a vertex identified by + // the target node identity public key in the V1 graph. If the node + // exists in the database, a timestamp of when the data for the node + // was lasted updated is returned along with a true boolean. Otherwise, + // an empty time.Time is returned with a false boolean. + // This is specific to the V1 graph since only V1 node announcements + // use timestamps for their latest update timestamp. + HasV1Node(ctx context.Context, nodePub [33]byte) (time.Time, bool, + error) + // HasNode determines if the graph has a vertex identified by - // the target node identity public key. If the node exists in the - // database, a timestamp of when the data for the node was lasted - // updated is returned along with a true boolean. Otherwise, an empty - // time.Time is returned with a false boolean. - HasNode(ctx context.Context, nodePub [33]byte) (time.Time, bool, error) + // the target node identity public key. + HasNode(ctx context.Context, nodePub [33]byte) (bool, error) // IsPublicNode is a helper method that determines whether the node with // the given public key is seen as a public node in the graph from the diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go index 27c3bbadc..a582fd5e4 100644 --- a/graph/db/kv_store.go +++ b/graph/db/kv_store.go @@ -3433,11 +3433,12 @@ func (c *KVStore) fetchLightningNode(tx kvdb.RTx, return node, nil } -// HasNode determines if the graph has a vertex identified by the target node -// identity public key. If the node exists in the database, a timestamp of when -// the data for the node was lasted updated is returned along with a true -// boolean. Otherwise, an empty time.Time is returned with a false boolean. -func (c *KVStore) HasNode(_ context.Context, +// HasV1Node determines if the graph has a vertex identified by the +// target node identity public key. If the node exists in the database, a +// timestamp of when the data for the node was lasted updated is returned along +// with a true boolean. Otherwise, an empty time.Time is returned with a false +// boolean. +func (c *KVStore) HasV1Node(_ context.Context, nodePub [33]byte) (time.Time, bool, error) { var ( @@ -3457,7 +3458,6 @@ func (c *KVStore) HasNode(_ context.Context, // exit early. nodeBytes := nodes.Get(nodePub[:]) if nodeBytes == nil { - exists = false return nil } @@ -3485,6 +3485,38 @@ func (c *KVStore) HasNode(_ context.Context, return updateTime, exists, nil } +// HasNode determines if the graph has a vertex identified by the target node +// identity public key. +func (c *KVStore) HasNode(_ context.Context, nodePub [33]byte) (bool, error) { + var exists bool + err := kvdb.View(c.db, func(tx kvdb.RTx) error { + // First grab the nodes bucket which stores the mapping from + // pubKey to node information. + nodes := tx.ReadBucket(nodeBucket) + if nodes == nil { + return ErrGraphNotFound + } + + // If a key for this serialized public key isn't found, we can + // exit early. + nodeBytes := nodes.Get(nodePub[:]) + if nodeBytes == nil { + return nil + } + + exists = true + + return nil + }, func() { + exists = false + }) + if err != nil { + return exists, err + } + + return exists, nil +} + // nodeTraversal is used to traverse all channels of a node given by its // public key and passes channel information into the specified callback. // diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go index 55efabf15..d9fca5155 100644 --- a/graph/db/sql_store.go +++ b/graph/db/sql_store.go @@ -53,6 +53,7 @@ type SQLQueries interface { DeleteUnconnectedNodes(ctx context.Context) ([][]byte, error) DeleteNodeByPubKey(ctx context.Context, arg sqlc.DeleteNodeByPubKeyParams) (sql.Result, error) DeleteNode(ctx context.Context, id int64) error + NodeExists(ctx context.Context, arg sqlc.NodeExistsParams) (bool, error) GetExtraNodeTypes(ctx context.Context, nodeID int64) ([]sqlc.GraphNodeExtraType, error) GetNodeExtraTypesBatch(ctx context.Context, ids []int64) ([]sqlc.GraphNodeExtraType, error) @@ -283,14 +284,14 @@ func (s *SQLStore) FetchNode(ctx context.Context, return node, nil } -// HasNode determines if the graph has a vertex identified by the +// HasV1Node determines if the graph has a vertex identified by the // target node identity public key. If the node exists in the database, a // timestamp of when the data for the node was lasted updated is returned along // with a true boolean. Otherwise, an empty time.Time is returned with a false // boolean. // // NOTE: part of the Store interface. -func (s *SQLStore) HasNode(ctx context.Context, +func (s *SQLStore) HasV1Node(ctx context.Context, pubKey [33]byte) (time.Time, bool, error) { var ( @@ -326,6 +327,32 @@ func (s *SQLStore) HasNode(ctx context.Context, return lastUpdate, exists, nil } +// HasNode determines if the graph has a vertex identified by the +// target node identity public key. +// +// NOTE: part of the Store interface. +func (s *SQLStore) HasNode(ctx context.Context, pubKey [33]byte) (bool, error) { + var ( + v = lnwire.GossipVersion1 + exists bool + ) + err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error { + var err error + exists, err = db.NodeExists(ctx, sqlc.NodeExistsParams{ + Version: int16(v), + PubKey: pubKey[:], + }) + + return err + }, sqldb.NoOpReset) + if err != nil { + return false, fmt.Errorf("unable to check if node (%x) "+ + "exists: %w", pubKey, err) + } + + return exists, nil +} + // AddrsForNode returns all known addresses for the target node public key // that the graph DB is aware of. The returned boolean indicates if the // given node is unknown to the graph DB or not. diff --git a/routing/router_test.go b/routing/router_test.go index 9f088917d..102afe85b 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -2717,11 +2717,11 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { copy(pub2[:], priv2.PubKey().SerializeCompressed()) // The two nodes we are about to add should not exist yet. - _, exists1, err := ctx.graph.HasNode(ctxb, pub1) + exists1, err := ctx.graph.HasNode(ctxb, pub1) require.NoError(t, err, "unable to query graph") require.False(t, exists1) - _, exists2, err := ctx.graph.HasNode(ctxb, pub2) + exists2, err := ctx.graph.HasNode(ctxb, pub2) require.NoError(t, err, "unable to query graph") require.False(t, exists2) @@ -2778,11 +2778,11 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { // After adding the edge between the two previously unknown nodes, they // should have been added to the graph. - _, exists1, err = ctx.graph.HasNode(ctxb, pub1) + exists1, err = ctx.graph.HasNode(ctxb, pub1) require.NoError(t, err, "unable to query graph") require.True(t, exists1) - _, exists2, err = ctx.graph.HasNode(ctxb, pub2) + exists2, err = ctx.graph.HasNode(ctxb, pub2) require.NoError(t, err, "unable to query graph") require.True(t, exists2) diff --git a/rpcserver.go b/rpcserver.go index fe0e6702b..f09278777 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -746,7 +746,7 @@ func (r *rpcServer) addDeps(ctx context.Context, s *server, return info.NodeKey1Bytes, info.NodeKey2Bytes, nil }, HasNode: func(nodePub route.Vertex) (bool, error) { - _, exists, err := graph.HasNode(ctx, nodePub) + exists, err := graph.HasNode(ctx, nodePub) return exists, err }, @@ -1822,7 +1822,7 @@ func (r *rpcServer) VerifyMessage(ctx context.Context, // // TODO(phlip9): Require valid nodes to have capital in active channels. graph := r.server.graphDB - _, active, err := graph.HasNode(ctx, pub) + active, err := graph.HasNode(ctx, pub) if err != nil { return nil, fmt.Errorf("failed to query graph: %w", err) }