Skip to content

Commit 06f558e

Browse files
committed
wallet: accurate SelectionResult::m_target
SelectionResult::m_target should be equal to actual selection target. Selection target is the sum of all recipient amounts plus non input fees. So we need to remove change_fee from the m_target. It's safe because change target is always greater than the change fee, so we can always cover fees if change output is created.
1 parent c8cf08e commit 06f558e

File tree

2 files changed

+10
-16
lines changed

2 files changed

+10
-16
lines changed

src/wallet/coinselection.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ std::optional<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& ut
166166
{
167167
SelectionResult result(target_value, SelectionAlgorithm::SRD);
168168

169+
// Include change for SRD as we want to avoid making really small change if the selection just
170+
// barely meets the target. Just use the lower bound change target instead of the randomly
171+
// generated one, since SRD will result in a random change amount anyway; avoid making the
172+
// target needlessly large.
173+
target_value += CHANGE_LOWER;
174+
169175
std::vector<size_t> indexes;
170176
indexes.resize(utxo_pool.size());
171177
std::iota(indexes.begin(), indexes.end(), 0);

src/wallet/spend.cpp

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -489,31 +489,19 @@ std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, cons
489489
// Vector of results. We will choose the best one based on waste.
490490
std::vector<SelectionResult> results;
491491

492-
// Note that unlike KnapsackSolver, we do not include the fee for creating a change output as BnB will not create a change output.
493-
std::vector<OutputGroup> positive_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, true /* positive_only */);
492+
std::vector<OutputGroup> positive_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, /*positive_only=*/true);
494493
if (auto bnb_result{SelectCoinsBnB(positive_groups, nTargetValue, coin_selection_params.m_cost_of_change)}) {
495494
results.push_back(*bnb_result);
496495
}
497496

498497
// 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.
499-
std::vector<OutputGroup> all_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, false /* positive_only */);
500-
CAmount target_with_change = nTargetValue;
501-
// While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output.
502-
// So we need to include that for KnapsackSolver and SRD as well, as we are expecting to create a change output.
503-
if (!coin_selection_params.m_subtract_fee_outputs) {
504-
target_with_change += coin_selection_params.m_change_fee;
505-
}
506-
if (auto knapsack_result{KnapsackSolver(all_groups, target_with_change, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast)}) {
498+
std::vector<OutputGroup> all_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, /*positive_only=*/false);
499+
if (auto knapsack_result{KnapsackSolver(all_groups, nTargetValue, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast)}) {
507500
knapsack_result->ComputeAndSetWaste(coin_selection_params.m_cost_of_change);
508501
results.push_back(*knapsack_result);
509502
}
510503

511-
// Include change for SRD as we want to avoid making really small change if the selection just
512-
// barely meets the target. Just use the lower bound change target instead of the randomly
513-
// generated one, since SRD will result in a random change amount anyway; avoid making the
514-
// target needlessly large.
515-
const CAmount srd_target = target_with_change + CHANGE_LOWER;
516-
if (auto srd_result{SelectCoinsSRD(positive_groups, srd_target, coin_selection_params.rng_fast)}) {
504+
if (auto srd_result{SelectCoinsSRD(positive_groups, nTargetValue, coin_selection_params.rng_fast)}) {
517505
srd_result->ComputeAndSetWaste(coin_selection_params.m_cost_of_change);
518506
results.push_back(*srd_result);
519507
}

0 commit comments

Comments
 (0)