graph/db: add version parameter to FetchChannelEdgesByID/Outpoint
What changed, and why it matters
This commit is a routine internal refactoring to prepare the LND channel graph database for future support of multiple gossip protocol versions. It adds a version parameter to two edge-lookup functions and makes the SQL store use that parameter instead of a hardcoded version. There is no security bug being fixed here and no behavior that would let an attacker do anything harmful.
No security action required. Treat as normal feature/refactoring work. If reviewing the broader multi-gossip-version feature, verify that V2 policy construction is completed before the feature is enabled in production.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change threads a lnwire.GossipVersion argument through FetchChannelEdgesByID and FetchChannelEdgesByOutpoint in the graph/db Store interface and both KV and SQL implementations. The legacy ChannelGraph wrapper hardcodes GossipVersion1, preserving existing behavior. VersionedGraph exposes the new methods using its configured version. The KV store rejects non-V1 versions with ErrVersionNotSupportedForKVDB; the SQL store validates the version and queries with it. A TODO comment notes that V2 policy building is not yet implemented and currently returns an error if encountered. No vulnerability is patched.
Changed components
graph/db/graph.gograph/db/interfaces.gograph/db/kv_store.gograph/db/sql_store.goInspect captured patch +73 / −15
diff --git a/graph/db/graph.go b/graph/db/graph.go
index 6c4b0a1..0f4dda6 100644
--- a/graph/db/graph.go
+++ b/graph/db/graph.go
@@ -711,7 +711,9 @@ func (c *ChannelGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error) {
- return c.db.FetchChannelEdgesByOutpoint(op)
+ return c.db.FetchChannelEdgesByOutpoint(
+ lnwire.GossipVersion1, op,
+ )
}
// FetchChannelEdgesByID attempts to lookup directed edges by channel ID.
@@ -719,7 +721,9 @@ func (c *ChannelGraph) FetchChannelEdgesByID(chanID uint64) (
*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error) {
- return c.db.FetchChannelEdgesByID(chanID)
+ return c.db.FetchChannelEdgesByID(
+ lnwire.GossipVersion1, chanID,
+ )
}
// ChannelView returns the verifiable edge information for each active channel.
@@ -785,6 +789,23 @@ func (c *VersionedGraph) FetchNode(ctx context.Context,
return c.db.FetchNode(ctx, c.v, nodePub)
}
+// FetchChannelEdgesByID attempts to lookup directed edges by channel ID.
+func (c *VersionedGraph) FetchChannelEdgesByID(chanID uint64) (
+ *models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
+ *models.ChannelEdgePolicy, error) {
+
+ return c.db.FetchChannelEdgesByID(c.v, chanID)
+}
+
+// FetchChannelEdgesByOutpoint attempts to lookup directed edges by funding
+// outpoint.
+func (c *VersionedGraph) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
+ *models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
+ *models.ChannelEdgePolicy, error) {
+
+ return c.db.FetchChannelEdgesByOutpoint(c.v, op)
+}
+
// 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) {
diff --git a/graph/db/interfaces.go b/graph/db/interfaces.go
index 5658fa5..c684813 100644
--- a/graph/db/interfaces.go
+++ b/graph/db/interfaces.go
@@ -276,7 +276,7 @@ type Store interface { //nolint:interfacebloat
// houses the general information for the channel itself is returned as
// well as two structs that contain the routing policies for the channel
// in either direction.
- FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
+ FetchChannelEdgesByOutpoint(v lnwire.GossipVersion, op *wire.OutPoint) (
*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error)
@@ -291,7 +291,7 @@ type Store interface { //nolint:interfacebloat
// zombie within the database. In this case, the ChannelEdgePolicy's
// will be nil, and the ChannelEdgeInfo will only include the public
// keys of each node.
- FetchChannelEdgesByID(chanID uint64) (
+ FetchChannelEdgesByID(v lnwire.GossipVersion, chanID uint64) (
*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error)
diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go
index b3442bd..0887ff0 100644
--- a/graph/db/kv_store.go
+++ b/graph/db/kv_store.go
@@ -3811,8 +3811,8 @@ func computeEdgePolicyKeys(info *models.ChannelEdgeInfo) ([]byte, []byte) {
// found, then ErrEdgeNotFound is returned. A struct which houses the general
// information for the channel itself is returned as well as two structs that
// contain the routing policies for the channel in either direction.
-func (c *KVStore) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
- *models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
+func (c *KVStore) FetchChannelEdgesByOutpoint(v lnwire.GossipVersion,
+ op *wire.OutPoint) (*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error) {
var (
@@ -3821,6 +3821,10 @@ func (c *KVStore) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
policy2 *models.ChannelEdgePolicy
)
+ if v != lnwire.GossipVersion1 {
+ return nil, nil, nil, ErrVersionNotSupportedForKVDB
+ }
+
err := kvdb.View(c.db, func(tx kvdb.RTx) error {
// First, grab the node bucket. This will be used to populate
// the Node pointers in each edge read from disk.
@@ -3897,10 +3901,14 @@ func (c *KVStore) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
// ErrZombieEdge an be returned if the edge is currently marked as a zombie
// within the database. In this case, the ChannelEdgePolicy's will be nil, and
// the ChannelEdgeInfo will only include the public keys of each node.
-func (c *KVStore) FetchChannelEdgesByID(chanID uint64) (
- *models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
+func (c *KVStore) FetchChannelEdgesByID(v lnwire.GossipVersion,
+ chanID uint64) (*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error) {
+ if v != lnwire.GossipVersion1 {
+ return nil, nil, nil, ErrVersionNotSupportedForKVDB
+ }
+
var (
edgeInfo *models.ChannelEdgeInfo
policy1 *models.ChannelEdgePolicy
diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go
index 2f0b1c5..7cebede 100644
--- a/graph/db/sql_store.go
+++ b/graph/db/sql_store.go
@@ -2008,8 +2008,8 @@ func (s *SQLStore) DeleteChannelEdges(v lnwire.GossipVersion,
// the ChannelEdgeInfo will only include the public keys of each node.
//
// NOTE: part of the Store interface.
-func (s *SQLStore) FetchChannelEdgesByID(chanID uint64) (
- *models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
+func (s *SQLStore) FetchChannelEdgesByID(v lnwire.GossipVersion,
+ chanID uint64) (*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error) {
var (
@@ -2018,11 +2018,18 @@ func (s *SQLStore) FetchChannelEdgesByID(chanID uint64) (
policy1, policy2 *models.ChannelEdgePolicy
chanIDB = channelIDToBytes(chanID)
)
+
+ if !isKnownGossipVersion(v) {
+ return nil, nil, nil, fmt.Errorf(
+ "unsupported gossip version: %d", v,
+ )
+ }
+
err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
row, err := db.GetChannelBySCIDWithPolicies(
ctx, sqlc.GetChannelBySCIDWithPoliciesParams{
Scid: chanIDB,
- Version: int16(lnwire.GossipVersion1),
+ Version: int16(v),
},
)
if errors.Is(err, sql.ErrNoRows) {
@@ -2031,7 +2038,7 @@ func (s *SQLStore) FetchChannelEdgesByID(chanID uint64) (
zombie, err := db.GetZombieChannel(
ctx, sqlc.GetZombieChannelParams{
Scid: chanIDB,
- Version: int16(lnwire.GossipVersion1),
+ Version: int16(v),
},
)
if errors.Is(err, sql.ErrNoRows) {
@@ -2118,8 +2125,8 @@ func (s *SQLStore) FetchChannelEdgesByID(chanID uint64) (
// contain the routing policies for the channel in either direction.
//
// NOTE: part of the Store interface.
-func (s *SQLStore) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
- *models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
+func (s *SQLStore) FetchChannelEdgesByOutpoint(v lnwire.GossipVersion,
+ op *wire.OutPoint) (*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
*models.ChannelEdgePolicy, error) {
var (
@@ -2127,11 +2134,18 @@ func (s *SQLStore) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
edge *models.ChannelEdgeInfo
policy1, policy2 *models.ChannelEdgePolicy
)
+
+ if !isKnownGossipVersion(v) {
+ return nil, nil, nil, fmt.Errorf(
+ "unsupported gossip version: %d", v,
+ )
+ }
+
err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
row, err := db.GetChannelByOutpointWithPolicies(
ctx, sqlc.GetChannelByOutpointWithPoliciesParams{
Outpoint: op.String(),
- Version: int16(lnwire.GossipVersion1),
+ Version: int16(v),
},
)
if errors.Is(err, sql.ErrNoRows) {
@@ -4662,6 +4676,21 @@ func getAndBuildChanPolicies(ctx context.Context, cfg *sqldb.QueryConfig,
return nil, nil, nil
}
+ // TODO(elle): update to support v2 policies.
+ if dbPol1 != nil &&
+ lnwire.GossipVersion(dbPol1.Version) != lnwire.GossipVersion1 {
+
+ return nil, nil, fmt.Errorf("unsupported policy1 version: %d",
+ dbPol1.Version)
+ }
+
+ if dbPol2 != nil &&
+ lnwire.GossipVersion(dbPol2.Version) != lnwire.GossipVersion1 {
+
+ return nil, nil, fmt.Errorf("unsupported policy2 version: %d",
+ dbPol2.Version)
+ }
+
var policyIDs = make([]int64, 0, 2)
if dbPol1 != nil {
policyIDs = append(policyIDs, dbPol1.ID)
Why this scored 15/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.