txconfirm: release abandoned fee input on CPFP reselect - #1066
Conversation
|
@claude please review this PR. It closes #664: The interesting part is the carried-over caveat, so please scrutinise:
Repro test |
|
Claude finished @ellemouton's task in 2m 29s —— View job Review:
|
When the precise per-input vsize recompute grows the package fee enough to push the selected fee input's change below the dust limit, broadcastWithCPFP reselects a larger fee input. It had already reserved and wallet-leased the original input, and never released it: the abandoned UTXO stayed locked for the parent's whole lifetime (or until the lease expired) even though the CPFP child only spends the reselected input, needlessly starving other fee selections (#664). Release the abandoned input's reservation and wallet lease when the reselect lands on a different outpoint. The release is skipped for a fee input carried over from a prior committed bump: TRUC package RBF needs the replacement child to double-spend the previous child's fee input, so that input must stay reserved. feeOutpointReserved records the carried- over state before the (idempotent) re-reservation so the two cases are told apart.
a5589ef to
8664040
Compare
|
Successfully created backport PR for |
Closes #664.
Problem
In
broadcastWithCPFP, when the precise per-input vsize recompute growsthe package fee enough to push the originally selected fee input's change
below the dust limit, the broadcaster reselects a larger fee input — but
it had already
reserveFeeInput'd (and wallet-LeaseOutput'd) theoriginal before the reselect and never released it. The abandoned UTXO
stays reserved and wallet-leased for the parent's whole lifetime (or until
DefaultFeeInputLeaseExpiry), even though the CPFP child only ever spendsthe reselected input. It's a spurious UTXO lock (not fund loss) that
starves other fee selections.
Fix
Release the abandoned input's reservation + wallet lease
(
releaseFeeOutpoint) when the reselect lands on a different outpoint.The caveat that makes this non-trivial:
selectFeeInputcanlegitimately return a carried-over reservation on a fee bump — TRUC
package RBF requires the replacement child to double-spend the previous
child's fee input, so that input must stay reserved. The release therefore
skips a carried-over input:
feeOutpointReservedrecords whether the inputwas already reserved before the (idempotent) re-reservation, so a
freshly-selected-and-abandoned input is released while a carried-over one
is left intact.
Testing
TestCPFPReselectReleasesAbandonedFeeInputdrives the exact reselect path(a P2PKH fee input heavier than the OP_TRUE change proxy grows the fee and
forces a reselect off the small UTXO) and asserts the abandoned input is
dropped from the in-memory reservation set and its wallet lease is
released, while the reselected input stays reserved. It fails on
mainandpasses with the fix. Full
txconfirmsuite +lint-changed-localgreen.🤖 Generated with Claude Code