Skip to content

staticaddr/deposit: retry deferred expiry notifications - #1297

Draft
starius wants to merge 3 commits into
lightninglabs:masterfrom
starius:deposit-expiry-replay
Draft

starius wants to merge 3 commits into
lightninglabs:masterfrom
starius:deposit-expiry-replay

Conversation

@starius

@starius starius commented Nov 14, 2026

Copy link
Copy Markdown
Collaborator

Since #1219, the deposit manager doesn't deliver a block height to the deposit FSMs when reconciliation fails or lnd's wallet tip is changing or unsynced, so deposits don't make expiry decisions from stale confirmation data. The skipped height was only delivered with the next block. The periodic deposit poll reconciles but never notifies the deposits. So an expiry sweep was delayed by a block interval, or forever if no block followed. This was raised as a non-blocking review comment on #1219.

A test failed because of that: when the wallet tip is still moving for the last blocks the test mines, the second set of deposits never expires and the test times out with "deposit expiries were not swept".

This PR retries the reconciliation and notification of the latest block height every second (ExpiryRetryInterval) until lnd provides a stable wallet view. The retry runs in the manager's event loop, so notifications stay serialized, and it stops once a height is delivered. A newer block supersedes the pending height and rearms the retry if reconciliation still fails. Failed retries are logged at debug level so a persistent wallet failure doesn't flood the log.

TestManagerRetriesDeferredExpiryNotification covers an unsynced wallet tip at startup, and an unsynced tip or a failing wallet query at a later block after a healthy startup. In each case nothing is signed while lnd is unhealthy, and the expiry sweep is signed and published once lnd recovers, without another block. The test fails without the fix. The existing tests that check no expiry happens while lnd is catching up or the wallet query fails still pass, because retries never act until the wallet view is stable.

Leaving this in draft state for now, since it may conflict with more fundamental deposits rework.

Pull Request Checklist

  • Add an entry to docs/release-notes/release-notes-next.md, or apply the
    no-changelog label (required by CI)

A block height that the deposit manager could not deliver to the
deposit FSMs, because lnd's wallet tip was changing or unsynced or the
wallet query failed, is currently dropped until the next block. Add the
interval in which such a height will be delivered again, configurable
per manager so tests can shorten it. It is not used yet.
A deposit whose expiry block arrives while lnd's wallet tip is changing
or unsynced, or while the wallet query fails, must expire once lnd
recovers, without waiting for another block. If no further block
arrives, the expiry sweep is never published. The static address
deposit expiry integration test hits this when the wallet tip is still
moving for the last blocks it mines.

The test fails until deferred notifications are retried.
The deposit manager skips delivering a block height to the deposit FSMs
when reconciliation fails or lnd's wallet tip is changing or unsynced,
so that deposits don't make expiry decisions from stale confirmation
data. The skipped height was only delivered with the next block, which
delays an expiry sweep by a block interval, or forever if no block
follows. The periodic deposit poll reconciles, but never notifies.

Retry the reconciliation and notification of the latest block height
every ExpiryRetryInterval until lnd provides a stable wallet view. The
retry runs in the manager's event loop, so notifications stay
serialized. Failed retries are logged at debug level to avoid flooding
the log while lnd is unavailable.
@starius
starius requested a review from hieblmi November 14, 2026 18:52
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.

1 participant