diff options
author | furszy <matiasfurszyfer@protonmail.com> | 2022-08-05 12:51:44 -0300 |
---|---|---|
committer | furszy <matiasfurszyfer@protonmail.com> | 2022-10-26 15:54:31 -0300 |
commit | 5baedc33519661af9d19efcefd23dca8998d2547 (patch) | |
tree | 3a52f7a25e97f9bd937a6a8a87c5b027f9f02d6a /src/wallet/spend.cpp | |
parent | 295852f61998a025b0b28a0671e6e1cf0dc08d0d (diff) |
wallet: remove fetch pre-selected-inputs responsibility from SelectCoins
so if there is an error in any of the pre-set coins, we can fail right away
without computing the wallet available coins set (calling `AvailableCoins`)
which is a slow operation as it goes through the entire wallet's txes map.
----------------------
And to make the Coin Selection flow cleared, have decoupled SelectCoins in two functions:
1) AutomaticCoinSelection.
2) SelectCoins.
1) AutomaticCoinSelection:
Receives a set of coins and selects the best subset of them to
cover the target amount.
2) SelectCoins
In charge of select all the user manually selected coins first ("pre-set inputs"), and
if coin_control 'm_allow_other_inputs=true', call 'AutomaticCoinSelection' to select a
subset of coins owned by the wallet to cover for the target - preset_inputs.total_amount
remaining value.
Diffstat (limited to 'src/wallet/spend.cpp')
-rw-r--r-- | src/wallet/spend.cpp | 51 |
1 files changed, 29 insertions, 22 deletions
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 0b7cb7faa4..84c96b041f 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -568,18 +568,14 @@ std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, cons return best_result; } -std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params) +std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const PreSelectedInputs& pre_set_inputs, + const CAmount& nTargetValue, const CCoinControl& coin_control, + const CoinSelectionParams& coin_selection_params) { - CAmount value_to_select = nTargetValue; - - util::Result<PreSelectedInputs> pre_selected_inputs = FetchSelectedInputs(wallet, coin_control, coin_selection_params); - if (!pre_selected_inputs) return std::nullopt; - PreSelectedInputs inputs = *pre_selected_inputs; - // If automatic coin selection was disabled, we just want to return the preset inputs result if (!coin_control.m_allow_other_inputs) { SelectionResult result(nTargetValue, SelectionAlgorithm::MANUAL); - result.AddInputs(inputs.coins, coin_selection_params.m_subtract_fee_outputs); + result.AddInputs(pre_set_inputs.coins, coin_selection_params.m_subtract_fee_outputs); if (!coin_selection_params.m_subtract_fee_outputs && result.GetSelectedEffectiveValue() < nTargetValue) { return std::nullopt; @@ -591,9 +587,23 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a return result; } - // Decrease the already selected amount - value_to_select -= inputs.total_amount; + // Decrease the selection target before start the automatic coin selection + CAmount selection_target = nTargetValue - pre_set_inputs.total_amount; + auto op_selection_result = AutomaticCoinSelection(wallet, available_coins, selection_target, coin_control, coin_selection_params); + if (!op_selection_result) return op_selection_result; + + // Add preset inputs to the automatic coin selection result + SelectionResult preselected(pre_set_inputs.total_amount, SelectionAlgorithm::MANUAL); + preselected.AddInputs(pre_set_inputs.coins, coin_selection_params.m_subtract_fee_outputs); + op_selection_result->Merge(preselected); + if (op_selection_result->GetAlgo() == SelectionAlgorithm::MANUAL) { + op_selection_result->ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee); + } + return op_selection_result; +} +std::optional<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& value_to_select, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params) +{ unsigned int limit_ancestor_count = 0; unsigned int limit_descendant_count = 0; wallet.chain().getPackageLimits(limit_ancestor_count, limit_descendant_count); @@ -610,9 +620,6 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a available_coins.Shuffle(coin_selection_params.rng_fast); } - SelectionResult preselected(inputs.total_amount, SelectionAlgorithm::MANUAL); - preselected.AddInputs(inputs.coins, coin_selection_params.m_subtract_fee_outputs); - // Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the // transaction at a target feerate. If an attempt fails, more attempts may be made using a more // permissive CoinEligibilityFilter. @@ -669,14 +676,6 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a return std::optional<SelectionResult>(); }(); - if (!res) return std::nullopt; - - // Add preset inputs to result - res->Merge(preselected); - if (res->GetAlgo() == SelectionAlgorithm::MANUAL) { - res->ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee); - } - return res; } @@ -889,6 +888,14 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.tx_noinputs_size); CAmount selection_target = recipients_sum + not_input_fees; + // Fetch manually selected coins + PreSelectedInputs preset_inputs; + if (coin_control.HasSelected()) { + auto res_fetch_inputs = FetchSelectedInputs(wallet, coin_control, coin_selection_params); + if (!res_fetch_inputs) return util::Error{util::ErrorString(res_fetch_inputs)}; + preset_inputs = *res_fetch_inputs; + } + // Fetch wallet available coins if "other inputs" are // allowed (coins automatically selected by the wallet) CoinsResult available_coins; @@ -903,7 +910,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( } // Choose coins to use - std::optional<SelectionResult> result = SelectCoins(wallet, available_coins, /*nTargetValue=*/selection_target, coin_control, coin_selection_params); + std::optional<SelectionResult> result = SelectCoins(wallet, available_coins, preset_inputs, /*nTargetValue=*/selection_target, coin_control, coin_selection_params); if (!result) { return util::Error{_("Insufficient funds")}; } |