What changed, and why it matters
This commit changes how the Lightning Network Daemon (LND) looks up a compact channel identifier from a funding transaction outpoint. It adds a 'gossip version' parameter to the lookup so that the database can distinguish between different protocol versions when resolving channel IDs. The change is a structural/API update rather than a fix for an active security flaw. It does not, on its own, prevent or enable a known attack, but it is part of making the graph database version-aware, which can help avoid mismatches between how channels are stored and queried.
Treat this as a normal refactoring/API-change commit. Reviewers should verify that all callers of ChannelID have been updated to supply a correct GossipVersion and that the SQL query index/plan for GetSCIDByOutpoint remains efficient with the now-variable version parameter. No immediate security patch or incident response is indicated by the commit content.
Security signals we found
API signature change to include protocol version in channel ID lookup
KV backend explicitly rejects unsupported gossip versions
SQL backend stops hardcoding GossipVersion1 and uses caller-supplied version
No direct input validation, bounds checking, or cryptographic change present
No mention of vulnerability, CVE, bug bounty, or security fix in commit message
Evidence from the diff
The commit modifies the Store interface and both KV and SQL implementations of ChannelID to accept a lnwire.GossipVersion parameter. The KV implementation now returns ErrVersionNotSupportedForKVDB for any version other than GossipVersion1. The SQL implementation passes the supplied version into the GetSCIDByOutpoint query instead of hardcoding GossipVersion1. The VersionedGraph wrapper is updated to forward its stored version. A test is updated to pass GossipVersion1. This is a versioning refactor that makes the outpoint-to-short-channel-ID lookup consistent with other versioned graph methods.
Changed components
graph/db/graph.gograph/db/interfaces.gograph/db/kv_store.gograph/db/sql_store.gograph/db/graph_test.goInspect captured patch +26 / −9
diff --git a/graph/db/graph.go b/graph/db/graph.go
index 91286b7..3e6b4e7 100644
--- a/graph/db/graph.go
+++ b/graph/db/graph.go
@@ -177,8 +177,9 @@ func (c *ChannelGraph) populateCache(ctx context.Context) error {
return nil
}, func() {},
)
- if err != nil &&
- !errors.Is(err, ErrVersionNotSupportedForKVDB) {
+ if err != nil && !errors.Is(
+ err, ErrVersionNotSupportedForKVDB,
+ ) {
return err
}
@@ -685,8 +686,10 @@ func (c *ChannelGraph) AddEdgeProof(chanID lnwire.ShortChannelID,
}
// ChannelID attempts to lookup the 8-byte compact channel ID.
-func (c *ChannelGraph) ChannelID(chanPoint *wire.OutPoint) (uint64, error) {
- return c.db.ChannelID(chanPoint)
+func (c *ChannelGraph) ChannelID(v lnwire.GossipVersion,
+ chanPoint *wire.OutPoint) (uint64, error) {
+
+ return c.db.ChannelID(v, chanPoint)
}
// HighestChanID returns the "highest" known channel ID in the channel graph.
@@ -947,6 +950,11 @@ func (c *VersionedGraph) ForEachChannelCacheable(
return c.db.ForEachChannelCacheable(c.v, cb, reset)
}
+// ChannelID attempts to lookup the 8-byte compact channel ID.
+func (c *VersionedGraph) ChannelID(chanPoint *wire.OutPoint) (uint64, error) {
+ return c.db.ChannelID(c.v, chanPoint)
+}
+
// IsPublicNode determines whether the node is seen as public in the graph.
func (c *VersionedGraph) IsPublicNode(pubKey [33]byte) (bool, error) {
return c.db.IsPublicNode(c.v, pubKey)
diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go
index f7776af..dbdfb13 100644
--- a/graph/db/graph_test.go
+++ b/graph/db/graph_test.go
@@ -1238,7 +1238,7 @@ func TestEdgeInfoUpdates(t *testing.T) {
// We should also be able to retrieve the channelID only knowing the
// channel point of the channel.
- dbChanID, err := graph.ChannelID(&outpoint)
+ dbChanID, err := graph.ChannelID(lnwire.GossipVersion1, &outpoint)
require.NoError(t, err, "unable to retrieve channel ID")
if dbChanID != chanID {
t.Fatalf("chan ID's mismatch, expected %v got %v", dbChanID,
diff --git a/graph/db/interfaces.go b/graph/db/interfaces.go
index 5a6d27d..95d8bb3 100644
--- a/graph/db/interfaces.go
+++ b/graph/db/interfaces.go
@@ -239,7 +239,8 @@ type Store interface { //nolint:interfacebloat
// ChannelID attempt to lookup the 8-byte compact channel ID which maps
// to the passed channel point (outpoint). If the passed channel doesn't
// exist within the database, then ErrEdgeNotFound is returned.
- ChannelID(chanPoint *wire.OutPoint) (uint64, error)
+ ChannelID(v lnwire.GossipVersion,
+ chanPoint *wire.OutPoint) (uint64, error)
// HighestChanID returns the "highest" known channel ID in the channel
// graph. This represents the "newest" channel from the PoV of the
diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go
index 3a143ee..bdb1a78 100644
--- a/graph/db/kv_store.go
+++ b/graph/db/kv_store.go
@@ -1998,7 +1998,13 @@ func (c *KVStore) DeleteChannelEdges(v lnwire.GossipVersion,
// ChannelID attempt to lookup the 8-byte compact channel ID which maps to the
// passed channel point (outpoint). If the passed channel doesn't exist within
// the database, then ErrEdgeNotFound is returned.
-func (c *KVStore) ChannelID(chanPoint *wire.OutPoint) (uint64, error) {
+func (c *KVStore) ChannelID(v lnwire.GossipVersion,
+ chanPoint *wire.OutPoint) (uint64, error) {
+
+ if v != lnwire.GossipVersion1 {
+ return 0, ErrVersionNotSupportedForKVDB
+ }
+
var chanID uint64
if err := kvdb.View(c.db, func(tx kvdb.RTx) error {
var err error
diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go
index 75f06f6..e2b8477 100644
--- a/graph/db/sql_store.go
+++ b/graph/db/sql_store.go
@@ -2507,7 +2507,9 @@ func (s *SQLStore) HasChannelEdge(v lnwire.GossipVersion,
// the database, then ErrEdgeNotFound is returned.
//
// NOTE: part of the Store interface.
-func (s *SQLStore) ChannelID(chanPoint *wire.OutPoint) (uint64, error) {
+func (s *SQLStore) ChannelID(v lnwire.GossipVersion,
+ chanPoint *wire.OutPoint) (uint64, error) {
+
var (
ctx = context.TODO()
channelID uint64
@@ -2516,7 +2518,7 @@ func (s *SQLStore) ChannelID(chanPoint *wire.OutPoint) (uint64, error) {
chanID, err := db.GetSCIDByOutpoint(
ctx, sqlc.GetSCIDByOutpointParams{
Outpoint: chanPoint.String(),
- Version: int16(lnwire.GossipVersion1),
+ Version: int16(v),
},
)
if errors.Is(err, sql.ErrNoRows) {
Why this scored 19/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.