Skip to content

Apply RBF replacements to the wallet before sync - #1124

Open
ram0verflow wants to merge 2 commits into
lightningdevkit:mainfrom
ram0verflow:fix-1117-rbf-before-sync
Open

ram0verflow wants to merge 2 commits into
lightningdevkit:mainfrom
ram0verflow:fix-1117-rbf-before-sync

Conversation

@ram0verflow

Copy link
Copy Markdown

Fixes #1117.

bump_fee_rbf wrote the replacement to the payment store but never applied it to the BDK wallet. A second bump before the next sync returned InvalidPaymentId (release) or panicked on the debug_assert! (debug).

  • Apply the replacement with apply_unconfirmed_txs before take_staged(), seen-at max(now, previous_last_seen + 1).
  • Carry conflicting_txids across rounds in bump_fee_rbf and the TxReplaced handler. The pending record is read before the persister/wallet locks.
  • No filtering of older rounds from chain sources: if a replacement never reaches the mempool, the wallet must fall back to the previous round.

Testing:

  • New onchain_fee_bump_rbf_twice_before_sync: fails on main, passes with this change.
  • onchain_fee_bump_rbf and onchain_fee_bump_rbf_respects_anchor_reserve pass.
  • cargo fmt --check clean; no new clippy warnings.

AI assistance: OpenAI Codex, Claude Code.

@ldk-reviews-bot

ldk-reviews-bot commented Oct 2, 2026 •

Copy link
Copy Markdown

👋 Thanks for assigning @jkczyz 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.

@ldk-reviews-bot
ldk-reviews-bot requested a review from tnull October 2, 2026 14:17
@jkczyz
jkczyz self-requested a review October 2, 2026 15:12
Bumping the same on-chain payment twice left the first replacement
unmapped. The payment id is derived from the original txid and each bump
sets the payment's txid to the newest one, so an earlier replacement is
found only through the pending-store entry's conflicting txids. The bump
never added the replaced txid to that list, so wallet sync's TxReplaced
event for an earlier replacement found no payment, logged an error, and
skipped it. The list stayed incomplete until the newest transaction was
itself replaced or the earlier one confirmed, when the TxReplaced event
for the newest one listed every conflict and repaired it.

The bump now records the replaced txid in the pending-store entry, so
the event resolves to the payment and the error log stops.

Developed with assistance from Claude Code.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Comment thread src/wallet/mod.rs Outdated
Comment on lines +542 to +548
if let Some(previous) = self.pending_payment_store.get(&payment_id).await? {
conflict_txids.extend(previous.conflicting_txids);
}

conflict_txids.push(txid);
conflict_txids.sort_unstable();
conflict_txids.dedup();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this ever add anything?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. The conflicts in TxReplaced come from direct_conflicts, which returns every tx in the graph spending the same outpoints, and each RBF round keeps the original inputs, so earlier rounds are already there. I hadn't checked it properly and assumed earlier entries could get lost. Dropped.

Comment thread src/wallet/mod.rs Outdated
.get(&payment_id)
.await?
.map(|p| p.conflicting_txids)
.unwrap_or_default();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is independent of #1117. A session of mine found this a little while ago, so I took the opportunity to clean it up. Could you base your PR on https://github.com/jkczyz/ldk-node/commits/2026-09-rbf-middle-round-conflict-list? Then you can drop this and the push/sort/dedup below.

Worth updating your commit's message to include something like:

Once the bump applies the replacement to the wallet, sync no longer emits TxReplaced for the replaced transaction (BDK derives events from a before/after diff of the canonical set), so nothing else populates conflicting_txids after a bump until a later eviction or confirmation flips the canonical set.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, rebased on your branch and dropped the conflict handling here. Added the paragraph to the commit message

Comment thread src/wallet/mod.rs
Comment on lines +2291 to +2294
locked_wallet.apply_unconfirmed_txs([(
fee_bumped_tx.clone(),
seen_at.max(previous_seen_at.saturating_add(1)),
)]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth adding a one-line comment on why + 1 is needed.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

@ram0verflow
ram0verflow force-pushed the fix-1117-rbf-before-sync branch from eebb200 to 30fc02b Compare October 3, 2026 02:50
bump_fee_rbf updated the payment store but not the BDK wallet, so a
second bump before sync failed with InvalidPaymentId (or panicked on
debug). Apply the replacement to the wallet immediately, with a seen-at
after the replaced round.

Once the bump applies the replacement to the wallet, sync no longer
emits TxReplaced for the replaced transaction (BDK derives events from
a before/after diff of the canonical set), so nothing else populates
conflicting_txids after a bump until a later eviction or confirmation
flips the canonical set.

Fixes lightningdevkit#1117.

AI assistance: OpenAI Codex, Claude Code.
@ram0verflow
ram0verflow force-pushed the fix-1117-rbf-before-sync branch from 30fc02b to a08f1fd Compare October 3, 2026 02:56
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.

bump_fee_rbf updates payment store before wallet sees replacement

3 participants