I hit this assertion in a test running on Antithesis.
Vibe coded functional test to demonstrate: https://github.com/dergoegge/bitcoin/commit/587e42c3504bed5cb45137cd151f1e80e2314eed. Because this is caused by a race condition, the commit also includes a sleep to reliably trigger the issue.
0node0 stderr bitcoind: wallet/coinselection.cpp:823: void wallet::SelectionResult::SetBumpFeeDiscount(const CAmount): Assertion `discount >= 0' failed.
Bug
Assertion discount >= 0 fails in SelectionResult::SetBumpFeeDiscount (src/wallet/coinselection.cpp:823).
Found during Antithesis testing with concurrent transaction creation.
Root Cause
Race condition between two MiniMiner calculations during coin selection:
- Individual bump fees calculated in
AvailableCoins(spend.cpp:517) viacalculateIndividualBumpFees()- creates MiniMiner, copies mempool state, releases lock - Combined bump fee calculated later in
ChooseSelectionResult(spend.cpp:809) viacalculateCombinedBumpFee()- creates a new MiniMiner with potentially different mempool state
Each MiniMiner constructor acquires LOCK(mempool.cs) only for the duration of the constructor (mini_miner.cpp:26). The lock is released before the actual fee calculations run.
If mempool state changes between these two calls (e.g., fee deltas modified via prioritisetransaction, new transactions, evictions), the combined calculation can return a higher value than the sum of individual calculations:
0// spend.cpp:813-815
1CAmount bump_fee_overestimate = summed_bump_fees - combined_bump_fee.value();
2if (bump_fee_overestimate) {
3 result.SetBumpFeeDiscount(bump_fee_overestimate); // negative if combined > summed
4}