diff --git a/autopilot/prefattach_test.go b/autopilot/prefattach_test.go index 78b738d3e..5439f02aa 100644 --- a/autopilot/prefattach_test.go +++ b/autopilot/prefattach_test.go @@ -31,12 +31,14 @@ type testGraph interface { } type testDBGraph struct { - db *graphdb.ChannelGraph + db *graphdb.VersionedGraph databaseChannelGraph } func newDiskChanGraph(t *testing.T) (testGraph, error) { - graphDB := graphdb.MakeTestGraph(t) + graphDB := graphdb.NewVersionedGraph( + graphdb.MakeTestGraph(t), lnwire.GossipVersion1, + ) require.NoError(t, graphDB.Start()) t.Cleanup(func() { require.NoError(t, graphDB.Stop()) diff --git a/graph/builder.go b/graph/builder.go index f9ce63eb8..3e1571396 100644 --- a/graph/builder.go +++ b/graph/builder.go @@ -111,7 +111,8 @@ type Builder struct { bestHeight atomic.Uint32 - cfg *Config + cfg *Config + v1Graph *graphdb.VersionedGraph // newBlocks is a channel in which new blocks connected to the end of // the main chain are sent over, and blocks updated after a call to @@ -146,7 +147,11 @@ var _ ChannelGraphSource = (*Builder)(nil) // NewBuilder constructs a new Builder. func NewBuilder(cfg *Config) (*Builder, error) { return &Builder{ - cfg: cfg, + cfg: cfg, + // For now, we'll just use V1 graph reader. + v1Graph: graphdb.NewVersionedGraph( + cfg.Graph, lnwire.GossipVersion1, + ), channelEdgeMtx: multimutex.NewMutex[uint64](), statTicker: ticker.New(defaultStatInterval), stats: new(builderStats), @@ -1266,7 +1271,7 @@ func (b *Builder) GetChannelByID(chanID lnwire.ShortChannelID) ( func (b *Builder) FetchNode(ctx context.Context, node route.Vertex) (*models.Node, error) { - return b.cfg.Graph.FetchNode(ctx, node) + return b.v1Graph.FetchNode(ctx, node) } // ForAllOutgoingChannels is used to iterate over all outgoing channels owned by diff --git a/graph/builder_test.go b/graph/builder_test.go index 72f271985..ca57a44c9 100644 --- a/graph/builder_test.go +++ b/graph/builder_test.go @@ -359,7 +359,7 @@ func TestWakeUpOnStaleBranch(t *testing.T) { // Create new router with same graph database. router, err := NewBuilder(&Config{ SelfNode: selfNode.PubKeyBytes, - Graph: ctx.graph, + Graph: ctx.graph.ChannelGraph, Chain: ctx.chain, ChainView: ctx.chainView, ChannelPruneExpiry: time.Hour * 24, @@ -1595,7 +1595,9 @@ func parseTestGraph(t *testing.T, useCache bool, path string) ( } return &testGraphInstance{ - graph: graph, + graph: graphdb.NewVersionedGraph( + graph, lnwire.GossipVersion1, + ), aliasMap: aliasMap, privKeyMap: privKeyMap, channelIDs: channelIDs, @@ -1690,7 +1692,7 @@ func asymmetricTestChannel(alias1, alias2 string, capacity btcutil.Amount, // assertChannelsPruned ensures that only the given channels are pruned from the // graph out of the set of all channels. -func assertChannelsPruned(t *testing.T, graph *graphdb.ChannelGraph, +func assertChannelsPruned(t *testing.T, graph *graphdb.VersionedGraph, channels []*testChannel, prunedChanIDs ...uint64) { t.Helper() @@ -1980,7 +1982,9 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, } return &testGraphInstance{ - graph: graph, + graph: graphdb.NewVersionedGraph( + graph, lnwire.GossipVersion1, + ), aliasMap: aliasMap, privKeyMap: privKeyMap, links: links, diff --git a/graph/db/graph.go b/graph/db/graph.go index 47df50e5a..ae7d93a73 100644 --- a/graph/db/graph.go +++ b/graph/db/graph.go @@ -293,23 +293,6 @@ func (c *ChannelGraph) AddNode(ctx context.Context, return nil } -// DeleteNode starts a new database transaction to remove a vertex/node -// from the database according to the node's public key. -func (c *ChannelGraph) DeleteNode(ctx context.Context, - nodePub route.Vertex) error { - - err := c.db.DeleteNode(ctx, lnwire.GossipVersion1, nodePub) - if err != nil { - return err - } - - if c.graphCache != nil { - c.graphCache.RemoveNode(nodePub) - } - - return nil -} - // AddChannelEdge adds a new (undirected, blank) edge to the graph database. An // undirected edge from the two target nodes are created. The information stored // denotes the static attributes of the channel, such as the channelID, the keys @@ -603,13 +586,6 @@ func (c *ChannelGraph) UpdateEdgePolicy(ctx context.Context, return nil } -// AddrsForNode returns all known addresses for the target node public key. -func (c *ChannelGraph) AddrsForNode(ctx context.Context, - nodePub *btcec.PublicKey) (bool, []net.Addr, error) { - - return c.db.AddrsForNode(ctx, lnwire.GossipVersion1, nodePub) -} - // ForEachSourceNodeChannel iterates through all channels of the source node. func (c *ChannelGraph) ForEachSourceNodeChannel(ctx context.Context, cb func(chanPoint wire.OutPoint, havePolicy bool, @@ -657,13 +633,6 @@ func (c *ChannelGraph) NodeUpdatesInHorizon(startTime, endTime time.Time, return c.db.NodeUpdatesInHorizon(startTime, endTime, opts...) } -// FetchNode attempts to look up a target node by its identity public key. -func (c *ChannelGraph) FetchNode(ctx context.Context, - nodePub route.Vertex) (*models.Node, error) { - - return c.db.FetchNode(ctx, lnwire.GossipVersion1, nodePub) -} - // HasV1Node determines if the graph has a vertex identified by the target node // in the V1 graph. func (c *ChannelGraph) HasV1Node(ctx context.Context, @@ -672,14 +641,6 @@ func (c *ChannelGraph) HasV1Node(ctx context.Context, 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, lnwire.GossipVersion1, nodePub) -} - // IsPublicNode determines whether the node is seen as public in the graph. func (c *ChannelGraph) IsPublicNode(pubKey [33]byte) (bool, error) { return c.db.IsPublicNode(pubKey) @@ -811,6 +772,62 @@ func (c *ChannelGraph) PruneTip() (*chainhash.Hash, uint32, error) { return c.db.PruneTip() } +// VersionedGraph is a wrapper around ChannelGraph that will call underlying +// Store methods with a specific gossip version. +type VersionedGraph struct { + *ChannelGraph + v lnwire.GossipVersion +} + +// NewVersionedGraph creates a new VersionedGraph. +func NewVersionedGraph(c *ChannelGraph, + v lnwire.GossipVersion) *VersionedGraph { + + return &VersionedGraph{ + ChannelGraph: c, + v: v, + } +} + +// FetchNode attempts to look up a target node by its identity public key. +func (c *VersionedGraph) FetchNode(ctx context.Context, + nodePub route.Vertex) (*models.Node, error) { + + return c.db.FetchNode(ctx, c.v, nodePub) +} + +// AddrsForNode returns all known addresses for the target node public key. +func (c *VersionedGraph) AddrsForNode(ctx context.Context, + nodePub *btcec.PublicKey) (bool, []net.Addr, error) { + + return c.db.AddrsForNode(ctx, c.v, nodePub) +} + +// DeleteNode starts a new database transaction to remove a vertex/node +// from the database according to the node's public key. +func (c *VersionedGraph) DeleteNode(ctx context.Context, + nodePub route.Vertex) error { + + err := c.db.DeleteNode(ctx, c.v, nodePub) + if err != nil { + return err + } + + if c.graphCache != nil { + c.graphCache.RemoveNode(nodePub) + } + + return nil +} + +// HasNode determines if the graph has a vertex identified by the target node +// in the V1 graph. +func (c *VersionedGraph) HasNode(ctx context.Context, nodePub [33]byte) (bool, + error) { + + return c.db.HasNode(ctx, c.v, nodePub) +} + // MakeTestGraph creates a new instance of the ChannelGraph for testing // purposes. The backing Store implementation depends on the version of // NewTestDB included in the current build. diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go index 16b08797a..ff54717a9 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -98,7 +98,7 @@ func TestNodeInsertionAndDeletion(t *testing.T) { t.Parallel() ctx := t.Context() - graph := MakeTestGraph(t) + graph := NewVersionedGraph(MakeTestGraph(t), lnwire.GossipVersion1) // We'd like to test basic insertion/deletion for vertexes from the // graph, so we'll create a test vertex to start with. @@ -123,7 +123,7 @@ func TestNodeInsertionAndDeletion(t *testing.T) { // without any errors. node := nodeWithAddrs(testAddrs) require.NoError(t, graph.AddNode(ctx, node)) - assertNodeInCache(t, graph, node, testFeatures) + assertNodeInCache(t, graph.ChannelGraph, node, testFeatures) // Our AddNode implementation uses the batcher meaning that it is // possible that two updates for the same node announcement may be @@ -153,16 +153,14 @@ func TestNodeInsertionAndDeletion(t *testing.T) { // Check that the node's features are fetched correctly. This check // will check the database directly. - features, err = graph.db.FetchNodeFeatures( - lnwire.GossipVersion1, node.PubKeyBytes, - ) + features, err = graph.FetchNodeFeatures(node.PubKeyBytes) require.NoError(t, err) require.Equal(t, testFeatures, features) // Next, delete the node from the graph, this should purge all data // related to the node. require.NoError(t, graph.DeleteNode(ctx, testPub)) - assertNodeNotInCache(t, graph, testPub) + assertNodeNotInCache(t, graph.ChannelGraph, testPub) // Attempting to delete the node again should return an error since // the node is no longer known. @@ -287,7 +285,7 @@ func TestPartialNode(t *testing.T) { t.Parallel() ctx := t.Context() - graph := MakeTestGraph(t) + graph := NewVersionedGraph(MakeTestGraph(t), lnwire.GossipVersion1) // To insert a partial node, we need to add a channel edge that has // node keys for nodes we are not yet aware @@ -301,8 +299,8 @@ func TestPartialNode(t *testing.T) { // Both of the nodes should now be in both the graph (as partial/shell) // nodes _and_ the cache should also have an awareness of both nodes. - assertNodeInCache(t, graph, &node1, nil) - assertNodeInCache(t, graph, &node2, nil) + assertNodeInCache(t, graph.ChannelGraph, &node1, nil) + assertNodeInCache(t, graph.ChannelGraph, &node2, nil) // Next, fetch the node2 from the database to ensure everything was // serialized properly. @@ -332,7 +330,7 @@ func TestPartialNode(t *testing.T) { // Next, delete the node from the graph, this should purge all data // related to the node. require.NoError(t, graph.DeleteNode(ctx, pubKey1)) - assertNodeNotInCache(t, graph, testPub) + assertNodeNotInCache(t, graph.ChannelGraph, testPub) // Finally, attempt to fetch the node again. This should fail as the // node should have been deleted from the database. @@ -3750,7 +3748,7 @@ func TestPruneGraphNodes(t *testing.T) { t.Parallel() ctx := t.Context() - graph := MakeTestGraph(t) + graph := NewVersionedGraph(MakeTestGraph(t), lnwire.GossipVersion1) // We'll start off by inserting our source node, to ensure that it's // the only node left after we prune the graph. @@ -3801,7 +3799,7 @@ func TestPruneGraphNodes(t *testing.T) { // source node (which can't be pruned), and node 1+2. Nodes 1 and two // should still be left in the graph as there's half of an advertised // edge between them. - assertNumNodes(t, graph, 3) + assertNumNodes(t, graph.ChannelGraph, 3) // Finally, we'll ensure that node3, the only fully unconnected node as // properly deleted from the graph and not another node in its place. @@ -3816,7 +3814,7 @@ func TestAddChannelEdgeShellNodes(t *testing.T) { t.Parallel() ctx := t.Context() - graph := MakeTestGraph(t) + graph := NewVersionedGraph(MakeTestGraph(t), lnwire.GossipVersion1) // To start, we'll create two nodes, and only add one of them to the // channel graph. @@ -3855,7 +3853,7 @@ func TestNodePruningUpdateIndexDeletion(t *testing.T) { t.Parallel() ctx := t.Context() - graph := MakeTestGraph(t) + graph := NewVersionedGraph(MakeTestGraph(t), lnwire.GossipVersion1) // We'll first populate our graph with a single node that will be // removed shortly. @@ -4836,7 +4834,7 @@ func TestLightningNodePersistence(t *testing.T) { ctx := t.Context() // Create a new test graph instance. - graph := MakeTestGraph(t) + graph := NewVersionedGraph(MakeTestGraph(t), lnwire.GossipVersion1) nodeAnnBytes, err := hex.DecodeString(testNodeAnn) require.NoError(t, err) diff --git a/graph/notifications_test.go b/graph/notifications_test.go index 3a30486c9..e3f48712e 100644 --- a/graph/notifications_test.go +++ b/graph/notifications_test.go @@ -1042,7 +1042,7 @@ func TestEncodeHexColor(t *testing.T) { type testCtx struct { builder *Builder - graph *graphdb.ChannelGraph + graph *graphdb.VersionedGraph aliases map[string]route.Vertex @@ -1059,7 +1059,9 @@ type testCtx struct { func createTestCtxSingleNode(t *testing.T, startingHeight uint32) *testCtx { - graph := graphdb.MakeTestGraph(t) + graph := graphdb.NewVersionedGraph( + graphdb.MakeTestGraph(t), lnwire.GossipVersion1, + ) sourceNode := createTestNode(t) require.NoError(t, @@ -1086,7 +1088,7 @@ func (c *testCtx) RestartBuilder(t *testing.T) { // start it. builder, err := NewBuilder(&Config{ SelfNode: selfNode.PubKeyBytes, - Graph: c.graph, + Graph: c.graph.ChannelGraph, Chain: c.chain, ChainView: c.chainView, Notifier: c.builder.cfg.Notifier, @@ -1108,7 +1110,7 @@ func (c *testCtx) RestartBuilder(t *testing.T) { } type testGraphInstance struct { - graph *graphdb.ChannelGraph + graph *graphdb.VersionedGraph // aliasMap is a map from a node's alias to its public key. This type is // provided in order to allow easily look up from the human memorable @@ -1157,7 +1159,7 @@ func createTestCtxFromGraphInstanceAssumeValid(t *testing.T, graphBuilder, err := NewBuilder(&Config{ SelfNode: selfnode.PubKeyBytes, - Graph: graphInstance.graph, + Graph: graphInstance.graph.ChannelGraph, Chain: chain, ChainView: chainView, Notifier: notifier, diff --git a/routing/router_test.go b/routing/router_test.go index 102afe85b..9dfe5c726 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -61,7 +61,8 @@ type testCtx struct { graphBuilder *mockGraphBuilder - graph *graphdb.ChannelGraph + graph *graphdb.ChannelGraph + v1Graph *graphdb.VersionedGraph aliases map[string]route.Vertex @@ -170,9 +171,12 @@ func createTestCtxFromGraphInstanceAssumeValid(t *testing.T, router: router, graphBuilder: graphBuilder, graph: graphInstance.graph, - aliases: graphInstance.aliasMap, - privKeys: graphInstance.privKeyMap, - channelIDs: graphInstance.channelIDs, + v1Graph: graphdb.NewVersionedGraph( + graphInstance.graph, lnwire.GossipVersion1, + ), + aliases: graphInstance.aliasMap, + privKeys: graphInstance.privKeyMap, + channelIDs: graphInstance.channelIDs, } t.Cleanup(func() { @@ -2717,11 +2721,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.v1Graph.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.v1Graph.HasNode(ctxb, pub2) require.NoError(t, err, "unable to query graph") require.False(t, exists2) @@ -2778,11 +2782,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.v1Graph.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.v1Graph.HasNode(ctxb, pub2) require.NoError(t, err, "unable to query graph") require.True(t, exists2) @@ -2907,12 +2911,12 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { _, _, err = ctx.router.FindRoute(req) require.NoError(t, err, "unable to find any routes") - copy1, err := ctx.graph.FetchNode(ctxb, pub1) + copy1, err := ctx.v1Graph.FetchNode(ctxb, pub1) require.NoError(t, err, "unable to fetch node") require.Equal(t, n1.Alias, copy1.Alias) - copy2, err := ctx.graph.FetchNode(ctxb, pub2) + copy2, err := ctx.v1Graph.FetchNode(ctxb, pub2) require.NoError(t, err, "unable to fetch node") require.Equal(t, n2.Alias, copy2.Alias) diff --git a/rpcserver.go b/rpcserver.go index f09278777..d465825dc 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 := s.v1Graph.HasNode(ctx, nodePub) return exists, err }, @@ -1821,7 +1821,7 @@ func (r *rpcServer) VerifyMessage(ctx context.Context, // channels signed the message. // // TODO(phlip9): Require valid nodes to have capital in active channels. - graph := r.server.graphDB + graph := r.server.v1Graph active, err := graph.HasNode(ctx, pub) if err != nil { return nil, fmt.Errorf("failed to query graph: %w", err) @@ -7143,7 +7143,7 @@ func (r *rpcServer) GetNodeInfo(ctx context.Context, "include_channels") } - graph := r.server.graphDB + graph := r.server.v1Graph // First, parse the hex-encoded public key into a full in-memory public // key object we can work with for querying. @@ -8298,7 +8298,7 @@ func (r *rpcServer) ForwardingHistory(ctx context.Context, return "", err } - peer, err := r.server.graphDB.FetchNode(ctx, vertex) + peer, err := r.server.v1Graph.FetchNode(ctx, vertex) if err != nil { return "", err } diff --git a/server.go b/server.go index 4e8ad037c..48c584ff0 100644 --- a/server.go +++ b/server.go @@ -321,6 +321,7 @@ type server struct { fundingMgr *funding.Manager graphDB *graphdb.ChannelGraph + v1Graph *graphdb.VersionedGraph chanStateDB *channeldb.ChannelStateDB @@ -669,12 +670,17 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr, HtlcInterceptor: invoiceHtlcModifier, } - addrSource := channeldb.NewMultiAddrSource(dbs.ChanStateDB, dbs.GraphDB) + v1Graph := graphdb.NewVersionedGraph( + dbs.GraphDB, lnwire.GossipVersion1, + ) + + addrSource := channeldb.NewMultiAddrSource(dbs.ChanStateDB, v1Graph) s := &server{ cfg: cfg, implCfg: implCfg, graphDB: dbs.GraphDB, + v1Graph: v1Graph, chanStateDB: dbs.ChanStateDB.ChannelStateDB(), addrSource: addrSource, miscDB: dbs.ChanStateDB, @@ -5207,7 +5213,7 @@ func (s *server) fetchNodeAdvertisedAddrs(ctx context.Context, return nil, err } - node, err := s.graphDB.FetchNode(ctx, vertex) + node, err := s.v1Graph.FetchNode(ctx, vertex) if err != nil { return nil, err }