From 61c2265629fdf11a2cc266fad54ceb0a1247bb5e Mon Sep 17 00:00:00 2001 From: furszy Date: Wed, 12 Oct 2022 23:37:02 -0300 Subject: [PATCH] wallet: group AvailableCoins filtering parameters in a single struct Plus clean callers that use the params default values --- src/bench/wallet_create_tx.cpp | 5 +++-- src/wallet/rpc/coins.cpp | 19 +++++++--------- src/wallet/rpc/spend.cpp | 4 +++- src/wallet/spend.cpp | 40 ++++++++++------------------------ src/wallet/spend.h | 26 +++++++++++++++------- 5 files changed, 44 insertions(+), 50 deletions(-) diff --git a/src/bench/wallet_create_tx.cpp b/src/bench/wallet_create_tx.cpp index 207b22c584..d6c133f9d2 100644 --- a/src/bench/wallet_create_tx.cpp +++ b/src/bench/wallet_create_tx.cpp @@ -111,9 +111,10 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type CAmount target = 0; if (preset_inputs) { // Select inputs, each has 49 BTC + wallet::CoinFilterParams filter_coins; + filter_coins.nMaximumCount = preset_inputs->num_of_internal_inputs; const auto& res = WITH_LOCK(wallet.cs_wallet, - return wallet::AvailableCoins(wallet, nullptr, std::nullopt, 1, MAX_MONEY, - MAX_MONEY, preset_inputs->num_of_internal_inputs)); + return wallet::AvailableCoins(wallet, /*coinControl=*/nullptr, /*feerate=*/std::nullopt, filter_coins)); for (int i=0; i < preset_inputs->num_of_internal_inputs; i++) { const auto& coin{res.coins.at(output_type)[i]}; target += coin.txout.nValue; diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index da961b97ef..837162ce07 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -591,11 +591,8 @@ RPCHelpMan listunspent() include_unsafe = request.params[3].get_bool(); } - CAmount nMinimumAmount = 0; - CAmount nMaximumAmount = MAX_MONEY; - CAmount nMinimumSumAmount = MAX_MONEY; - uint64_t nMaximumCount = 0; - bool include_immature_coinbase{false}; + CoinFilterParams filter_coins; + filter_coins.nMinimumAmount = 0; if (!request.params[4].isNull()) { const UniValue& options = request.params[4].get_obj(); @@ -611,19 +608,19 @@ RPCHelpMan listunspent() true, true); if (options.exists("minimumAmount")) - nMinimumAmount = AmountFromValue(options["minimumAmount"]); + filter_coins.nMinimumAmount = AmountFromValue(options["minimumAmount"]); if (options.exists("maximumAmount")) - nMaximumAmount = AmountFromValue(options["maximumAmount"]); + filter_coins.nMaximumAmount = AmountFromValue(options["maximumAmount"]); if (options.exists("minimumSumAmount")) - nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]); + filter_coins.nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]); if (options.exists("maximumCount")) - nMaximumCount = options["maximumCount"].getInt(); + filter_coins.nMaximumCount = options["maximumCount"].getInt(); if (options.exists("include_immature_coinbase")) { - include_immature_coinbase = options["include_immature_coinbase"].get_bool(); + filter_coins.include_immature_coinbase = options["include_immature_coinbase"].get_bool(); } } @@ -640,7 +637,7 @@ RPCHelpMan listunspent() cctl.m_max_depth = nMaxDepth; cctl.m_include_unsafe_inputs = include_unsafe; LOCK(pwallet->cs_wallet); - vecOutputs = AvailableCoinsListUnspent(*pwallet, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, include_immature_coinbase).All(); + vecOutputs = AvailableCoinsListUnspent(*pwallet, &cctl, filter_coins).All(); } LOCK(pwallet->cs_wallet); diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 6cb33fc11e..8cfd28d887 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -1385,7 +1385,9 @@ RPCHelpMan sendall() total_input_value += tx->tx->vout[input.prevout.n].nValue; } } else { - for (const COutput& output : AvailableCoins(*pwallet, &coin_control, fee_rate, /*nMinimumAmount=*/0).All()) { + CoinFilterParams coins_params; + coins_params.nMinimumAmount = 0; + for (const COutput& output : AvailableCoins(*pwallet, &coin_control, fee_rate, coins_params).All()) { CHECK_NONFATAL(output.input_bytes > 0); if (send_max && fee_rate.GetFee(output.input_bytes) > output.txout.nValue) { continue; diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 03d260ea96..2ec6607923 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -191,12 +191,7 @@ util::Result FetchSelectedInputs(const CWallet& wallet, const CoinsResult AvailableCoins(const CWallet& wallet, const CCoinControl* coinControl, std::optional feerate, - const CAmount& nMinimumAmount, - const CAmount& nMaximumAmount, - const CAmount& nMinimumSumAmount, - const uint64_t nMaximumCount, - bool only_spendable, - bool include_immature_coinbase) + const CoinFilterParams& params) { AssertLockHeld(wallet.cs_wallet); @@ -214,7 +209,7 @@ CoinsResult AvailableCoins(const CWallet& wallet, const uint256& wtxid = entry.first; const CWalletTx& wtx = entry.second; - if (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase) + if (wallet.IsTxImmatureCoinBase(wtx) && !params.include_immature_coinbase) continue; int nDepth = wallet.GetTxDepthInMainChain(wtx); @@ -273,7 +268,7 @@ CoinsResult AvailableCoins(const CWallet& wallet, const CTxOut& output = wtx.tx->vout[i]; const COutPoint outpoint(wtxid, i); - if (output.nValue < nMinimumAmount || output.nValue > nMaximumAmount) + if (output.nValue < params.nMinimumAmount || output.nValue > params.nMaximumAmount) continue; // Skip manually selected coins (the caller can fetch them directly) @@ -305,7 +300,7 @@ CoinsResult AvailableCoins(const CWallet& wallet, bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable)); // Filter by spendable outputs only - if (!spendable && only_spendable) continue; + if (!spendable && params.only_spendable) continue; // Obtain script type std::vector> script_solutions; @@ -329,14 +324,14 @@ CoinsResult AvailableCoins(const CWallet& wallet, // Cache total amount as we go result.total_amount += output.nValue; // Checks the sum amount of all UTXO's. - if (nMinimumSumAmount != MAX_MONEY) { - if (result.total_amount >= nMinimumSumAmount) { + if (params.nMinimumSumAmount != MAX_MONEY) { + if (result.total_amount >= params.nMinimumSumAmount) { return result; } } // Checks the maximum number of UTXO's. - if (nMaximumCount > 0 && result.Size() >= nMaximumCount) { + if (params.nMaximumCount > 0 && result.Size() >= params.nMaximumCount) { return result; } } @@ -345,21 +340,16 @@ CoinsResult AvailableCoins(const CWallet& wallet, return result; } -CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl, const CAmount& nMinimumAmount, const CAmount& nMaximumAmount, const CAmount& nMinimumSumAmount, const uint64_t nMaximumCount, bool include_immature_coinbase) +CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl, CoinFilterParams params) { - return AvailableCoins(wallet, coinControl, /*feerate=*/ std::nullopt, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, /*only_spendable=*/false, include_immature_coinbase); + params.only_spendable = false; + return AvailableCoins(wallet, coinControl, /*feerate=*/ std::nullopt, params); } CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl) { LOCK(wallet.cs_wallet); - return AvailableCoins(wallet, coinControl, - /*feerate=*/ std::nullopt, - /*nMinimumAmount=*/ 1, - /*nMaximumAmount=*/ MAX_MONEY, - /*nMinimumSumAmount=*/ MAX_MONEY, - /*nMaximumCount=*/ 0 - ).total_amount; + return AvailableCoins(wallet, coinControl).total_amount; } const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const CTransaction& tx, int output) @@ -898,13 +888,7 @@ static util::Result CreateTransactionInternal( // allowed (coins automatically selected by the wallet) CoinsResult available_coins; if (coin_control.m_allow_other_inputs) { - available_coins = AvailableCoins(wallet, - &coin_control, - coin_selection_params.m_effective_feerate, - 1, /*nMinimumAmount*/ - MAX_MONEY, /*nMaximumAmount*/ - MAX_MONEY, /*nMinimumSumAmount*/ - 0); /*nMaximumCount*/ + available_coins = AvailableCoins(wallet, &coin_control, coin_selection_params.m_effective_feerate); } // Choose coins to use diff --git a/src/wallet/spend.h b/src/wallet/spend.h index 1d4570dcbb..fc7f7bc535 100644 --- a/src/wallet/spend.h +++ b/src/wallet/spend.h @@ -55,24 +55,34 @@ struct CoinsResult { CAmount total_amount{0}; }; +struct CoinFilterParams { + // Outputs below the minimum amount will not get selected + CAmount nMinimumAmount{1}; + // Outputs above the maximum amount will not get selected + CAmount nMaximumAmount{MAX_MONEY}; + // Return outputs until the minimum sum amount is covered + CAmount nMinimumSumAmount{MAX_MONEY}; + // Maximum number of outputs that can be returned + uint64_t nMaximumCount{0}; + // By default, return only spendable outputs + bool only_spendable{true}; + // By default, do not include immature coinbase outputs + bool include_immature_coinbase{false}; +}; + /** * Populate the CoinsResult struct with vectors of available COutputs, organized by OutputType. */ CoinsResult AvailableCoins(const CWallet& wallet, const CCoinControl* coinControl = nullptr, std::optional feerate = std::nullopt, - const CAmount& nMinimumAmount = 1, - const CAmount& nMaximumAmount = MAX_MONEY, - const CAmount& nMinimumSumAmount = MAX_MONEY, - const uint64_t nMaximumCount = 0, - bool only_spendable = true, - bool include_immature_coinbase = false) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); + const CoinFilterParams& params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); /** - * Wrapper function for AvailableCoins which skips the `feerate` parameter. Use this function + * Wrapper function for AvailableCoins which skips the `feerate` and `CoinFilterParams::only_spendable` parameters. Use this function * to list all available coins (e.g. listunspent RPC) while not intending to fund a transaction. */ -CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, bool include_immature_coinbase = false) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); +CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl = nullptr, CoinFilterParams params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl = nullptr);