2022-12-24 23:49:50 +00:00
|
|
|
// Copyright (c) 2021-2022 The Bitcoin Core developers
|
2021-02-10 16:06:01 -05:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#ifndef BITCOIN_WALLET_SPEND_H
|
|
|
|
#define BITCOIN_WALLET_SPEND_H
|
|
|
|
|
2021-09-11 10:29:00 +08:00
|
|
|
#include <consensus/amount.h>
|
2022-05-24 12:29:51 -03:00
|
|
|
#include <policy/fees.h> // for FeeCalculation
|
2022-04-08 16:43:10 -03:00
|
|
|
#include <util/result.h>
|
2021-02-10 16:06:01 -05:00
|
|
|
#include <wallet/coinselection.h>
|
|
|
|
#include <wallet/transaction.h>
|
|
|
|
#include <wallet/wallet.h>
|
|
|
|
|
2020-12-13 03:15:40 +01:00
|
|
|
#include <optional>
|
|
|
|
|
2021-11-12 11:13:29 -05:00
|
|
|
namespace wallet {
|
2022-01-18 21:04:26 -05:00
|
|
|
/** Get the marginal bytes if spending the specified output from this transaction.
|
2022-06-27 09:11:09 +02:00
|
|
|
* Use CoinControl to determine whether to expect signature grinding when calculating the size of the input spend. */
|
|
|
|
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet, const CCoinControl* coin_control = nullptr);
|
|
|
|
int CalculateMaximumSignedInputSize(const CTxOut& txout, const COutPoint outpoint, const SigningProvider* pwallet, const CCoinControl* coin_control = nullptr);
|
2021-02-12 18:01:22 -05:00
|
|
|
struct TxSize {
|
|
|
|
int64_t vsize{-1};
|
|
|
|
int64_t weight{-1};
|
|
|
|
};
|
|
|
|
|
2022-06-27 09:11:09 +02:00
|
|
|
/** Calculate the size of the transaction using CoinControl to determine
|
|
|
|
* whether to expect signature grinding when calculating the size of the input spend. */
|
2019-10-18 17:17:17 -04:00
|
|
|
TxSize CalculateMaximumSignedTxSize(const CTransaction& tx, const CWallet* wallet, const std::vector<CTxOut>& txouts, const CCoinControl* coin_control = nullptr);
|
|
|
|
TxSize CalculateMaximumSignedTxSize(const CTransaction& tx, const CWallet* wallet, const CCoinControl* coin_control = nullptr) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet);
|
2021-02-12 18:01:22 -05:00
|
|
|
|
2022-03-11 16:30:04 +01:00
|
|
|
/**
|
|
|
|
* COutputs available for spending, stored by OutputType.
|
|
|
|
* This struct is really just a wrapper around OutputType vectors with a convenient
|
|
|
|
* method for concatenating and returning all COutputs as one vector.
|
|
|
|
*
|
2022-07-29 10:35:50 +02:00
|
|
|
* Size(), Clear(), Erase(), Shuffle(), and Add() methods are implemented to
|
|
|
|
* allow easy interaction with the struct.
|
2022-03-11 16:30:04 +01:00
|
|
|
*/
|
2022-04-22 17:31:28 -03:00
|
|
|
struct CoinsResult {
|
2022-07-29 10:01:25 +02:00
|
|
|
std::map<OutputType, std::vector<COutput>> coins;
|
2022-03-11 16:30:04 +01:00
|
|
|
|
|
|
|
/** Concatenate and return all COutputs as one vector */
|
2022-08-10 14:35:53 +02:00
|
|
|
std::vector<COutput> All() const;
|
2022-03-11 16:30:04 +01:00
|
|
|
|
|
|
|
/** The following methods are provided so that CoinsResult can mimic a vector,
|
|
|
|
* i.e., methods can work with individual OutputType vectors or on the entire object */
|
2022-07-29 10:35:50 +02:00
|
|
|
size_t Size() const;
|
2022-12-08 15:55:41 -03:00
|
|
|
/** Return how many different output types this struct stores */
|
|
|
|
size_t TypesCount() const { return coins.size(); }
|
2022-08-10 14:35:53 +02:00
|
|
|
void Clear();
|
2022-11-22 11:39:35 -03:00
|
|
|
void Erase(const std::unordered_set<COutPoint, SaltedOutpointHasher>& coins_to_remove);
|
2022-07-29 10:01:25 +02:00
|
|
|
void Shuffle(FastRandomContext& rng_fast);
|
|
|
|
void Add(OutputType type, const COutput& out);
|
2022-03-11 16:30:04 +01:00
|
|
|
|
2022-12-02 12:33:22 -03:00
|
|
|
CAmount GetTotalAmount() { return total_amount; }
|
|
|
|
std::optional<CAmount> GetEffectiveTotalAmount() {return total_effective_amount; }
|
|
|
|
|
|
|
|
private:
|
2022-11-22 11:51:33 -03:00
|
|
|
/** Sum of all available coins raw value */
|
2022-04-27 11:15:09 -03:00
|
|
|
CAmount total_amount{0};
|
2022-11-22 11:51:33 -03:00
|
|
|
/** Sum of all available coins effective value (each output value minus fees required to spend it) */
|
|
|
|
std::optional<CAmount> total_effective_amount{0};
|
2022-04-22 17:31:28 -03:00
|
|
|
};
|
2022-03-11 16:30:04 +01:00
|
|
|
|
2022-10-12 23:37:02 -03:00
|
|
|
struct CoinFilterParams {
|
|
|
|
// Outputs below the minimum amount will not get selected
|
2022-10-13 16:26:53 -03:00
|
|
|
CAmount min_amount{1};
|
2022-10-12 23:37:02 -03:00
|
|
|
// Outputs above the maximum amount will not get selected
|
2022-10-13 16:26:53 -03:00
|
|
|
CAmount max_amount{MAX_MONEY};
|
2022-10-12 23:37:02 -03:00
|
|
|
// Return outputs until the minimum sum amount is covered
|
2022-10-13 16:26:53 -03:00
|
|
|
CAmount min_sum_amount{MAX_MONEY};
|
2022-10-12 23:37:02 -03:00
|
|
|
// Maximum number of outputs that can be returned
|
2022-10-13 16:26:53 -03:00
|
|
|
uint64_t max_count{0};
|
2022-10-12 23:37:02 -03:00
|
|
|
// By default, return only spendable outputs
|
|
|
|
bool only_spendable{true};
|
|
|
|
// By default, do not include immature coinbase outputs
|
|
|
|
bool include_immature_coinbase{false};
|
2022-07-28 16:57:58 -03:00
|
|
|
// By default, skip locked UTXOs
|
|
|
|
bool skip_locked{true};
|
2022-10-12 23:37:02 -03:00
|
|
|
};
|
|
|
|
|
2021-02-12 18:01:22 -05:00
|
|
|
/**
|
2022-03-11 16:30:04 +01:00
|
|
|
* Populate the CoinsResult struct with vectors of available COutputs, organized by OutputType.
|
2021-02-12 18:01:22 -05:00
|
|
|
*/
|
wallet: add 'only_spendable' filter to AvailableCoins
We are skipping the non-spendable coins that appear in vCoins ('AvailableCoins' result) later, in several parts of the CreateTransaction and GetBalance flows:
GetAvailableBalance (1) gets all the available coins calling AvailableCoins and, right away, walk through the entire vector, skipping the non-spendable coins, to calculate the total balance.
Inside CreateTransactionInternal —> SelectCoins(vCoins,...), we have several calls to AttemptSelection which, on each of them internally, we call twice to GroupOutputs which internally has two for-loops over the entire vCoins vector that skip the non-spendable coins.
So, Purpose is not add the non-spendable coins into the AvailableCoins result (vCoins) in the first place for the processes that aren’t using them at all, so we don’t waste resources skipping them later so many times.
Note: this speedup is for all the processes that call to CreateTransaction and GetBalance* internally.
2022-06-02 14:45:04 -03:00
|
|
|
CoinsResult AvailableCoins(const CWallet& wallet,
|
|
|
|
const CCoinControl* coinControl = nullptr,
|
|
|
|
std::optional<CFeeRate> feerate = std::nullopt,
|
2022-10-12 23:37:02 -03:00
|
|
|
const CoinFilterParams& params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
2022-04-24 18:01:58 -04:00
|
|
|
|
|
|
|
/**
|
2022-10-12 23:37:02 -03:00
|
|
|
* Wrapper function for AvailableCoins which skips the `feerate` and `CoinFilterParams::only_spendable` parameters. Use this function
|
2022-04-24 18:01:58 -04:00
|
|
|
* to list all available coins (e.g. listunspent RPC) while not intending to fund a transaction.
|
|
|
|
*/
|
2022-10-12 23:37:02 -03:00
|
|
|
CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl = nullptr, CoinFilterParams params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
2021-02-12 18:01:22 -05:00
|
|
|
|
|
|
|
CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl = nullptr);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find non-change parent output.
|
|
|
|
*/
|
|
|
|
const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const CTransaction& tx, int output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
2022-01-18 19:08:42 -05:00
|
|
|
const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
2021-02-12 18:01:22 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return list of available coins and locked coins grouped by non-change output address.
|
|
|
|
*/
|
|
|
|
std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
|
|
|
|
|
|
|
std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<COutput>& outputs, const CoinSelectionParams& coin_sel_params, const CoinEligibilityFilter& filter, bool positive_only);
|
|
|
|
/**
|
2022-03-25 20:57:40 +01:00
|
|
|
* Attempt to find a valid input set that preserves privacy by not mixing OutputTypes.
|
|
|
|
* `ChooseSelectionResult()` will be called on each OutputType individually and the best
|
|
|
|
* the solution (according to the waste metric) will be chosen. If a valid input cannot be found from any
|
|
|
|
* single OutputType, fallback to running `ChooseSelectionResult()` over all available coins.
|
2021-05-21 18:39:41 -04:00
|
|
|
*
|
2022-03-25 20:57:40 +01:00
|
|
|
* param@[in] wallet The wallet which provides solving data for the coins
|
|
|
|
* param@[in] nTargetValue The target value
|
|
|
|
* param@[in] eligilibity_filter A filter containing rules for which coins are allowed to be included in this selection
|
|
|
|
* param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
|
|
|
|
* param@[in] coin_selection_params Parameters for the coin selection
|
|
|
|
* param@[in] allow_mixed_output_types Relax restriction that SelectionResults must be of the same OutputType
|
|
|
|
* returns If successful, a SelectionResult containing the input set
|
2022-12-07 14:35:46 -03:00
|
|
|
* If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds")
|
|
|
|
* or (2) an specific error message if there was something particularly wrong (e.g. a selection
|
|
|
|
* result that surpassed the tx max weight size).
|
2021-02-12 18:01:22 -05:00
|
|
|
*/
|
2022-08-08 15:18:45 -03:00
|
|
|
util::Result<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins,
|
2022-03-25 20:57:40 +01:00
|
|
|
const CoinSelectionParams& coin_selection_params, bool allow_mixed_output_types);
|
2022-04-20 13:37:18 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Attempt to find a valid input set that meets the provided eligibility filter and target.
|
|
|
|
* Multiple coin selection algorithms will be run and the input set that produces the least waste
|
|
|
|
* (according to the waste metric) will be chosen.
|
|
|
|
*
|
|
|
|
* param@[in] wallet The wallet which provides solving data for the coins
|
|
|
|
* param@[in] nTargetValue The target value
|
|
|
|
* param@[in] eligilibity_filter A filter containing rules for which coins are allowed to be included in this selection
|
|
|
|
* param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
|
|
|
|
* param@[in] coin_selection_params Parameters for the coin selection
|
|
|
|
* returns If successful, a SelectionResult containing the input set
|
2022-12-07 14:35:46 -03:00
|
|
|
* If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds")
|
|
|
|
* or (2) an specific error message if there was something particularly wrong (e.g. a selection
|
|
|
|
* result that surpassed the tx max weight size).
|
2022-04-20 13:37:18 +02:00
|
|
|
*/
|
2022-08-08 15:18:45 -03:00
|
|
|
util::Result<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins,
|
2021-05-21 18:39:41 -04:00
|
|
|
const CoinSelectionParams& coin_selection_params);
|
2021-02-12 18:01:22 -05:00
|
|
|
|
2022-07-22 16:16:44 -03:00
|
|
|
// User manually selected inputs that must be part of the transaction
|
|
|
|
struct PreSelectedInputs
|
|
|
|
{
|
|
|
|
std::set<COutput> coins;
|
|
|
|
// If subtract fee from outputs is disabled, the 'total_amount'
|
|
|
|
// will be the sum of each output effective value
|
|
|
|
// instead of the sum of the outputs amount
|
|
|
|
CAmount total_amount{0};
|
|
|
|
|
|
|
|
void Insert(const COutput& output, bool subtract_fee_outputs)
|
|
|
|
{
|
|
|
|
if (subtract_fee_outputs) {
|
|
|
|
total_amount += output.txout.nValue;
|
|
|
|
} else {
|
|
|
|
total_amount += output.GetEffectiveValue();
|
|
|
|
}
|
|
|
|
coins.insert(output);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-02-12 18:01:22 -05:00
|
|
|
/**
|
2022-08-05 12:51:44 -03:00
|
|
|
* Fetch and validate coin control selected inputs.
|
|
|
|
* Coins could be internal (from the wallet) or external.
|
|
|
|
*/
|
|
|
|
util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const CCoinControl& coin_control,
|
|
|
|
const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Select a set of coins such that nTargetValue is met; never select unconfirmed coins if they are not ours
|
2021-05-21 18:55:21 -04:00
|
|
|
* param@[in] wallet The wallet which provides data necessary to spend the selected coins
|
2022-04-20 13:37:18 +02:00
|
|
|
* param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
|
2021-05-21 18:55:21 -04:00
|
|
|
* param@[in] nTargetValue The target value
|
|
|
|
* param@[in] coin_selection_params Parameters for this coin selection such as feerates, whether to avoid partial spends,
|
|
|
|
* and whether to subtract the fee from the outputs.
|
|
|
|
* returns If successful, a SelectionResult containing the selected coins
|
2022-12-07 14:35:46 -03:00
|
|
|
* If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds")
|
|
|
|
* or (2) an specific error message if there was something particularly wrong (e.g. a selection
|
|
|
|
* result that surpassed the tx max weight size).
|
2021-02-12 18:01:22 -05:00
|
|
|
*/
|
2022-08-08 15:18:45 -03:00
|
|
|
util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control,
|
2021-05-21 18:55:21 -04:00
|
|
|
const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
2021-02-12 18:01:22 -05:00
|
|
|
|
2022-08-05 12:51:44 -03:00
|
|
|
/**
|
|
|
|
* Select all coins from coin_control, and if coin_control 'm_allow_other_inputs=true', call 'AutomaticCoinSelection' to
|
|
|
|
* select a set of coins such that nTargetValue - pre_set_inputs.total_amount is met.
|
|
|
|
*/
|
2022-08-08 15:18:45 -03:00
|
|
|
util::Result<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) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
2022-08-05 12:51:44 -03:00
|
|
|
|
2020-12-13 01:37:40 +01:00
|
|
|
struct CreatedTransactionResult
|
|
|
|
{
|
|
|
|
CTransactionRef tx;
|
|
|
|
CAmount fee;
|
2022-05-24 12:29:51 -03:00
|
|
|
FeeCalculation fee_calc;
|
2020-12-13 01:37:40 +01:00
|
|
|
int change_pos;
|
|
|
|
|
2022-05-24 12:29:51 -03:00
|
|
|
CreatedTransactionResult(CTransactionRef _tx, CAmount _fee, int _change_pos, const FeeCalculation& _fee_calc)
|
|
|
|
: tx(_tx), fee(_fee), fee_calc(_fee_calc), change_pos(_change_pos) {}
|
2020-12-13 01:37:40 +01:00
|
|
|
};
|
|
|
|
|
2021-02-12 18:01:22 -05:00
|
|
|
/**
|
|
|
|
* Create a new transaction paying the recipients with a set of coins
|
|
|
|
* selected by SelectCoins(); Also create the change output, when needed
|
2020-12-13 03:15:40 +01:00
|
|
|
* @note passing change_pos as -1 will result in setting a random position
|
2021-02-12 18:01:22 -05:00
|
|
|
*/
|
2022-07-21 08:30:39 -04:00
|
|
|
util::Result<CreatedTransactionResult> CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, int change_pos, const CCoinControl& coin_control, bool sign = true);
|
2021-02-12 18:01:22 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Insert additional inputs into the transaction by
|
|
|
|
* calling CreateTransaction();
|
|
|
|
*/
|
|
|
|
bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl);
|
2021-11-12 11:13:29 -05:00
|
|
|
} // namespace wallet
|
2021-02-12 18:01:22 -05:00
|
|
|
|
2021-02-10 16:06:01 -05:00
|
|
|
#endif // BITCOIN_WALLET_SPEND_H
|