@@ -2399,24 +2399,30 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil
2399
2399
setCoinsRet.clear ();
2400
2400
nValueRet = 0 ;
2401
2401
2402
- if (coin_selection_params.use_bnb ) {
2403
- // Get the feerate for effective value.
2404
- // When subtracting the fee from the outputs, we want the effective feerate to be 0
2405
- CFeeRate effective_feerate{0 };
2406
- if (!coin_selection_params.m_subtract_fee_outputs ) {
2407
- effective_feerate = coin_selection_params.m_effective_feerate ;
2408
- }
2402
+ // Calculate the fees for things that aren't inputs, excluding the change output
2403
+ const CAmount not_input_fees = coin_selection_params.m_effective_feerate .GetFee (coin_selection_params.tx_noinputs_size );
2409
2404
2410
- std::vector<OutputGroup> groups = GroupOutputs (coins, !coin_selection_params.m_avoid_partial_spends , effective_feerate, coin_selection_params.m_long_term_feerate , eligibility_filter, true /* positive_only */ );
2405
+ // Get the feerate for effective value.
2406
+ // When subtracting the fee from the outputs, we want the effective feerate to be 0
2407
+ CFeeRate effective_feerate{0 };
2408
+ if (!coin_selection_params.m_subtract_fee_outputs ) {
2409
+ effective_feerate = coin_selection_params.m_effective_feerate ;
2410
+ }
2411
2411
2412
- // Calculate cost of change
2413
- CAmount cost_of_change = coin_selection_params.m_discard_feerate .GetFee (coin_selection_params.change_spend_size ) + coin_selection_params.m_effective_feerate .GetFee (coin_selection_params.change_output_size );
2412
+ // Cost of change is the cost of creating the change output + cost of spending the change output in the future.
2413
+ // For creating the change output now, we use the effective feerate.
2414
+ // For spending the change output in the future, we use the discard feerate for now.
2415
+ // So cost of change = (change output size * effective feerate) + (size of spending change output * discard feerate)
2416
+ const CAmount change_fee = coin_selection_params.m_effective_feerate .GetFee (coin_selection_params.change_output_size );
2417
+ const CAmount cost_of_change = coin_selection_params.m_discard_feerate .GetFee (coin_selection_params.change_spend_size ) + change_fee;
2414
2418
2415
- // Calculate the fees for things that aren't inputs
2416
- CAmount not_input_fees = coin_selection_params.m_effective_feerate . GetFee ( coin_selection_params.tx_noinputs_size );
2419
+ if (coin_selection_params. use_bnb ) {
2420
+ std::vector<OutputGroup> positive_groups = GroupOutputs (coins, ! coin_selection_params.m_avoid_partial_spends , effective_feerate, coin_selection_params.m_long_term_feerate , eligibility_filter, true /* positive_only */ );
2417
2421
bnb_used = true ;
2418
- return SelectCoinsBnB (groups , nTargetValue, cost_of_change, setCoinsRet, nValueRet, not_input_fees);
2422
+ return SelectCoinsBnB (positive_groups , nTargetValue, cost_of_change, setCoinsRet, nValueRet, not_input_fees);
2419
2423
} else {
2424
+ // The knapsack solver has some legacy behavior where it will spend dust outputs. We retain this behavior, so don't filter for positive only here.
2425
+ // The knapsack solver currently does not use effective values, so we give GroupOutputs feerates of 0 so it sets the effective values to be the same as the real value.
2420
2426
std::vector<OutputGroup> groups = GroupOutputs (coins, !coin_selection_params.m_avoid_partial_spends , CFeeRate (0 ), CFeeRate (0 ), eligibility_filter, false /* positive_only */ );
2421
2427
2422
2428
bnb_used = false ;
0 commit comments