Pre-Submission Checklist
LND Version
0.20.1-beta (commit v0.20.1-beta-1-g20a93e8e9)
LND Configuration
Standard config; sweeper using default fee-bumping / RBF behaviour. Nodes sweep to_remote outputs after remote-initiated force-closes.
Backend Version
bitcoind (full node)
Backend Configuration
Default.
OS/Distribution
Linux (containerised).
Bug Details & Steps to Reproduce
We noticed some sweep transactions being reported as receives by downstream tooling (Faraday), and traced it to sweeps disappearing from ListSweeps.
The pattern occurs when a peer force-closes a channel and our node sweeps its balance back to its own wallet:
- Sweeper broadcasts sweep tx A at a low feerate.
- The fee bumper RBFs it, producing replacement B at a higher feerate.
handleBumpEventTxReplaced calls Store.DeleteTx(A) and then stores B.
- Due to a mempool/propagation race, the original tx A is the one that confirms — not replacement B.
- The input is marked swept via the spend notification.
TxConfirmed is not handled in handleBumpEvent (comment: "we already subscribe to the input's spending event"), and markInputsSwept does not call StoreTx.
Net effect: no code path ever re-adds the confirmed tx A to the sweeper store. The store is left holding only B, which never confirmed.
Example (mainnet), txids redacted — happy to share the specific transactions and fuller logs privately:
SWPR: Created initial sweep tx=<A> feerate=750 sat/kw, fee=365 sats
SWPR: RBFed tx=<A> (fee=365, 750 sat/kw) with new tx=<B> (fee=606, 1246 sat/kw)
CNCT: commitSweepResolver(...): local commitment output was swept by remote party via <A>
The original tx <A> confirmed on-chain; the replacement <B> never did. Because <A> was deleted from the store on RBF, IsOurTx(<A>) returns false — producing the "swept by remote party" log for our own tx — and <A> is absent from ListSweeps.
Expected Behavior
After an RBF where the original/replaced tx is the one that confirms, the confirmed sweep txid should still be discoverable — ListSweeps should include it and IsOurTx should return true for it.
Actual Behavior
The confirmed sweep txid is permanently missing from ListSweeps and IsOurTx returns false, because it was removed from the store on the RBF replacement and never re-added. Funds are resolved correctly on-chain (this is purely a bookkeeping/labeling issue), but ListSweeps consumers misclassify the sweep.
Possible fix directions (happy to open a PR in whatever shape you'd prefer):
- On the input's spend notification, if the confirming txid isn't already in the store, record it (reconcile the store to the actually-confirmed tx); or
- Defer deleting the replaced tx until the input is fully resolved, so whichever variant confirms remains discoverable.
Debug Information
Relevant SWPR / CNCT sweeper log excerpts above; fuller logs available on request.
Environment
lnd 0.20.1-beta, bitcoind backend, Linux.
Pre-Submission Checklist
LND Version
0.20.1-beta(commitv0.20.1-beta-1-g20a93e8e9)LND Configuration
Standard config; sweeper using default fee-bumping / RBF behaviour. Nodes sweep
to_remoteoutputs after remote-initiated force-closes.Backend Version
bitcoind (full node)
Backend Configuration
Default.
OS/Distribution
Linux (containerised).
Bug Details & Steps to Reproduce
We noticed some sweep transactions being reported as receives by downstream tooling (Faraday), and traced it to sweeps disappearing from
ListSweeps.The pattern occurs when a peer force-closes a channel and our node sweeps its balance back to its own wallet:
handleBumpEventTxReplacedcallsStore.DeleteTx(A)and then stores B.TxConfirmedis not handled inhandleBumpEvent(comment: "we already subscribe to the input's spending event"), andmarkInputsSweptdoes not callStoreTx.Net effect: no code path ever re-adds the confirmed tx A to the sweeper store. The store is left holding only B, which never confirmed.
Example (mainnet), txids redacted — happy to share the specific transactions and fuller logs privately:
The original tx
<A>confirmed on-chain; the replacement<B>never did. Because<A>was deleted from the store on RBF,IsOurTx(<A>)returns false — producing the "swept by remote party" log for our own tx — and<A>is absent fromListSweeps.Expected Behavior
After an RBF where the original/replaced tx is the one that confirms, the confirmed sweep txid should still be discoverable —
ListSweepsshould include it andIsOurTxshould return true for it.Actual Behavior
The confirmed sweep txid is permanently missing from
ListSweepsandIsOurTxreturns false, because it was removed from the store on the RBF replacement and never re-added. Funds are resolved correctly on-chain (this is purely a bookkeeping/labeling issue), butListSweepsconsumers misclassify the sweep.Possible fix directions (happy to open a PR in whatever shape you'd prefer):
Debug Information
Relevant
SWPR/CNCTsweeper log excerpts above; fuller logs available on request.Environment
lnd 0.20.1-beta, bitcoind backend, Linux.