What changed, and why it matters
This commit is a small internal plumbing change: it adds a 'gossip version' parameter to the function that marks Lightning channels as 'zombies' (inactive/stale), so the database layer can handle different channel gossip formats consistently. It is not a security fix and does not appear to introduce a vulnerability. It simply extends an existing pattern already used for the 'mark live' function.
No security action required. Treat as normal code maintenance; review as part of routine release testing for gossip-version handling consistency.
Security signals we found
No security-relevant bug fix or vulnerability patch evident in the diff
Change is API/versioning consistency work, not a correction of unsafe behavior
No input validation weakening; SQLStore adds a known-version check
No privilege boundary, cryptographic, or network exposure changes
Evidence from the diff
The commit versions the MarkEdgeZombie API across the Store interface, ChannelGraph wrapper, KVStore, and SQLStore. KVStore rejects non-v1 versions with ErrVersionNotSupportedForKVDB, while SQLStore accepts any known gossip version and uses it in UpsertZombieChannel and cache invalidation. Builder.MarkZombieEdge hardcodes GossipVersion1 because that ad-hoc path only handles v1 channels. This follows the same versioning pattern already established for MarkEdgeLive.
Changed components
graph/db/interfaces.gograph/db/graph.gograph/db/kv_store.gograph/db/sql_store.gograph/builder.gograph/db/graph_test.goInspect captured patch +38 / −24
diff --git a/graph/builder.go b/graph/builder.go
index 2e17ef5..d63cab5 100644
--- a/graph/builder.go
+++ b/graph/builder.go
@@ -963,7 +963,7 @@ func (b *Builder) MarkZombieEdge(chanID uint64) error {
// node pubkeys so this edge can't be resurrected.
var zeroKey [33]byte
err := b.cfg.Graph.MarkEdgeZombie(
- context.TODO(), chanID, zeroKey, zeroKey,
+ context.TODO(), lnwire.GossipVersion1, chanID, zeroKey, zeroKey,
)
if err != nil {
return fmt.Errorf("unable to mark spent chan(id=%v) as a "+
diff --git a/graph/db/graph.go b/graph/db/graph.go
index a082d5b..f564d88 100644
--- a/graph/db/graph.go
+++ b/graph/db/graph.go
@@ -566,12 +566,13 @@ func (c *ChannelGraph) FilterKnownChanIDs(ctx context.Context,
}
// MarkEdgeZombie attempts to mark a channel identified by its channel ID as a
-// zombie. This method is used on an ad-hoc basis, when channels need to be
-// marked as zombies outside the normal pruning cycle.
-func (c *ChannelGraph) MarkEdgeZombie(ctx context.Context, chanID uint64,
+// zombie for the given gossip version. This method is used on an ad-hoc basis,
+// when channels need to be marked as zombies outside the normal pruning cycle.
+func (c *ChannelGraph) MarkEdgeZombie(ctx context.Context,
+ v lnwire.GossipVersion, chanID uint64,
pubKey1, pubKey2 [33]byte) error {
- err := c.db.MarkEdgeZombie(ctx, chanID, pubKey1, pubKey2)
+ err := c.db.MarkEdgeZombie(ctx, v, chanID, pubKey1, pubKey2)
if err != nil {
return err
}
diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go
index 90d6748..90a2fc5 100644
--- a/graph/db/graph_test.go
+++ b/graph/db/graph_test.go
@@ -2964,11 +2964,13 @@ func TestFilterKnownChanIDsZombieRevival(t *testing.T) {
// Mark channel 1 and 2 as zombies.
err := graph.MarkEdgeZombie(
- ctx, scid1.ToUint64(), [33]byte{}, [33]byte{},
+ ctx, lnwire.GossipVersion1, scid1.ToUint64(),
+ [33]byte{}, [33]byte{},
)
require.NoError(t, err)
err = graph.MarkEdgeZombie(
- ctx, scid2.ToUint64(), [33]byte{}, [33]byte{},
+ ctx, lnwire.GossipVersion1, scid2.ToUint64(),
+ [33]byte{}, [33]byte{},
)
require.NoError(t, err)
@@ -3323,7 +3325,8 @@ func TestStressTestChannelGraphAPI(t *testing.T) {
}
return graph.MarkEdgeZombie(
- ctx, channel.id.ToUint64(),
+ ctx, lnwire.GossipVersion1,
+ channel.id.ToUint64(),
node1.PubKeyBytes,
node2.PubKeyBytes,
)
@@ -4626,7 +4629,8 @@ func TestGraphZombieIndex(t *testing.T) {
// If we mark the edge as a zombie manually, then it should show up as
// being a zombie once again.
err = graph.MarkEdgeZombie(
- ctx, edge.ChannelID, node1.PubKeyBytes, node2.PubKeyBytes,
+ ctx, lnwire.GossipVersion1, edge.ChannelID,
+ node1.PubKeyBytes, node2.PubKeyBytes,
)
require.NoError(t, err, "unable to mark edge as zombie")
diff --git a/graph/db/interfaces.go b/graph/db/interfaces.go
index ae07bbe..e701e61 100644
--- a/graph/db/interfaces.go
+++ b/graph/db/interfaces.go
@@ -327,10 +327,11 @@ type Store interface { //nolint:interfacebloat
ChannelView(ctx context.Context) ([]EdgePoint, error)
// MarkEdgeZombie attempts to mark a channel identified by its channel
- // ID as a zombie. This method is used on an ad-hoc basis, when channels
- // need to be marked as zombies outside the normal pruning cycle.
- MarkEdgeZombie(ctx context.Context, chanID uint64,
- pubKey1, pubKey2 [33]byte) error
+ // ID as a zombie for the given gossip version. This method is used on
+ // an ad-hoc basis, when channels need to be marked as zombies outside
+ // the normal pruning cycle.
+ MarkEdgeZombie(ctx context.Context, v lnwire.GossipVersion,
+ chanID uint64, pubKey1, pubKey2 [33]byte) error
// MarkEdgeLive clears an edge from our zombie index for the given
// gossip version, deeming it as live.
diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go
index b39432d..cd8a928 100644
--- a/graph/db/kv_store.go
+++ b/graph/db/kv_store.go
@@ -4289,10 +4289,14 @@ func (c *KVStore) ChannelView(_ context.Context) ([]EdgePoint, error) {
}
// MarkEdgeZombie attempts to mark a channel identified by its channel ID as a
-// zombie. This method is used on an ad-hoc basis, when channels need to be
-// marked as zombies outside the normal pruning cycle.
-func (c *KVStore) MarkEdgeZombie(_ context.Context, chanID uint64,
- pubKey1, pubKey2 [33]byte) error {
+// zombie for the given gossip version. This method is used on an ad-hoc basis,
+// when channels need to be marked as zombies outside the normal pruning cycle.
+func (c *KVStore) MarkEdgeZombie(_ context.Context, v lnwire.GossipVersion,
+ chanID uint64, pubKey1, pubKey2 [33]byte) error {
+
+ if v != lnwire.GossipVersion1 {
+ return ErrVersionNotSupportedForKVDB
+ }
c.cacheMu.Lock()
defer c.cacheMu.Unlock()
diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go
index c3ac93a..c9e7384 100644
--- a/graph/db/sql_store.go
+++ b/graph/db/sql_store.go
@@ -1779,12 +1779,16 @@ func (s *SQLStore) FilterChannelRange(ctx context.Context, startHeight,
}
// MarkEdgeZombie attempts to mark a channel identified by its channel ID as a
-// zombie. This method is used on an ad-hoc basis, when channels need to be
-// marked as zombies outside the normal pruning cycle.
+// zombie for the given gossip version. This method is used on an ad-hoc basis,
+// when channels need to be marked as zombies outside the normal pruning cycle.
//
// NOTE: part of the Store interface.
-func (s *SQLStore) MarkEdgeZombie(ctx context.Context, chanID uint64,
- pubKey1, pubKey2 [33]byte) error {
+func (s *SQLStore) MarkEdgeZombie(ctx context.Context, v lnwire.GossipVersion,
+ chanID uint64, pubKey1, pubKey2 [33]byte) error {
+
+ if !isKnownGossipVersion(v) {
+ return fmt.Errorf("unsupported gossip version: %d", v)
+ }
s.cacheMu.Lock()
defer s.cacheMu.Unlock()
@@ -1794,7 +1798,7 @@ func (s *SQLStore) MarkEdgeZombie(ctx context.Context, chanID uint64,
err := s.db.ExecTx(ctx, sqldb.WriteTxOpt(), func(db SQLQueries) error {
return db.UpsertZombieChannel(
ctx, sqlc.UpsertZombieChannelParams{
- Version: int16(lnwire.GossipVersion1),
+ Version: int16(v),
Scid: chanIDB,
NodeKey1: pubKey1[:],
NodeKey2: pubKey2[:],
@@ -1806,8 +1810,8 @@ func (s *SQLStore) MarkEdgeZombie(ctx context.Context, chanID uint64,
"(channel_id=%d): %w", chanID, err)
}
- s.rejectCache.remove(lnwire.GossipVersion1, chanID)
- s.chanCache.remove(lnwire.GossipVersion1, chanID)
+ s.rejectCache.remove(v, chanID)
+ s.chanCache.remove(v, chanID)
return nil
}
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.