Skip to content

[bug]: Zombie pruning skips channels that never emitted a channel update #10223

@ziggie1984

Description

@ziggie1984

Summary

pruneZombieChans only considers channels returned by ChanUpdatesInHorizon. Both backends implement ChanUpdatesInHorizon to return channels that have at least one policy with a last_update
within the time range. Channels that never emitted any channel update are never returned and therefore never pruned by the zombie pass, even though IsZombieChannel would deem them stale
(zero timestamps).

Details

  • In graph/builder.go, pruneZombieChans builds candidates via:
    • oldEdges := Graph.ChanUpdatesInHorizon(start=Unix(0), end=now-ChannelPruneExpiry).
    • Only those are examined and possibly pruned; never-updated channels aren’t included.
  • KV (V1) backend (graph/db/kv_store.go):
    • ChanUpdatesInHorizon iterates edgeUpdateIndexBucket keyed by [last_update_ts][chan_id]; edges without any update have no index entry.
  • SQL backend (graph/db/sql_store.go + sqldb/sqlc/queries/graph.sql):
    • GetChannelsByPolicyLastUpdateRange filters rows where cp1.last_update OR cp2.last_update is within range; channels with both NULL are excluded.
  • Exception: with AssumeChannelValid, double-disabled channels are pruned — but this still requires policies to exist to know “disabled”.

Impact

  • Large numbers of never-updated channels persist indefinitely, increasing graph size and degrading performance.

Reproduction

  • Add a channel with no policies (no channel_update).
  • Advance time beyond ChannelPruneExpiry.
  • Trigger pruneZombieChans.
  • Expected: channel pruned (both edges stale by timestamp semantics).
  • Actual: channel not considered because ChanUpdatesInHorizon doesn’t return it.

Proposed Fix

  • Add a new DB method (preferred) used by pruneZombieChans, e.g. ChanCandidatesForPrune(start, end) that returns:
    • Channels where max(policy1.last_update, policy2.last_update) < end, OR
    • Both policies missing AND channel creation/announcement time < end.
  • SQL: extend WHERE to include never-updated channels using a channel-level timestamp.
  • KV: add a “channel last-activity/created-at” time index and range scan it; avoid full graph scans per tick.

Acceptance

  • Channels with no updates older than ChannelPruneExpiry are pruned across both backends.
  • Add unit tests to cover never-updated channels and ensure current semantics remain for updated ones.

Labels
bug, graph, pruning, db, performance, sql, kv

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions