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

Preserve our funding contribution across counterparty RBF attempts

Public commit record

What the developer wrote

Authored by Jeffrey Czyz

100/100 · Strong
Preserve our funding contribution across counterparty RBF attempts

When the counterparty initiates an RBF and we have no new contribution
queued via QuiescentAction, we must re-use our prior contribution so
that our splice is not lost. Track contributions in a new field on
PendingFunding so the last entry can be re-used in this scenario.

Each entry stores the feerate-adjusted version because that reflects
what was actually negotiated and allows correct feerate re-adjustment
on subsequent RBFs. Only explicitly provided contributions (from a
QuiescentAction) append to the vec. Re-used contributions are replaced
in-place with the version adjusted for the new feerate so they remain
accurate for further RBF rounds, without growing the vec.

Add test_splice_rbf_acceptor_recontributes to verify that when the
counterparty initiates an RBF and we have no new QuiescentAction
queued, our prior contribution is automatically re-used so the splice
is preserved.

Add test_splice_rbf_recontributes_feerate_too_high to verify that when
the counterparty RBFs at a feerate too high for our prior contribution
to cover, the RBF is rejected rather than proceeding without our
contribution.

Add test for sequential RBF splice attempts

Add test_splice_rbf_sequential that exercises three consecutive RBF
rounds on the same splice (initial → RBF #1 → RBF #2) to verify:
- Each round requires the 25/24 feerate increase (253 → 264 → 275)
- DiscardFunding events reference the correct funding txid from each
replaced candidate
- The final RBF splice can be mined and splice_locked successfully

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification✓ Links an issue, advisory, or supporting reference
The short version

What changed, and why it matters

This commit fixes a bug in Lightning Dev Kit's splicing/RBF logic. When one party tried to speed up or replace a splice transaction (an RBF), and the other party had not queued a new contribution, the other party's original funds could be silently dropped from the new transaction. The fix remembers each side's last contribution and re-uses it automatically, or rejects the RBF if the new fee rate makes the old contribution impossible. Without the fix, a counterparty could potentially strip the victim's funds out of a splice, causing loss of funds or channel disruption.

Recommended action

Reviewers should verify that the `contributions` vector is correctly bounded/replaced to avoid unbounded growth, that the feerate adjustment math cannot be manipulated to force rejection or acceptance, and that serialization backward compatibility is handled. Users running nodes with splicing enabled should upgrade once the fix is released.

Security signals we found

01

Funds-loss bug: counterparty RBF could drop the acceptor's splice contribution

02

State persistence added to remember prior funding contributions across RBF rounds

03

Validation added to reject RBF when prior contribution cannot cover new feerate

04

Serialization added for FundingContribution to preserve state across restarts

05

Tests added for re-contribution, rejection, sequential RBF, and disconnect cleanup

Risk score

Why this scored 59/100

Our methodology →
Potential impact 18/30
Exploitability 12/25
Stealth signal 8/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.