Skip to content

Roll channel and node reminders across 6-hourly buckets - #107

Open
TheBlueMatt wants to merge 2 commits into
lightningdevkit:mainfrom
TheBlueMatt:main
Open

TheBlueMatt wants to merge 2 commits into
lightningdevkit:mainfrom
TheBlueMatt:main

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Contributor
Clients backdate everything we send them by a week and prune anything
they haven't heard about in two weeks, so a channel direction lives for
seven days past the header of the last snapshot that wrote it. Since we
never send value-identical re-broadcasts, an unchanging channel is only
written by a reminder. Reminders were previously included only in the
snapshot generated at 00:00 UTC every fifth day (or for scopes above 50
hours), i.e. in one three-hour window out of forty for any client
syncing at least every two days. Clients that missed that window, or
synced daily at a fixed hour outside it, lost every stable channel a
week after their last reminder, and channels can never be re-announced
to an incremental client afterwards. Even clients that caught every
window only kept a channel that had mutated once and then gone quiet if
a reminder happened to fall in the single day between the six-day
eligibility age and the seven-day client lifetime.

Instead, every channel and node is now assigned to one of 24 buckets
(a mixed hash of the SCID, or the node id's x coordinate), one bucket
becomes due every six hours, and a snapshot includes the reminders of
every bucket that became due within its (last_sync, reference] window.
Consecutive snapshots thus chain without gaps and any client that syncs
at least once every six days is reminded of every stable channel once
per six-day cycle, regardless of which snapshots it fetches. Clients
further behind receive all buckets at once, which subsumes the old
scope rule.

The channel-side six-day streak-age gate (and the window-function query
that computed it) is dropped: with a six-day rotation it recreated the
timing lottery for freshly mutated channels, and skipping recently
mutated channels saves few bytes since those mostly carry an
incremental update anyway. Node reminders keep their eligibility
semantics but only evaluate the 14-day announcement history for nodes
whose bucket is due.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Matt Corallo and others added 2 commits September 15, 2026 00:56
Clients backdate everything we send them by a week and prune anything
they haven't heard about in two weeks, so a channel direction lives for
seven days past the header of the last snapshot that wrote it. Since we
never send value-identical re-broadcasts, an unchanging channel is only
written by a reminder. Reminders were previously included only in the
snapshot generated at 00:00 UTC every fifth day (or for scopes above 50
hours), i.e. in one three-hour window out of forty for any client
syncing at least every two days. Clients that missed that window, or
synced daily at a fixed hour outside it, lost every stable channel a
week after their last reminder, and channels can never be re-announced
to an incremental client afterwards. Even clients that caught every
window only kept a channel that had mutated once and then gone quiet if
a reminder happened to fall in the single day between the six-day
eligibility age and the seven-day client lifetime.

Instead, every channel and node is now assigned to one of 24 buckets
(a mixed hash of the SCID, or the node id's x coordinate), one bucket
becomes due every six hours, and a snapshot includes the reminders of
every bucket that became due within its (last_sync, reference] window.
Consecutive snapshots thus chain without gaps and any client that syncs
at least once every six days is reminded of every stable channel once
per six-day cycle, regardless of which snapshots it fetches. Clients
further behind receive all buckets at once, which subsumes the old
scope rule.

The channel-side six-day streak-age gate (and the window-function query
that computed it) is dropped: with a six-day rotation it recreated the
timing lottery for freshly mutated channels, and skipping recently
mutated channels saves few bytes since those mostly carry an
incremental update anyway. Node reminders keep their eligibility
semantics but only evaluate the 14-day announcement history for nodes
whose bucket is due.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A channel_announcement is sent to an incremental client only if its
`seen` timestamp, or the moment the channel first had updates in both
directions, is newer than the client's last sync. Both are one-time
events, so a channel that leaves and later re-enters our snapshots is
never announced again.

That is exactly what happens when one peer of a channel goes offline
for a month: after two weeks its direction is pruned from our network
graph, which drops the channel altogether and rejects its updates, so
clients stop receiving reminders for it and prune it a week later. When
the peer comes back it re-broadcasts the announcement and both peers
update the channel again, and it re-enters our graph, but every client
that synced in the meantime only ever receives updates for a channel it
no longer has, and drops them.

Instead of the first update per direction, we now look, per direction,
at the first update seen after the client's last sync and check whether
it had a predecessor within the prune interval. If not, updates in that
direction (re)started after the last sync, either because the channel
is new (the previous behaviour) or because it had been pruned and has
come back, and the channel is announced alongside full updates in both
directions. Since we only ever drop a channel after a full prune
interval without updates and then block it for another week, every
resumption after a prune implies such a gap in the update history.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ldk-reviews-bot

ldk-reviews-bot commented Sep 15, 2026 •

Copy link
Copy Markdown

I've assigned @valentinewallace as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants