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

Fail held HTLC failures when force-closing

Public commit record

What the developer wrote

Authored by elnosh

68/100 · Adequate
Fail held HTLC failures when force-closing

When our counterparty fails an HTLC, the failure is held until the
ChannelMonitorUpdate for their revoke_and_ack completes. If the channel
is force-closed while that update is in-flight, the held failure was
dropped with the Channel. As the ChannelMonitor had already applied the
revocation, the HTLC was in no commitment transaction it tracks either,
so it was never failed, eventually causing a force-close.

Instead, include the held failures in the ChannelForceClosed update and
have the ChannelMonitor fail them via a MonitorEvent::HTLCEvent when
applying it. HTLC monitor events are only released once all updates
have been persisted, so the failure is only acted on once the
revocation is durable.

HTLCs which are still in a commitment transaction the ChannelMonitor
tracks are skipped. This is the case if the update for the revocation
was blocked rather than in-flight, and thus dropped on close, in which
case the counterparty can still claim the HTLC on-chain. Such HTLCs are
resolved like any other HTLC the ChannelMonitor tracks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
The short version

What changed, and why it matters

This commit fixes a bug in the Lightning Dev Kit where a forwarded payment failure could get permanently lost if a channel was force-closed at exactly the wrong moment. Previously, when the other side of a channel told us an HTLC (a conditional payment) had failed, that failure was temporarily held until a channel-state update finished. If the channel was force-closed while that update was still in flight, the held failure was discarded. Because the payment was also no longer in any on-chain commitment transaction the node watches, it would never be failed backwards or forwards, eventually causing another force-close. The fix hands those held failures to the ChannelMonitor as part of the force-close update, so they are properly failed once the relevant state updates are durably persisted.

Recommended action

Reviewers should verify that the new counterparty_failed_htlcs serialization is backward-compatible (optional_vec with default empty), that fail_counterparty_failed_htlcs correctly identifies HTLCs still in tracked commitments, and that no other pending HTLC state (forwards, finalized fulfills) has a similar force-close loss issue. Operators should upgrade to include this fix to avoid stuck forwarded payments and unnecessary force-closes.

Security signals we found

01

Fixes a state-loss race that could leave forwarded HTLCs unresolved

02

Prevents a secondary force-close caused by an un-failed HTLC

03

Adds ChannelMonitorUpdateStep::ChannelForceClosed field counterparty_failed_htlcs

04

Introduces ChannelMonitor::fail_counterparty_failed_htlcs to emit HTLC failure events from the monitor

05

Skips failing HTLCs still present in tracked counterparty commitment transactions to avoid premature failure when the counterparty could still claim on-chain

06

Uses existing pending_monitor_events mechanism so failures are released only after persistence

07

Adds regression tests for holder force-close, counterparty error, commitment-confirmed close, restart, stale ChannelManager, and blocked RAA update

Risk score

Why this scored 68/100

Our methodology →
Potential impact 22/30
Exploitability 12/25
Stealth signal 10/15
Affected reach 12/15
Confidence 8/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.