From 7bb38651d941feb23870180e530901450ee18ec6 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Sun, 26 Oct 2025 17:46:50 +0200 Subject: [PATCH] graph/db: convert other node CRUD methods Convert a few more CRUD methods to handle v2 nodes. Then update some more tests to be run against both v1 and v2 nodes. --- graph/db/graph.go | 26 ++++++++------- graph/db/graph_test.go | 27 +++++++++------ graph/db/sql_store.go | 2 +- routing/pathfind_test.go | 72 +++++++++++++++++++++++----------------- routing/router_test.go | 6 ++-- rpcserver.go | 6 ++-- server.go | 6 ++-- 7 files changed, 82 insertions(+), 63 deletions(-) diff --git a/graph/db/graph.go b/graph/db/graph.go index ae7d93a73..3fbb00e93 100644 --- a/graph/db/graph.go +++ b/graph/db/graph.go @@ -618,13 +618,6 @@ func (c *ChannelGraph) ForEachNodeCacheable(ctx context.Context, return c.db.ForEachNodeCacheable(ctx, cb, reset) } -// LookupAlias attempts to return the alias as advertised by the target node. -func (c *ChannelGraph) LookupAlias(ctx context.Context, - pub *btcec.PublicKey) (string, error) { - - return c.db.LookupAlias(ctx, lnwire.GossipVersion1, pub) -} - // NodeUpdatesInHorizon returns all known lightning nodes with updates in the // range. func (c *ChannelGraph) NodeUpdatesInHorizon(startTime, endTime time.Time, @@ -755,11 +748,6 @@ func (c *ChannelGraph) IsClosedScid(scid lnwire.ShortChannelID) (bool, error) { return c.db.IsClosedScid(scid) } -// SourceNode returns the source node of the graph. -func (c *ChannelGraph) SourceNode(ctx context.Context) (*models.Node, error) { - return c.db.SourceNode(ctx, lnwire.GossipVersion1) -} - // SetSourceNode sets the source node within the graph database. func (c *ChannelGraph) SetSourceNode(ctx context.Context, node *models.Node) error { @@ -828,6 +816,20 @@ func (c *VersionedGraph) HasNode(ctx context.Context, nodePub [33]byte) (bool, return c.db.HasNode(ctx, c.v, nodePub) } +// LookupAlias attempts to return the alias as advertised by the target node. +func (c *VersionedGraph) LookupAlias(ctx context.Context, + pub *btcec.PublicKey) (string, error) { + + return c.db.LookupAlias(ctx, c.v, pub) +} + +// SourceNode returns the source node of the graph. +func (c *VersionedGraph) SourceNode(ctx context.Context) (*models.Node, + error) { + + return c.db.SourceNode(ctx, c.v) +} + // 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 d7ceb06aa..33d1b2bbe 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -130,6 +130,14 @@ var versionedTests = []versionedTest{ name: "node crud", test: testNodeInsertionAndDeletion, }, + { + name: "source node", + test: testSourceNode, + }, + { + name: "alias lookup", + test: testAliasLookup, + }, } // TestVersionedDBs runs various tests against both v1 and v2 versioned @@ -414,16 +422,15 @@ func TestPartialNode(t *testing.T) { require.ErrorIs(t, err, ErrGraphNodeNotFound) } -// TestAliasLookup tests the alias lookup functionality of the graph store. -func TestAliasLookup(t *testing.T) { - t.Parallel() +// testAliasLookup tests the alias lookup functionality of the graph store. +func testAliasLookup(t *testing.T, v lnwire.GossipVersion) { ctx := t.Context() - graph := MakeTestGraph(t) + graph := NewVersionedGraph(MakeTestGraph(t), v) // We'd like to test the alias index within the database, so first // create a new test node. - testNode := createTestVertex(t, lnwire.GossipVersion1) + testNode := createTestVertex(t, v) // Add the node to the graph's database, this should also insert an // entry into the alias index for this node. @@ -438,23 +445,23 @@ func TestAliasLookup(t *testing.T) { require.Equal(t, testNode.Alias.UnwrapOr(""), dbAlias) // Ensure that looking up a non-existent alias results in an error. - node := createTestVertex(t, lnwire.GossipVersion1) + node := createTestVertex(t, v) nodePub, err = node.PubKey() require.NoError(t, err, "unable to generate pubkey") _, err = graph.LookupAlias(ctx, nodePub) require.ErrorIs(t, err, ErrNodeAliasNotFound) } -// TestSourceNode tests the source node functionality of the graph store. -func TestSourceNode(t *testing.T) { +// testSourceNode tests the source node functionality of the graph store. +func testSourceNode(t *testing.T, v lnwire.GossipVersion) { t.Parallel() ctx := t.Context() - graph := MakeTestGraph(t) + graph := NewVersionedGraph(MakeTestGraph(t), v) // We'd like to test the setting/getting of the source node, so we // first create a fake node to use within the test. - testNode := createTestVertex(t, lnwire.GossipVersion1) + testNode := createTestVertex(t, v) // Attempt to fetch the source node, this should return an error as the // source node hasn't yet been set. diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go index 0df0985b7..2c794fa95 100644 --- a/graph/db/sql_store.go +++ b/graph/db/sql_store.go @@ -524,7 +524,7 @@ func (s *SQLStore) SourceNode(ctx context.Context, err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error { _, nodePub, err := s.getSourceNode(ctx, db, v) if err != nil { - return fmt.Errorf("unable to fetch V1 source node: %w", + return fmt.Errorf("unable to fetch source node: %w", err) } diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index 473bd413e..132d61fb8 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -417,7 +417,10 @@ func parseTestGraph(t *testing.T, useCache bool, path string) ( } return &testGraphInstance{ - graph: graph, + graph: graph, + v1Graph: graphdb.NewVersionedGraph( + graph, lnwire.GossipVersion1, + ), mcBackend: mcBackend, aliasMap: aliasMap, privKeyMap: privKeyMap, @@ -487,6 +490,7 @@ type testChannel struct { type testGraphInstance struct { graph *graphdb.ChannelGraph + v1Graph *graphdb.VersionedGraph mcBackend kvdb.Backend // aliasMap is a map from a node's alias to its public key. This type is @@ -781,7 +785,10 @@ func createTestGraphFromChannels(t *testing.T, useCache bool, } return &testGraphInstance{ - graph: graph, + graph: graph, + v1Graph: graphdb.NewVersionedGraph( + graph, lnwire.GossipVersion1, + ), mcBackend: graphBackend, aliasMap: aliasMap, privKeyMap: privKeyMap, @@ -1095,7 +1102,7 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc expectedHops := test.expectedHops expectedHopCount := len(expectedHops) - sourceNode, err := graphInstance.graph.SourceNode(ctx) + sourceNode, err := graphInstance.v1Graph.SourceNode(ctx) require.NoError(t, err, "unable to fetch source node") sourceVertex := route.Vertex(sourceNode.PubKeyBytes) @@ -1107,7 +1114,7 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc paymentAmt := lnwire.NewMSatFromSatoshis(test.paymentAmt) target := graphInstance.aliasMap[test.target] path, err := dbFindPath( - graphInstance.graph, nil, &mockBandwidthHints{}, + graphInstance.v1Graph, nil, &mockBandwidthHints{}, &RestrictParams{ FeeLimit: test.feeLimit, ProbabilitySource: noProbabilitySource, @@ -1237,7 +1244,7 @@ func runPathFindingWithAdditionalEdges(t *testing.T, useCache bool) { ctx := t.Context() - sourceNode, err := graph.graph.SourceNode(ctx) + sourceNode, err := graph.v1Graph.SourceNode(ctx) require.NoError(t, err, "unable to fetch source node") paymentAmt := lnwire.NewMSatFromSatoshis(100) @@ -1282,7 +1289,8 @@ func runPathFindingWithAdditionalEdges(t *testing.T, useCache bool) { []*unifiedEdge, error) { return dbFindPath( - graph.graph, additionalEdges, &mockBandwidthHints{}, + graph.v1Graph, additionalEdges, + &mockBandwidthHints{}, r, testPathFindingConfig, sourceNode.PubKeyBytes, doge.PubKeyBytes, paymentAmt, 0, 0, @@ -1322,7 +1330,7 @@ func runPathFindingWithBlindedPathDuplicateHop(t *testing.T, useCache bool) { ctx := t.Context() - sourceNode, err := graph.graph.SourceNode(ctx) + sourceNode, err := graph.v1Graph.SourceNode(ctx) require.NoError(t, err, "unable to fetch source node") paymentAmt := lnwire.NewMSatFromSatoshis(100) @@ -1396,7 +1404,7 @@ func runPathFindingWithBlindedPathDuplicateHop(t *testing.T, useCache bool) { []*unifiedEdge, error) { return dbFindPath( - graph.graph, blindedPath, &mockBandwidthHints{}, + graph.v1Graph, blindedPath, &mockBandwidthHints{}, r, testPathFindingConfig, sourceNode.PubKeyBytes, dummyTarget, paymentAmt, 0, 0, @@ -1456,7 +1464,7 @@ func runPathFindingWithRedundantAdditionalEdges(t *testing.T, useCache bool) { } path, err := dbFindPath( - ctx.graph, additionalEdges, ctx.bandwidthHints, + ctx.v1Graph, additionalEdges, ctx.bandwidthHints, &ctx.restrictParams, &ctx.pathFindingConfig, ctx.source, target, paymentAmt, ctx.timePref, 0, ) @@ -1809,7 +1817,7 @@ func runPathNotAvailable(t *testing.T, useCache bool) { ctx := t.Context() - sourceNode, err := graph.graph.SourceNode(ctx) + sourceNode, err := graph.v1Graph.SourceNode(ctx) require.NoError(t, err, "unable to fetch source node") // With the test graph loaded, we'll test that queries for target that @@ -1822,7 +1830,7 @@ func runPathNotAvailable(t *testing.T, useCache bool) { copy(unknownNode[:], unknownNodeBytes) _, err = dbFindPath( - graph.graph, nil, &mockBandwidthHints{}, + graph.v1Graph, nil, &mockBandwidthHints{}, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, unknownNode, 100, 0, 0, ) @@ -1865,14 +1873,14 @@ func runDestTLVGraphFallback(t *testing.T, useCache bool) { ctx := newPathFindingTestContext(t, useCache, testChannels, "roasbeef") - sourceNode, err := ctx.graph.SourceNode(t.Context()) + sourceNode, err := ctx.v1Graph.SourceNode(t.Context()) require.NoError(t, err, "unable to fetch source node") find := func(r *RestrictParams, target route.Vertex) ([]*unifiedEdge, error) { return dbFindPath( - ctx.graph, nil, &mockBandwidthHints{}, + ctx.v1Graph, nil, &mockBandwidthHints{}, r, testPathFindingConfig, sourceNode.PubKeyBytes, target, 100, 0, 0, ) @@ -2084,7 +2092,7 @@ func runPathInsufficientCapacity(t *testing.T, useCache bool) { require.NoError(t, err, "unable to create graph") ctx := t.Context() - sourceNode, err := graph.graph.SourceNode(ctx) + sourceNode, err := graph.v1Graph.SourceNode(ctx) require.NoError(t, err, "unable to fetch source node") // Next, test that attempting to find a path in which the current @@ -2099,7 +2107,7 @@ func runPathInsufficientCapacity(t *testing.T, useCache bool) { payAmt := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) _, err = dbFindPath( - graph.graph, nil, &mockBandwidthHints{}, + graph.v1Graph, nil, &mockBandwidthHints{}, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, payAmt, 0, 0, ) @@ -2115,7 +2123,7 @@ func runRouteFailMinHTLC(t *testing.T, useCache bool) { require.NoError(t, err, "unable to create graph") ctx := t.Context() - sourceNode, err := graph.graph.SourceNode(ctx) + sourceNode, err := graph.v1Graph.SourceNode(ctx) require.NoError(t, err, "unable to fetch source node") // We'll not attempt to route an HTLC of 10 SAT from roasbeef to Son @@ -2124,7 +2132,7 @@ func runRouteFailMinHTLC(t *testing.T, useCache bool) { target := graph.aliasMap["songoku"] payAmt := lnwire.MilliSatoshi(10) _, err = dbFindPath( - graph.graph, nil, &mockBandwidthHints{}, + graph.v1Graph, nil, &mockBandwidthHints{}, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, payAmt, 0, 0, ) @@ -2200,7 +2208,7 @@ func runRouteFailDisabledEdge(t *testing.T, useCache bool) { require.NoError(t, err, "unable to create graph") ctx := t.Context() - sourceNode, err := graph.graph.SourceNode(ctx) + sourceNode, err := graph.v1Graph.SourceNode(ctx) require.NoError(t, err, "unable to fetch source node") // First, we'll try to route from roasbeef -> sophon. This should @@ -2208,7 +2216,7 @@ func runRouteFailDisabledEdge(t *testing.T, useCache bool) { target := graph.aliasMap["sophon"] payAmt := lnwire.NewMSatFromSatoshis(105000) _, err = dbFindPath( - graph.graph, nil, &mockBandwidthHints{}, + graph.v1Graph, nil, &mockBandwidthHints{}, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, payAmt, 0, 0, ) @@ -2232,7 +2240,7 @@ func runRouteFailDisabledEdge(t *testing.T, useCache bool) { } _, err = dbFindPath( - graph.graph, nil, &mockBandwidthHints{}, + graph.v1Graph, nil, &mockBandwidthHints{}, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, payAmt, 0, 0, ) @@ -2252,7 +2260,7 @@ func runRouteFailDisabledEdge(t *testing.T, useCache bool) { // If we attempt to route through that edge, we should get a failure as // it is no longer eligible. _, err = dbFindPath( - graph.graph, nil, &mockBandwidthHints{}, + graph.v1Graph, nil, &mockBandwidthHints{}, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, payAmt, 0, 0, ) @@ -2269,7 +2277,7 @@ func runPathSourceEdgesBandwidth(t *testing.T, useCache bool) { require.NoError(t, err, "unable to create graph") ctx := t.Context() - sourceNode, err := graph.graph.SourceNode(ctx) + sourceNode, err := graph.v1Graph.SourceNode(ctx) require.NoError(t, err, "unable to fetch source node") // First, we'll try to route from roasbeef -> sophon. This should @@ -2278,7 +2286,7 @@ func runPathSourceEdgesBandwidth(t *testing.T, useCache bool) { target := graph.aliasMap["sophon"] payAmt := lnwire.NewMSatFromSatoshis(50000) path, err := dbFindPath( - graph.graph, nil, &mockBandwidthHints{}, + graph.v1Graph, nil, &mockBandwidthHints{}, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, payAmt, 0, 0, ) @@ -2299,7 +2307,7 @@ func runPathSourceEdgesBandwidth(t *testing.T, useCache bool) { // Since both these edges has a bandwidth of zero, no path should be // found. _, err = dbFindPath( - graph.graph, nil, bandwidths, + graph.v1Graph, nil, bandwidths, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, payAmt, 0, 0, ) @@ -2314,7 +2322,7 @@ func runPathSourceEdgesBandwidth(t *testing.T, useCache bool) { // Now, if we attempt to route again, we should find the path via // phamnuven, as the other source edge won't be considered. path, err = dbFindPath( - graph.graph, nil, bandwidths, + graph.v1Graph, nil, bandwidths, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, payAmt, 0, 0, ) @@ -2340,7 +2348,7 @@ func runPathSourceEdgesBandwidth(t *testing.T, useCache bool) { // Since we ignore disable flags for local channels, a path should // still be found. path, err = dbFindPath( - graph.graph, nil, bandwidths, + graph.v1Graph, nil, bandwidths, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, payAmt, 0, 0, ) @@ -3184,6 +3192,7 @@ func runInboundFees(t *testing.T, useCache bool) { type pathFindingTestContext struct { t *testing.T graph *graphdb.ChannelGraph + v1Graph *graphdb.VersionedGraph restrictParams RestrictParams bandwidthHints bandwidthHints pathFindingConfig PathFindingConfig @@ -3201,7 +3210,7 @@ func newPathFindingTestContext(t *testing.T, useCache bool, ) require.NoError(t, err, "unable to create graph") - sourceNode, err := testGraphInstance.graph.SourceNode( + sourceNode, err := testGraphInstance.v1Graph.SourceNode( t.Context(), ) require.NoError(t, err, "unable to fetch source node") @@ -3212,6 +3221,7 @@ func newPathFindingTestContext(t *testing.T, useCache bool, source: route.Vertex(sourceNode.PubKeyBytes), pathFindingConfig: *testPathFindingConfig, graph: testGraphInstance.graph, + v1Graph: testGraphInstance.v1Graph, restrictParams: *noRestrictions, bandwidthHints: &mockBandwidthHints{}, } @@ -3247,7 +3257,7 @@ func (c *pathFindingTestContext) findPath(target route.Vertex, error) { return dbFindPath( - c.graph, nil, c.bandwidthHints, &c.restrictParams, + c.v1Graph, nil, c.bandwidthHints, &c.restrictParams, &c.pathFindingConfig, c.source, target, amt, c.timePref, 0, ) } @@ -3255,7 +3265,7 @@ func (c *pathFindingTestContext) findPath(target route.Vertex, func (c *pathFindingTestContext) findBlindedPaths( restrictions *blindedPathRestrictions) ([][]blindedHop, error) { - return dbFindBlindedPaths(c.graph, restrictions) + return dbFindBlindedPaths(c.v1Graph, restrictions) } func (c *pathFindingTestContext) assertPath(path []*unifiedEdge, @@ -3277,7 +3287,7 @@ func (c *pathFindingTestContext) assertPath(path []*unifiedEdge, // dbFindPath calls findPath after getting a db transaction from the database // graph. -func dbFindPath(graph *graphdb.ChannelGraph, +func dbFindPath(graph *graphdb.VersionedGraph, additionalEdges map[route.Vertex][]AdditionalEdge, bandwidthHints bandwidthHints, r *RestrictParams, cfg *PathFindingConfig, @@ -3315,7 +3325,7 @@ func dbFindPath(graph *graphdb.ChannelGraph, // dbFindBlindedPaths calls findBlindedPaths after getting a db transaction from // the database graph. -func dbFindBlindedPaths(graph *graphdb.ChannelGraph, +func dbFindBlindedPaths(graph *graphdb.VersionedGraph, restrictions *blindedPathRestrictions) ([][]blindedHop, error) { sourceNode, err := graph.SourceNode(context.Background()) diff --git a/routing/router_test.go b/routing/router_test.go index 9dfe5c726..cb4393c06 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -132,7 +132,7 @@ func createTestCtxFromGraphInstanceAssumeValid(t *testing.T, ) require.NoError(t, err) - sourceNode, err := graphInstance.graph.SourceNode(t.Context()) + sourceNode, err := graphInstance.v1Graph.SourceNode(t.Context()) require.NoError(t, err) sessionSource := &SessionSource{ GraphSessionFactory: graphInstance.graph, @@ -1205,7 +1205,7 @@ func TestFindPathFeeWeighting(t *testing.T) { var preImage [32]byte copy(preImage[:], bytes.Repeat([]byte{9}, 32)) - sourceNode, err := ctx.graph.SourceNode(t.Context()) + sourceNode, err := ctx.v1Graph.SourceNode(t.Context()) require.NoError(t, err, "unable to fetch source node") amt := lnwire.MilliSatoshi(100) @@ -1216,7 +1216,7 @@ func TestFindPathFeeWeighting(t *testing.T) { // the edge weighting, we should select the direct path over the 2 hop // path even though the direct path has a higher potential time lock. path, err := dbFindPath( - ctx.graph, nil, &mockBandwidthHints{}, + ctx.v1Graph, nil, &mockBandwidthHints{}, noRestrictions, testPathFindingConfig, sourceNode.PubKeyBytes, target, amt, 0, 0, diff --git a/rpcserver.go b/rpcserver.go index d465825dc..06e015507 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -704,7 +704,7 @@ func (r *rpcServer) addDeps(ctx context.Context, s *server, invoiceHtlcModifier *invoices.HtlcModificationInterceptor) error { // Set up router rpc backend. - selfNode, err := s.graphDB.SourceNode(ctx) + selfNode, err := s.v1Graph.SourceNode(ctx) if err != nil { return err } @@ -4995,7 +4995,7 @@ func createRPCOpenChannel(ctx context.Context, r *rpcServer, // Look up our channel peer's node alias if the caller requests it. if peerAliasLookup { - peerAlias, err := r.server.graphDB.LookupAlias(ctx, nodePub) + peerAlias, err := r.server.v1Graph.LookupAlias(ctx, nodePub) if err != nil { peerAlias = fmt.Sprintf("unable to lookup "+ "peer alias: %v", err) @@ -7909,7 +7909,7 @@ const feeBase float64 = 1000000 func (r *rpcServer) FeeReport(ctx context.Context, _ *lnrpc.FeeReportRequest) (*lnrpc.FeeReportResponse, error) { - channelGraph := r.server.graphDB + channelGraph := r.server.v1Graph selfNode, err := channelGraph.SourceNode(ctx) if err != nil { return nil, err diff --git a/server.go b/server.go index 48c584ff0..78b1971e1 100644 --- a/server.go +++ b/server.go @@ -988,7 +988,7 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr, MinProbability: routingConfig.MinRouteProbability, } - sourceNode, err := dbs.GraphDB.SourceNode(ctx) + sourceNode, err := s.v1Graph.SourceNode(ctx) if err != nil { return nil, fmt.Errorf("error getting source node: %w", err) } @@ -3440,7 +3440,7 @@ func (s *server) updateAndBroadcastSelfNode(ctx context.Context, // Update the on-disk version of our announcement. // Load and modify self node istead of creating anew instance so we // don't risk overwriting any existing values. - selfNode, err := s.graphDB.SourceNode(ctx) + selfNode, err := s.v1Graph.SourceNode(ctx) if err != nil { return fmt.Errorf("unable to get current source node: %w", err) } @@ -5624,7 +5624,7 @@ func (s *server) setSelfNode(ctx context.Context, nodePub route.Vertex, nodeLastUpdate = time.Now() ) - srcNode, err := s.graphDB.SourceNode(ctx) + srcNode, err := s.v1Graph.SourceNode(ctx) switch { case err == nil: // If we have a source node persisted in the DB already, then we