gossipd: reset dying_channels array after compact.
What changed, and why it matters
This patch fixes a bug in Core Lightning's gossip daemon where, after compacting the network graph store, the list of 'dying' channels was not reset and the code that repopulates it was not hooked up. This could cause the node to lose track of channels that are being closed, potentially leading to incorrect routing decisions or stale channel state. The fix clears the old list and provides a callback so dying channels are reloaded from the newly compacted store.
Apply the patch. Monitor for any gossip-related routing anomalies or stale channel announcements after compaction on nodes that have not yet been patched.
Security signals we found
State desynchronization after store compaction
Missing callback registration causing incomplete metadata reload
Potential use of stale channel liveness data
Evidence from the diff
In gossipd/gossmap_manage.c, compactd_done() is called after the gossip store has been compacted. Previously, gm->dying_channels was not freed/reset, and gossmap_load_initial() was passed NULL as the add_dying callback. After compaction, the gossmap is reloaded from the compacted file, but the dying_channels array would retain stale entries and new dying channels would not be recorded. The patch frees and resets gm->dying_channels and passes gossmap_add_dying_chan as the callback to gossmap_load_initial so dying channels are repopulated during reload.
Changed components
gossipd/gossmap_manage.cgossip store compaction pathdying_channels trackingInspect captured patch +5 / −1
diff --git a/gossipd/gossmap_manage.c b/gossipd/gossmap_manage.c
index 61ce44d8..ed11baff 100644
--- a/gossipd/gossmap_manage.c
+++ b/gossipd/gossmap_manage.c
@@ -1613,13 +1613,17 @@ static void compactd_done(struct io_conn *unused, struct gossmap_manage *gm)
status_debug("compaction done: %"PRIu64" -> %"PRIu64" bytes",
gm->compactd->old_size, (u64)st.st_size);
+ /* We will reload dying_channels as we reopen */
+ tal_free(gm->dying_channels);
+ gm->dying_channels = tal_arr(gm, struct chan_dying, 0);
+
/* Switch gossmap to new one, as a sanity check (rather than
* writing end marker and letting it reopen) */
tal_free(gm->raw_gossmap);
gm->raw_gossmap = gossmap_load_initial(gm, GOSSIP_STORE_COMPACT_FILENAME,
st.st_size,
gossmap_logcb,
- NULL,
+ gossmap_add_dying_chan,
gm);
if (!gm->raw_gossmap)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
Why this scored 55/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.