mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-10 10:52:31 -05:00
![MacroFake](/assets/img/avatar_default.png)
111ea3ab71
wallet: refactor GetNewDestination, use BResult (furszy)22351725bc
send: refactor CreateTransaction flow to return a BResult<CTransactionRef> (furszy)198fcca162
wallet: refactor, include 'FeeCalculation' inside 'CreatedTransactionResult' (furszy)7a45c33d1f
Introduce generic 'Result' class (furszy) Pull request description: Based on a common function signature pattern that we have all around the sources: ```cpp bool doSomething(arg1, arg2, arg3, arg4, &result_obj, &error_string) { // do something... if (error) { error_string = "something bad happened"; return false; } result = goodResult; return true; } ``` Introduced a generic class `BResult` that encapsulate the function boolean result, the result object (in case of having it) and, in case of failure, the string error reason. Obtaining in this way cleaner function signatures and removing boilerplate code: ```cpp BResult<Obj> doSomething(arg1, arg2, arg3, arg4) { // do something... if (error) return "something bad happened"; return goodResult; } ``` Same cleanup applies equally to the function callers' side as well. There is no longer need to add the error string and the result object declarations before calling the function: Before: ```cpp Obj result_obj; std::string error_string; if (!doSomething(arg1, arg2, arg3, arg4, result_obj, error_string)) { LogPrintf("Error: %s", error_string); } return result_obj; ``` Now: ```cpp BResult<Obj> op_res = doSomething(arg1, arg2, arg3, arg4); if (!op_res) { LogPrintf("Error: %s", op_res.GetError()); } return op_res.GetObjResult(); ``` ### Initial Implementation: Have connected this new concept to two different flows for now: 1) The `CreateTransaction` flow. --> 7ba2b87c 2) The `GetNewDestination` flow. --> bcee0912 Happy note: even when introduced a new class into the sources, the amount of lines removed is almost equal to added ones :). Extra note: this work is an extended version (and a decoupling) of the work that is inside #24845 (which does not contain the `GetNewDestination` changes nor the inclusion of the `FeeCalculation` field inside `CreatedTransactionResult`). ACKs for top commit: achow101: ACK111ea3ab71
w0xlt: reACK111ea3ab71
theStack: re-ACK111ea3ab71
MarcoFalke: review ACK111ea3ab71
🎏 Tree-SHA512: 6d84d901a4cb923727067f25ff64542a40edd1ea84fdeac092312ac684c34e3688a52ac5eb012717d2b73f4cb742b9d78e458eb0e9cb9d6d72a916395be91f69
126 lines
6.8 KiB
C++
126 lines
6.8 KiB
C++
// Copyright (c) 2021 The Bitcoin Core developers
|
|
// 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
|
|
|
|
#include <consensus/amount.h>
|
|
#include <policy/fees.h> // for FeeCalculation
|
|
#include <util/result.h>
|
|
#include <wallet/coinselection.h>
|
|
#include <wallet/transaction.h>
|
|
#include <wallet/wallet.h>
|
|
|
|
#include <optional>
|
|
|
|
namespace wallet {
|
|
/** Get the marginal bytes if spending the specified output from this transaction.
|
|
* 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);
|
|
struct TxSize {
|
|
int64_t vsize{-1};
|
|
int64_t weight{-1};
|
|
};
|
|
|
|
/** Calculate the size of the transaction using CoinControl to determine
|
|
* whether to expect signature grinding when calculating the size of the input spend. */
|
|
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);
|
|
|
|
struct CoinsResult {
|
|
std::vector<COutput> coins;
|
|
// Sum of all the coins amounts
|
|
CAmount total_amount{0};
|
|
};
|
|
/**
|
|
* Return vector of available COutputs.
|
|
* By default, returns only the spendable coins.
|
|
*/
|
|
CoinsResult AvailableCoins(const CWallet& wallet,
|
|
const CCoinControl* coinControl = nullptr,
|
|
std::optional<CFeeRate> 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) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
|
|
|
/**
|
|
* Wrapper function for AvailableCoins which skips the `feerate` parameter. 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) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
|
|
|
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);
|
|
const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
|
|
|
/**
|
|
* 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);
|
|
|
|
/**
|
|
* 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] coins The vector of coins 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
|
|
* If failed, a nullopt
|
|
*/
|
|
std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins,
|
|
const CoinSelectionParams& coin_selection_params);
|
|
|
|
/**
|
|
* Select a set of coins such that nTargetValue is met and at least
|
|
* all coins from coin_control are selected; never select unconfirmed coins if they are not ours
|
|
* param@[in] wallet The wallet which provides data necessary to spend the selected coins
|
|
* param@[in] vAvailableCoins The vector of coins available to be spent
|
|
* 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
|
|
* If failed, a nullopt.
|
|
*/
|
|
std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, const CCoinControl& coin_control,
|
|
const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
|
|
|
struct CreatedTransactionResult
|
|
{
|
|
CTransactionRef tx;
|
|
CAmount fee;
|
|
FeeCalculation fee_calc;
|
|
int change_pos;
|
|
|
|
CreatedTransactionResult(CTransactionRef _tx, CAmount _fee, int _change_pos, const FeeCalculation& _fee_calc)
|
|
: tx(_tx), fee(_fee), fee_calc(_fee_calc), change_pos(_change_pos) {}
|
|
};
|
|
|
|
/**
|
|
* Create a new transaction paying the recipients with a set of coins
|
|
* selected by SelectCoins(); Also create the change output, when needed
|
|
* @note passing change_pos as -1 will result in setting a random position
|
|
*/
|
|
BResult<CreatedTransactionResult> CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, int change_pos, const CCoinControl& coin_control, bool sign = true);
|
|
|
|
/**
|
|
* 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);
|
|
} // namespace wallet
|
|
|
|
#endif // BITCOIN_WALLET_SPEND_H
|