AI-generated analysisPublished automatically and not human-verified. Validated context appears in community notes below.
← Watch feed
Moderate 57 Bitcoin

Stop re-hydrating pending payments once they are fully resolved

Public commit record

What the developer wrote

Authored by Matt Corallo

85/100 · Strong
Stop re-hydrating pending payments once they are fully resolved

`MonitorEvent`s aren't delivered to the `ChannelManager` in a
durable fasion - if the `ChannelManager` fetches the pending
`MonitorEvent`s, then the `ChannelMonitor` gets persisted (i.e. due
to a block update) then the node crashes, prior to persisting the
`ChannelManager` again, the `MonitorEvent` and its effects on the
`ChannelManger` will be lost. This isn't likely in a sync persist
environment, but in an async one this could be an issue.

Note that this is only an issue for closed channels -
`MonitorEvent`s only inform the `ChannelManager` that a channel is
closed (which the `ChannelManager` will learn on startup or when it
next tries to advance the channel state), that
`ChannelMonitorUpdate` writes completed (which the `ChannelManager`
will detect on startup), or that HTLCs resolved on-chain post
closure. Of the three, only the last is problematic to lose prior
to a reload.

In previous commits we ensured that HTLC resolutions which came to
`ChannelManager` via a `MonitorEvent` were replayed on startup if
the `MonitorEvent` was lost. However, in cases where the
`ChannelManager` was so stale that it didn't have the payment state
for an HTLC at all, we only re-add it in cases where
`ChannelMonitor::get_pending_or_resolved_outbound_htlcs` includes
it.

Because constantly re-adding a payment state and then failing it
would generate lots of noise for users on startup (not to mention
risk of confusing stale payment events for the latest state of a
payment when the `PaymentId` has been reused to retry a payment).
Thus, `get_pending_or_resolved_outbound_htlcs` does not include
state for HTLCs which were resolved on chain with a preimage or
HTLCs which were resolved on chain with a timeout after
`ANTI_REORG_DELAY` confirmations.

This critera matches the critera for generating a `MonitorEvent`,
and works great under the assumption that `MonitorEvent`s are
reliably delivered. However, if they are not, and our
`ChannelManager` is lost or substantially old (or, in a future
where we do not persist `ChannelManager` at all), we will not end
up seeing payment resolution events for an HTLC.

Instead, we really want to tell our `ChannelMonitor`s when the
resolution of an HTLC is complete. Note that we don't particularly
care about non-payment HTLCs, as there is no re-hydration of state
to do there - `ChannelManager` load ignores forwarded HTLCs coming
back from `get_pending_or_resolved_outbound_htlcs` as there's
nothing to do - we always attempt to replay the success/failure and
figure out if it mattered based on whether there was still an HTLC
to claim/fail.

Here we, finally, begin actually using the new
`ChannelMonitorUpdateStep::ReleasePaymentComplete` updates,
skipping re-hydration of pending payments once they have been fully
resolved through to a user `Event`.
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
The short version

What changed, and why it matters

This commit fixes a reliability issue in the Lightning Dev Kit's handling of payment events after a channel closes. In rare crash scenarios, the wallet could lose track of whether an on-chain payment had already been reported to the user, causing it to either replay old payment notifications or fail to report a resolution. The fix marks HTLCs as fully resolved in the ChannelMonitor so they are not re-processed on restart, reducing duplicate or missing payment events.

Recommended action

Review async persistence ordering in deployments to ensure ChannelManager is persisted after MonitorEvents are processed, and verify that ChannelMonitorUpdateStep::ReleasePaymentComplete updates are durably written. Backport if running versions prior to this fix in production nodes with async persistence.

Security signals we found

01

Loss of MonitorEvent delivery in async persistence environments

02

Potential duplicate or missing PaymentSent/PaymentFailed events on restart

03

Stale ChannelManager state causing payment re-hydration

04

Use of ChannelMonitorUpdateStep::ReleasePaymentComplete to prevent reprocessing

05

Removal of get_pending_or_resolved_outbound_htlcs re-hydration path

Risk score

Why this scored 57/100

Our methodology →
Potential impact 18/30
Exploitability 8/25
Stealth signal 10/15
Affected reach 10/15
Confidence 7/10
Evidence quality 4/5
Human-validated context

Community notes

Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.

No validated notes yet.

The AI analysis stands alone for now. Submit a note if you can add evidence or important context.