What changed, and why it matters
This commit is a small internal cleanup: it threads a Go request-lifecycle 'context' through the GraphSession database-query helper so callers can cancel or time out graph lookups. The only concrete behavior change is in the SQL backend, where a hard-coded placeholder context.TODO() is replaced by the caller-supplied context. There is no direct security fix, exploit, or vulnerability visible in the diff, but it removes a future foot-gun where graph queries could not respect cancellation/timeouts.
No immediate action required. Treat as routine refactoring. If auditing, verify that all production call sites of GraphSession eventually pass a real, cancellable context rather than context.TODO()/context.Background(), so graph queries honor request deadlines and resource exhaustion is less likely.
Security signals we found
context propagation refactor
SQLStore replaces context.TODO() with caller-supplied context
no bounds, auth, crypto, or input-validation changes
no vendor security disclosure or CVE references present
Evidence from the diff
The change updates the GraphSession method signature across ChannelGraph, Store interface, KVStore, SQLStore, routing GraphSessionFactory, and test mocks to accept a context.Context. KVStore ignores the context (underscore receiver), preserving existing behavior. SQLStore now uses the passed ctx in ExecTx instead of context.TODO(). routing/payment_session.go passes context.TODO() at the call site, so no new cancellation behavior is introduced there yet. The commit is plumbing/refactoring with one minor correctness improvement (SQLStore respects caller context).
Changed components
graph/db/graph.gograph/db/interfaces.gograph/db/kv_store.gograph/db/sql_store.gorouting/graph.gorouting/payment_session.gorouting/mock_graph_test.gorouting/pathfind_test.gorouting/payment_session_test.goInspect captured patch +19 / −16
diff --git a/graph/db/graph.go b/graph/db/graph.go
index eaf3526..a1eb2e3 100644
--- a/graph/db/graph.go
+++ b/graph/db/graph.go
@@ -253,14 +253,14 @@ func (c *ChannelGraph) FetchNodeFeatures(ctx context.Context,
// instance which can be used to perform queries against the channel graph. If
// the graph cache is not enabled, then the call-back will be provided with
// access to the graph via a consistent read-only transaction.
-func (c *ChannelGraph) GraphSession(cb func(graph NodeTraverser) error,
- reset func()) error {
+func (c *ChannelGraph) GraphSession(ctx context.Context,
+ cb func(graph NodeTraverser) error, reset func()) error {
if c.graphCache != nil {
return cb(c)
}
- return c.db.GraphSession(cb, reset)
+ return c.db.GraphSession(ctx, cb, reset)
}
// ForEachNodeCached iterates through all the stored vertices/nodes in the
diff --git a/graph/db/interfaces.go b/graph/db/interfaces.go
index 06c74c9..f507162 100644
--- a/graph/db/interfaces.go
+++ b/graph/db/interfaces.go
@@ -156,7 +156,8 @@ type Store interface { //nolint:interfacebloat
// GraphSession will provide the call-back with access to a
// NodeTraverser instance which can be used to perform queries against
// the channel graph.
- GraphSession(cb func(graph NodeTraverser) error, reset func()) error
+ GraphSession(ctx context.Context,
+ cb func(graph NodeTraverser) error, reset func()) error
// ForEachChannel iterates through all the channel edges stored within
// the graph and invokes the passed callback for each edge. The callback
diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go
index a353257..c202d76 100644
--- a/graph/db/kv_store.go
+++ b/graph/db/kv_store.go
@@ -4487,8 +4487,8 @@ func (c *KVStore) IsClosedScid(_ context.Context,
// GraphSession will provide the call-back with access to a NodeTraverser
// instance which can be used to perform queries against the channel graph.
-func (c *KVStore) GraphSession(cb func(graph NodeTraverser) error,
- reset func()) error {
+func (c *KVStore) GraphSession(_ context.Context,
+ cb func(graph NodeTraverser) error, reset func()) error {
return c.db.View(func(tx walletdb.ReadTx) error {
return cb(&nodeTraverserSession{
diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go
index b310897..fea367a 100644
--- a/graph/db/sql_store.go
+++ b/graph/db/sql_store.go
@@ -3316,10 +3316,8 @@ func (s *SQLStore) IsClosedScid(ctx context.Context,
// instance which can be used to perform queries against the channel graph.
//
// NOTE: part of the Store interface.
-func (s *SQLStore) GraphSession(cb func(graph NodeTraverser) error,
- reset func()) error {
-
- var ctx = context.TODO()
+func (s *SQLStore) GraphSession(ctx context.Context,
+ cb func(graph NodeTraverser) error, reset func()) error {
return s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
return cb(newSQLNodeTraverser(db, s.cfg.ChainHash))
diff --git a/routing/graph.go b/routing/graph.go
index 73ca334..b245d40 100644
--- a/routing/graph.go
+++ b/routing/graph.go
@@ -32,7 +32,8 @@ type GraphSessionFactory interface {
// GraphSession will provide the call-back with access to a
// graphdb.NodeTraverser instance which can be used to perform queries
// against the channel graph.
- GraphSession(cb func(graph graphdb.NodeTraverser) error,
+ GraphSession(ctx context.Context,
+ cb func(graph graphdb.NodeTraverser) error,
reset func()) error
}
diff --git a/routing/mock_graph_test.go b/routing/mock_graph_test.go
index 0f657bd..2105514 100644
--- a/routing/mock_graph_test.go
+++ b/routing/mock_graph_test.go
@@ -234,8 +234,8 @@ func (m *mockGraph) FetchNodeFeatures(_ context.Context,
// the channel graph.
//
// NOTE: Part of the GraphSessionFactory interface.
-func (m *mockGraph) GraphSession(cb func(graph graphdb.NodeTraverser) error,
- _ func()) error {
+func (m *mockGraph) GraphSession(_ context.Context,
+ cb func(graph graphdb.NodeTraverser) error, _ func()) error {
return cb(m)
}
diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go
index 3dc1ddf..85689ef 100644
--- a/routing/pathfind_test.go
+++ b/routing/pathfind_test.go
@@ -3326,7 +3326,7 @@ func dbFindPath(graph *graphdb.VersionedGraph,
}
var route []*unifiedEdge
- err = graph.GraphSession(func(graph graphdb.NodeTraverser) error {
+ err = graph.GraphSession(ctx, func(graph graphdb.NodeTraverser) error {
route, _, err = findPath(
&graphParams{
additionalEdges: additionalEdges,
diff --git a/routing/payment_session.go b/routing/payment_session.go
index bb79521..4cddfa2 100644
--- a/routing/payment_session.go
+++ b/routing/payment_session.go
@@ -1,6 +1,7 @@
package routing
import (
+ "context"
"fmt"
"github.com/btcsuite/btcd/btcec/v2"
@@ -344,6 +345,7 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
for {
err := p.graphSessFactory.GraphSession(
+ context.TODO(),
findPath, func() {
path = nil
},
diff --git a/routing/payment_session_test.go b/routing/payment_session_test.go
index 547fe0e..0bc0b6d 100644
--- a/routing/payment_session_test.go
+++ b/routing/payment_session_test.go
@@ -1,6 +1,7 @@
package routing
import (
+ "context"
"testing"
"time"
@@ -260,8 +261,8 @@ func (g *sessionGraph) sourceNode() route.Vertex {
return route.Vertex{}
}
-func (g *sessionGraph) GraphSession(cb func(graph graphdb.NodeTraverser) error,
- _ func()) error {
+func (g *sessionGraph) GraphSession(_ context.Context,
+ cb func(graph graphdb.NodeTraverser) error, _ func()) error {
return cb(g)
}
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.