diff options
author | furszy <matiasfurszyfer@protonmail.com> | 2022-12-18 10:28:59 -0300 |
---|---|---|
committer | furszy <matiasfurszyfer@protonmail.com> | 2023-04-05 09:32:39 -0300 |
commit | 6107ec2229c5f5b4e944a6b10d38010c850094ac (patch) | |
tree | 2871cf2354d648487253ddab816da55e529dd8ac /src/wallet/spend.cpp | |
parent | 1284223691127e76135a46d251c52416104f0ff1 (diff) | |
download | bitcoin-6107ec2229c5f5b4e944a6b10d38010c850094ac.tar.xz |
coin selection: knapsack, select closest UTXO above target if result exceeds max tx size
The simplest scenario where this is useful is on the 'check_max_weight' unit test
already:
We create 1515 UTXOs with 0.033 BTC each, and 1 UTXO with 50 BTC. Then perform
Coin Selection.
As the selection of the 1515 small UTXOs exceeds the max allowed tx size, the
expectation here is to receive a selection result that only contain the big
UTXO (which is not happening for the reasons stated below).
As knapsack returns a result that exceeds the max allowed transaction size, we
fallback to SRD, which selects coins randomly up until the target is met. So
we end up with a selection result with lot more coins than what is needed.
Diffstat (limited to 'src/wallet/spend.cpp')
-rw-r--r-- | src/wallet/spend.cpp | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index a55e4c45a8..b28da6ec42 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -563,12 +563,18 @@ util::Result<SelectionResult> ChooseSelectionResult(const CAmount& nTargetValue, } }; + // Maximum allowed weight + int max_inputs_weight = MAX_STANDARD_TX_WEIGHT - (coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR); + if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change)}) { results.push_back(*bnb_result); } else append_error(bnb_result); + // As Knapsack and SRD can create change, also deduce change weight. + max_inputs_weight -= (coin_selection_params.change_output_size * WITNESS_SCALE_FACTOR); + // 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. - if (auto knapsack_result{KnapsackSolver(groups.mixed_group, nTargetValue, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast)}) { + if (auto knapsack_result{KnapsackSolver(groups.mixed_group, nTargetValue, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast, max_inputs_weight)}) { knapsack_result->ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee); results.push_back(*knapsack_result); } else append_error(knapsack_result); |