2021-02-10 18:06:01 -03:00
// 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.
2021-09-10 23:29:00 -03:00
# include <consensus/amount.h>
2021-02-10 18:06:01 -03:00
# include <consensus/validation.h>
# include <interfaces/chain.h>
# include <policy/policy.h>
2019-10-18 18:17:17 -03:00
# include <script/signingprovider.h>
2021-02-10 18:06:01 -03:00
# include <util/check.h>
# include <util/fees.h>
# include <util/moneystr.h>
# include <util/rbf.h>
# include <util/translation.h>
# include <wallet/coincontrol.h>
# include <wallet/fees.h>
# include <wallet/receive.h>
# include <wallet/spend.h>
# include <wallet/transaction.h>
# include <wallet/wallet.h>
using interfaces : : FoundBlock ;
static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES { 100 } ;
2021-02-12 20:01:22 -03:00
int GetTxSpendSize ( const CWallet & wallet , const CWalletTx & wtx , unsigned int out , bool use_max_sig )
{
return CalculateMaximumSignedInputSize ( wtx . tx - > vout [ out ] , & wallet , use_max_sig ) ;
}
2021-02-10 18:06:01 -03:00
std : : string COutput : : ToString ( ) const
{
return strprintf ( " COutput(%s, %d, %d) [ % s ] " , tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue)) ;
}
2019-10-18 18:17:17 -03:00
int CalculateMaximumSignedInputSize ( const CTxOut & txout , const SigningProvider * provider , bool use_max_sig )
2021-02-10 18:06:01 -03:00
{
CMutableTransaction txn ;
txn . vin . push_back ( CTxIn ( COutPoint ( ) ) ) ;
2019-10-18 18:17:17 -03:00
if ( ! provider | | ! DummySignInput ( * provider , txn . vin [ 0 ] , txout , use_max_sig ) ) {
2021-02-10 18:06:01 -03:00
return - 1 ;
}
return GetVirtualTransactionInputSize ( txn . vin [ 0 ] ) ;
}
2019-10-18 18:17:17 -03:00
int CalculateMaximumSignedInputSize ( const CTxOut & txout , const CWallet * wallet , bool use_max_sig )
{
const std : : unique_ptr < SigningProvider > provider = wallet - > GetSolvingProvider ( txout . scriptPubKey ) ;
return CalculateMaximumSignedInputSize ( txout , provider . get ( ) , use_max_sig ) ;
}
2021-02-10 18:06:01 -03:00
// txouts needs to be in the order of tx.vin
2019-10-18 18:17:17 -03:00
TxSize CalculateMaximumSignedTxSize ( const CTransaction & tx , const CWallet * wallet , const std : : vector < CTxOut > & txouts , const CCoinControl * coin_control )
2021-02-10 18:06:01 -03:00
{
CMutableTransaction txNew ( tx ) ;
2019-10-18 18:17:17 -03:00
if ( ! wallet - > DummySignTx ( txNew , txouts , coin_control ) ) {
2021-02-10 18:06:01 -03:00
return TxSize { - 1 , - 1 } ;
}
CTransaction ctx ( txNew ) ;
int64_t vsize = GetVirtualTransactionSize ( ctx ) ;
int64_t weight = GetTransactionWeight ( ctx ) ;
return TxSize { vsize , weight } ;
}
2019-10-18 18:17:17 -03:00
TxSize CalculateMaximumSignedTxSize ( const CTransaction & tx , const CWallet * wallet , const CCoinControl * coin_control )
2021-02-10 18:06:01 -03:00
{
std : : vector < CTxOut > txouts ;
2019-10-18 18:17:17 -03:00
// Look up the inputs. The inputs are either in the wallet, or in coin_control.
2021-02-10 18:06:01 -03:00
for ( const CTxIn & input : tx . vin ) {
const auto mi = wallet - > mapWallet . find ( input . prevout . hash ) ;
// Can not estimate size without knowing the input details
2019-10-18 18:17:17 -03:00
if ( mi ! = wallet - > mapWallet . end ( ) ) {
assert ( input . prevout . n < mi - > second . tx - > vout . size ( ) ) ;
txouts . emplace_back ( mi - > second . tx - > vout . at ( input . prevout . n ) ) ;
} else if ( coin_control ) {
CTxOut txout ;
if ( ! coin_control - > GetExternalOutput ( input . prevout , txout ) ) {
return TxSize { - 1 , - 1 } ;
}
txouts . emplace_back ( txout ) ;
} else {
2021-02-10 18:06:01 -03:00
return TxSize { - 1 , - 1 } ;
}
}
2019-10-18 18:17:17 -03:00
return CalculateMaximumSignedTxSize ( tx , wallet , txouts , coin_control ) ;
2021-02-10 18:06:01 -03:00
}
2021-02-12 20:01:22 -03:00
void AvailableCoins ( const CWallet & wallet , std : : vector < COutput > & vCoins , const CCoinControl * coinControl , const CAmount & nMinimumAmount , const CAmount & nMaximumAmount , const CAmount & nMinimumSumAmount , const uint64_t nMaximumCount )
2021-02-10 18:06:01 -03:00
{
2021-02-12 20:01:22 -03:00
AssertLockHeld ( wallet . cs_wallet ) ;
2021-02-10 18:06:01 -03:00
vCoins . clear ( ) ;
CAmount nTotal = 0 ;
// Either the WALLET_FLAG_AVOID_REUSE flag is not set (in which case we always allow), or we default to avoiding, and only in the case where
// a coin control object is provided, and has the avoid address reuse flag set to false, do we allow already used addresses
2021-02-12 20:01:22 -03:00
bool allow_used_addresses = ! wallet . IsWalletFlagSet ( WALLET_FLAG_AVOID_REUSE ) | | ( coinControl & & ! coinControl - > m_avoid_address_reuse ) ;
2021-02-10 18:06:01 -03:00
const int min_depth = { coinControl ? coinControl - > m_min_depth : DEFAULT_MIN_DEPTH } ;
const int max_depth = { coinControl ? coinControl - > m_max_depth : DEFAULT_MAX_DEPTH } ;
const bool only_safe = { coinControl ? ! coinControl - > m_include_unsafe_inputs : true } ;
std : : set < uint256 > trusted_parents ;
2021-02-12 20:01:22 -03:00
for ( const auto & entry : wallet . mapWallet )
2021-02-10 18:06:01 -03:00
{
const uint256 & wtxid = entry . first ;
const CWalletTx & wtx = entry . second ;
2021-02-12 20:01:22 -03:00
if ( ! wallet . chain ( ) . checkFinalTx ( * wtx . tx ) ) {
2021-02-10 18:06:01 -03:00
continue ;
}
2021-02-12 20:01:22 -03:00
if ( wallet . IsTxImmatureCoinBase ( wtx ) )
2021-02-10 18:06:01 -03:00
continue ;
2021-02-12 20:01:22 -03:00
int nDepth = wallet . GetTxDepthInMainChain ( wtx ) ;
2021-02-10 18:06:01 -03:00
if ( nDepth < 0 )
continue ;
// We should not consider coins which aren't at least in our mempool
// It's possible for these to be conflicted via ancestors which we may never be able to detect
if ( nDepth = = 0 & & ! wtx . InMempool ( ) )
continue ;
2021-02-12 20:01:22 -03:00
bool safeTx = CachedTxIsTrusted ( wallet , wtx , trusted_parents ) ;
2021-02-10 18:06:01 -03:00
// We should not consider coins from transactions that are replacing
// other transactions.
//
// Example: There is a transaction A which is replaced by bumpfee
// transaction B. In this case, we want to prevent creation of
// a transaction B' which spends an output of B.
//
// Reason: If transaction A were initially confirmed, transactions B
// and B' would no longer be valid, so the user would have to create
// a new transaction C to replace B'. However, in the case of a
// one-block reorg, transactions B' and C might BOTH be accepted,
// when the user only wanted one of them. Specifically, there could
// be a 1-block reorg away from the chain where transactions A and C
// were accepted to another chain where B, B', and C were all
// accepted.
if ( nDepth = = 0 & & wtx . mapValue . count ( " replaces_txid " ) ) {
safeTx = false ;
}
// Similarly, we should not consider coins from transactions that
// have been replaced. In the example above, we would want to prevent
// creation of a transaction A' spending an output of A, because if
// transaction B were initially confirmed, conflicting with A and
// A', we wouldn't want to the user to create a transaction D
// intending to replace A', but potentially resulting in a scenario
// where A, A', and D could all be accepted (instead of just B and
// D, or just A and A' like the user would want).
if ( nDepth = = 0 & & wtx . mapValue . count ( " replaced_by_txid " ) ) {
safeTx = false ;
}
if ( only_safe & & ! safeTx ) {
continue ;
}
if ( nDepth < min_depth | | nDepth > max_depth ) {
continue ;
}
for ( unsigned int i = 0 ; i < wtx . tx - > vout . size ( ) ; i + + ) {
// Only consider selected coins if add_inputs is false
if ( coinControl & & ! coinControl - > m_add_inputs & & ! coinControl - > IsSelected ( COutPoint ( entry . first , i ) ) ) {
continue ;
}
if ( wtx . tx - > vout [ i ] . nValue < nMinimumAmount | | wtx . tx - > vout [ i ] . nValue > nMaximumAmount )
continue ;
if ( coinControl & & coinControl - > HasSelected ( ) & & ! coinControl - > fAllowOtherInputs & & ! coinControl - > IsSelected ( COutPoint ( entry . first , i ) ) )
continue ;
2021-02-12 20:01:22 -03:00
if ( wallet . IsLockedCoin ( entry . first , i ) )
2021-02-10 18:06:01 -03:00
continue ;
2021-02-12 20:01:22 -03:00
if ( wallet . IsSpent ( wtxid , i ) )
2021-02-10 18:06:01 -03:00
continue ;
2021-02-12 20:01:22 -03:00
isminetype mine = wallet . IsMine ( wtx . tx - > vout [ i ] ) ;
2021-02-10 18:06:01 -03:00
if ( mine = = ISMINE_NO ) {
continue ;
}
2021-02-12 20:01:22 -03:00
if ( ! allow_used_addresses & & wallet . IsSpentKey ( wtxid , i ) ) {
2021-02-10 18:06:01 -03:00
continue ;
}
2021-02-12 20:01:22 -03:00
std : : unique_ptr < SigningProvider > provider = wallet . GetSolvingProvider ( wtx . tx - > vout [ i ] . scriptPubKey ) ;
2021-02-10 18:06:01 -03:00
bool solvable = provider ? IsSolvable ( * provider , wtx . tx - > vout [ i ] . scriptPubKey ) : false ;
bool spendable = ( ( mine & ISMINE_SPENDABLE ) ! = ISMINE_NO ) | | ( ( ( mine & ISMINE_WATCH_ONLY ) ! = ISMINE_NO ) & & ( coinControl & & coinControl - > fAllowWatchOnly & & solvable ) ) ;
2021-02-12 20:01:22 -03:00
vCoins . push_back ( COutput ( wallet , wtx , i , nDepth , spendable , solvable , safeTx , ( coinControl & & coinControl - > fAllowWatchOnly ) ) ) ;
2021-02-10 18:06:01 -03:00
// Checks the sum amount of all UTXO's.
if ( nMinimumSumAmount ! = MAX_MONEY ) {
nTotal + = wtx . tx - > vout [ i ] . nValue ;
if ( nTotal > = nMinimumSumAmount ) {
return ;
}
}
// Checks the maximum number of UTXO's.
if ( nMaximumCount > 0 & & vCoins . size ( ) > = nMaximumCount ) {
return ;
}
}
}
}
2021-02-12 20:01:22 -03:00
CAmount GetAvailableBalance ( const CWallet & wallet , const CCoinControl * coinControl )
2021-02-10 18:06:01 -03:00
{
2021-02-12 20:01:22 -03:00
LOCK ( wallet . cs_wallet ) ;
2021-02-10 18:06:01 -03:00
CAmount balance = 0 ;
std : : vector < COutput > vCoins ;
2021-02-12 20:01:22 -03:00
AvailableCoins ( wallet , vCoins , coinControl ) ;
2021-02-10 18:06:01 -03:00
for ( const COutput & out : vCoins ) {
if ( out . fSpendable ) {
balance + = out . tx - > tx - > vout [ out . i ] . nValue ;
}
}
return balance ;
}
2021-02-12 20:01:22 -03:00
const CTxOut & FindNonChangeParentOutput ( const CWallet & wallet , const CTransaction & tx , int output )
2021-02-10 18:06:01 -03:00
{
2021-02-12 20:01:22 -03:00
AssertLockHeld ( wallet . cs_wallet ) ;
2021-02-10 18:06:01 -03:00
const CTransaction * ptx = & tx ;
int n = output ;
2021-02-12 20:01:22 -03:00
while ( OutputIsChange ( wallet , ptx - > vout [ n ] ) & & ptx - > vin . size ( ) > 0 ) {
2021-02-10 18:06:01 -03:00
const COutPoint & prevout = ptx - > vin [ 0 ] . prevout ;
2021-02-12 20:01:22 -03:00
auto it = wallet . mapWallet . find ( prevout . hash ) ;
if ( it = = wallet . mapWallet . end ( ) | | it - > second . tx - > vout . size ( ) < = prevout . n | |
! wallet . IsMine ( it - > second . tx - > vout [ prevout . n ] ) ) {
2021-02-10 18:06:01 -03:00
break ;
}
ptx = it - > second . tx . get ( ) ;
n = prevout . n ;
}
return ptx - > vout [ n ] ;
}
2021-02-12 20:01:22 -03:00
std : : map < CTxDestination , std : : vector < COutput > > ListCoins ( const CWallet & wallet )
2021-02-10 18:06:01 -03:00
{
2021-02-12 20:01:22 -03:00
AssertLockHeld ( wallet . cs_wallet ) ;
2021-02-10 18:06:01 -03:00
std : : map < CTxDestination , std : : vector < COutput > > result ;
std : : vector < COutput > availableCoins ;
2021-02-12 20:01:22 -03:00
AvailableCoins ( wallet , availableCoins ) ;
2021-02-10 18:06:01 -03:00
for ( const COutput & coin : availableCoins ) {
CTxDestination address ;
2021-02-12 20:01:22 -03:00
if ( ( coin . fSpendable | | ( wallet . IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) & & coin . fSolvable ) ) & &
ExtractDestination ( FindNonChangeParentOutput ( wallet , * coin . tx - > tx , coin . i ) . scriptPubKey , address ) ) {
2021-02-10 18:06:01 -03:00
result [ address ] . emplace_back ( std : : move ( coin ) ) ;
}
}
std : : vector < COutPoint > lockedCoins ;
2021-02-12 20:01:22 -03:00
wallet . ListLockedCoins ( lockedCoins ) ;
2021-02-10 18:06:01 -03:00
// Include watch-only for LegacyScriptPubKeyMan wallets without private keys
2021-02-12 20:01:22 -03:00
const bool include_watch_only = wallet . GetLegacyScriptPubKeyMan ( ) & & wallet . IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ;
2021-02-10 18:06:01 -03:00
const isminetype is_mine_filter = include_watch_only ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE ;
for ( const COutPoint & output : lockedCoins ) {
2021-02-12 20:01:22 -03:00
auto it = wallet . mapWallet . find ( output . hash ) ;
if ( it ! = wallet . mapWallet . end ( ) ) {
int depth = wallet . GetTxDepthInMainChain ( it - > second ) ;
2021-02-10 18:06:01 -03:00
if ( depth > = 0 & & output . n < it - > second . tx - > vout . size ( ) & &
2021-02-12 20:01:22 -03:00
wallet . IsMine ( it - > second . tx - > vout [ output . n ] ) = = is_mine_filter
2021-02-10 18:06:01 -03:00
) {
CTxDestination address ;
2021-02-12 20:01:22 -03:00
if ( ExtractDestination ( FindNonChangeParentOutput ( wallet , * it - > second . tx , output . n ) . scriptPubKey , address ) ) {
2021-02-10 18:06:01 -03:00
result [ address ] . emplace_back (
2021-02-12 20:01:22 -03:00
wallet , it - > second , output . n , depth , true /* spendable */ , true /* solvable */ , false /* safe */ ) ;
2021-02-10 18:06:01 -03:00
}
}
}
}
return result ;
}
2021-02-12 20:01:22 -03:00
std : : vector < OutputGroup > GroupOutputs ( const CWallet & wallet , const std : : vector < COutput > & outputs , const CoinSelectionParams & coin_sel_params , const CoinEligibilityFilter & filter , bool positive_only )
2021-02-10 18:06:01 -03:00
{
std : : vector < OutputGroup > groups_out ;
if ( ! coin_sel_params . m_avoid_partial_spends ) {
// Allowing partial spends means no grouping. Each COutput gets its own OutputGroup.
for ( const COutput & output : outputs ) {
// Skip outputs we cannot spend
if ( ! output . fSpendable ) continue ;
size_t ancestors , descendants ;
2021-02-12 20:01:22 -03:00
wallet . chain ( ) . getTransactionAncestry ( output . tx - > GetHash ( ) , ancestors , descendants ) ;
2021-02-10 18:06:01 -03:00
CInputCoin input_coin = output . GetInputCoin ( ) ;
// Make an OutputGroup containing just this output
OutputGroup group { coin_sel_params } ;
2021-02-12 20:01:22 -03:00
group . Insert ( input_coin , output . nDepth , CachedTxIsFromMe ( wallet , * output . tx , ISMINE_ALL ) , ancestors , descendants , positive_only ) ;
2021-02-10 18:06:01 -03:00
// Check the OutputGroup's eligibility. Only add the eligible ones.
if ( positive_only & & group . GetSelectionAmount ( ) < = 0 ) continue ;
if ( group . m_outputs . size ( ) > 0 & & group . EligibleForSpending ( filter ) ) groups_out . push_back ( group ) ;
}
return groups_out ;
}
// We want to combine COutputs that have the same scriptPubKey into single OutputGroups
// except when there are more than OUTPUT_GROUP_MAX_ENTRIES COutputs grouped in an OutputGroup.
// To do this, we maintain a map where the key is the scriptPubKey and the value is a vector of OutputGroups.
// For each COutput, we check if the scriptPubKey is in the map, and if it is, the COutput's CInputCoin is added
// to the last OutputGroup in the vector for the scriptPubKey. When the last OutputGroup has
// OUTPUT_GROUP_MAX_ENTRIES CInputCoins, a new OutputGroup is added to the end of the vector.
std : : map < CScript , std : : vector < OutputGroup > > spk_to_groups_map ;
for ( const auto & output : outputs ) {
// Skip outputs we cannot spend
if ( ! output . fSpendable ) continue ;
size_t ancestors , descendants ;
2021-02-12 20:01:22 -03:00
wallet . chain ( ) . getTransactionAncestry ( output . tx - > GetHash ( ) , ancestors , descendants ) ;
2021-02-10 18:06:01 -03:00
CInputCoin input_coin = output . GetInputCoin ( ) ;
CScript spk = input_coin . txout . scriptPubKey ;
std : : vector < OutputGroup > & groups = spk_to_groups_map [ spk ] ;
if ( groups . size ( ) = = 0 ) {
// No OutputGroups for this scriptPubKey yet, add one
groups . emplace_back ( coin_sel_params ) ;
}
// Get the last OutputGroup in the vector so that we can add the CInputCoin to it
// A pointer is used here so that group can be reassigned later if it is full.
OutputGroup * group = & groups . back ( ) ;
// Check if this OutputGroup is full. We limit to OUTPUT_GROUP_MAX_ENTRIES when using -avoidpartialspends
// to avoid surprising users with very high fees.
if ( group - > m_outputs . size ( ) > = OUTPUT_GROUP_MAX_ENTRIES ) {
// The last output group is full, add a new group to the vector and use that group for the insertion
groups . emplace_back ( coin_sel_params ) ;
group = & groups . back ( ) ;
}
// Add the input_coin to group
2021-02-12 20:01:22 -03:00
group - > Insert ( input_coin , output . nDepth , CachedTxIsFromMe ( wallet , * output . tx , ISMINE_ALL ) , ancestors , descendants , positive_only ) ;
2021-02-10 18:06:01 -03:00
}
// Now we go through the entire map and pull out the OutputGroups
for ( const auto & spk_and_groups_pair : spk_to_groups_map ) {
const std : : vector < OutputGroup > & groups_per_spk = spk_and_groups_pair . second ;
// Go through the vector backwards. This allows for the first item we deal with being the partial group.
for ( auto group_it = groups_per_spk . rbegin ( ) ; group_it ! = groups_per_spk . rend ( ) ; group_it + + ) {
const OutputGroup & group = * group_it ;
// Don't include partial groups if there are full groups too and we don't want partial groups
if ( group_it = = groups_per_spk . rbegin ( ) & & groups_per_spk . size ( ) > 1 & & ! filter . m_include_partial_groups ) {
continue ;
}
// Check the OutputGroup's eligibility. Only add the eligible ones.
if ( positive_only & & group . GetSelectionAmount ( ) < = 0 ) continue ;
if ( group . m_outputs . size ( ) > 0 & & group . EligibleForSpending ( filter ) ) groups_out . push_back ( group ) ;
}
}
return groups_out ;
}
2021-02-12 20:01:22 -03:00
bool AttemptSelection ( const CWallet & wallet , const CAmount & nTargetValue , const CoinEligibilityFilter & eligibility_filter , std : : vector < COutput > coins ,
std : : set < CInputCoin > & setCoinsRet , CAmount & nValueRet , const CoinSelectionParams & coin_selection_params )
2021-02-10 18:06:01 -03:00
{
setCoinsRet . clear ( ) ;
nValueRet = 0 ;
2021-05-20 19:52:18 -04:00
// Vector of results for use with waste calculation
// In order: calculated waste, selected inputs, selected input value (sum of input values)
// TODO: Use a struct representing the selection result
std : : vector < std : : tuple < CAmount , std : : set < CInputCoin > , CAmount > > results ;
2021-02-10 18:06:01 -03:00
// Note that unlike KnapsackSolver, we do not include the fee for creating a change output as BnB will not create a change output.
2021-02-12 20:01:22 -03:00
std : : vector < OutputGroup > positive_groups = GroupOutputs ( wallet , coins , coin_selection_params , eligibility_filter , true /* positive_only */ ) ;
2021-05-20 19:52:18 -04:00
std : : set < CInputCoin > bnb_coins ;
CAmount bnb_value ;
if ( SelectCoinsBnB ( positive_groups , nTargetValue , coin_selection_params . m_cost_of_change , bnb_coins , bnb_value ) ) {
const auto waste = GetSelectionWaste ( bnb_coins , /* cost of change */ CAmount ( 0 ) , nTargetValue , ! coin_selection_params . m_subtract_fee_outputs ) ;
results . emplace_back ( std : : make_tuple ( waste , std : : move ( bnb_coins ) , bnb_value ) ) ;
2021-02-10 18:06:01 -03:00
}
2021-05-20 19:52:18 -04:00
2021-02-10 18:06:01 -03:00
// 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.
2021-02-12 20:01:22 -03:00
std : : vector < OutputGroup > all_groups = GroupOutputs ( wallet , coins , coin_selection_params , eligibility_filter , false /* positive_only */ ) ;
2021-02-10 18:06:01 -03:00
// While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output.
// So we need to include that for KnapsackSolver as well, as we are expecting to create a change output.
2021-05-20 19:52:18 -04:00
std : : set < CInputCoin > knapsack_coins ;
CAmount knapsack_value ;
if ( KnapsackSolver ( nTargetValue + coin_selection_params . m_change_fee , all_groups , knapsack_coins , knapsack_value ) ) {
const auto waste = GetSelectionWaste ( knapsack_coins , coin_selection_params . m_cost_of_change , nTargetValue + coin_selection_params . m_change_fee , ! coin_selection_params . m_subtract_fee_outputs ) ;
results . emplace_back ( std : : make_tuple ( waste , std : : move ( knapsack_coins ) , knapsack_value ) ) ;
}
2021-05-20 20:20:49 -04:00
// We include the minimum final change for SRD as we do want to avoid making really small change.
// KnapsackSolver does not need this because it includes MIN_CHANGE internally.
const CAmount srd_target = nTargetValue + coin_selection_params . m_change_fee + MIN_FINAL_CHANGE ;
auto srd_result = SelectCoinsSRD ( positive_groups , srd_target ) ;
if ( srd_result ! = std : : nullopt ) {
const auto waste = GetSelectionWaste ( srd_result - > first , coin_selection_params . m_cost_of_change , srd_target , ! coin_selection_params . m_subtract_fee_outputs ) ;
results . emplace_back ( std : : make_tuple ( waste , std : : move ( srd_result - > first ) , srd_result - > second ) ) ;
}
2021-05-20 19:52:18 -04:00
if ( results . size ( ) = = 0 ) {
// No solution found
return false ;
}
// Choose the result with the least waste
// If the waste is the same, choose the one which spends more inputs.
const auto & best_result = std : : min_element ( results . begin ( ) , results . end ( ) , [ ] ( const auto & a , const auto & b ) {
return std : : get < 0 > ( a ) < std : : get < 0 > ( b ) | | ( std : : get < 0 > ( a ) = = std : : get < 0 > ( b ) & & std : : get < 1 > ( a ) . size ( ) > std : : get < 1 > ( b ) . size ( ) ) ;
} ) ;
setCoinsRet = std : : get < 1 > ( * best_result ) ;
nValueRet = std : : get < 2 > ( * best_result ) ;
return true ;
2021-02-10 18:06:01 -03:00
}
2021-02-12 20:01:22 -03:00
bool SelectCoins ( const CWallet & wallet , const std : : vector < COutput > & vAvailableCoins , const CAmount & nTargetValue , std : : set < CInputCoin > & setCoinsRet , CAmount & nValueRet , const CCoinControl & coin_control , CoinSelectionParams & coin_selection_params )
2021-02-10 18:06:01 -03:00
{
std : : vector < COutput > vCoins ( vAvailableCoins ) ;
CAmount value_to_select = nTargetValue ;
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
if ( coin_control . HasSelected ( ) & & ! coin_control . fAllowOtherInputs )
{
for ( const COutput & out : vCoins )
{
if ( ! out . fSpendable )
continue ;
nValueRet + = out . tx - > tx - > vout [ out . i ] . nValue ;
setCoinsRet . insert ( out . GetInputCoin ( ) ) ;
}
return ( nValueRet > = nTargetValue ) ;
}
// calculate value from preset inputs and store them
std : : set < CInputCoin > setPresetCoins ;
CAmount nValueFromPresetInputs = 0 ;
std : : vector < COutPoint > vPresetInputs ;
coin_control . ListSelected ( vPresetInputs ) ;
2019-10-18 18:17:17 -03:00
for ( const COutPoint & outpoint : vPresetInputs ) {
int input_bytes = - 1 ;
CTxOut txout ;
2021-02-12 20:01:22 -03:00
std : : map < uint256 , CWalletTx > : : const_iterator it = wallet . mapWallet . find ( outpoint . hash ) ;
2019-10-18 18:17:17 -03:00
if ( it ! = wallet . mapWallet . end ( ) ) {
2021-02-10 18:06:01 -03:00
const CWalletTx & wtx = it - > second ;
// Clearly invalid input, fail
if ( wtx . tx - > vout . size ( ) < = outpoint . n ) {
return false ;
}
2019-10-18 18:17:17 -03:00
input_bytes = GetTxSpendSize ( wallet , wtx , outpoint . n , false ) ;
txout = wtx . tx - > vout . at ( outpoint . n ) ;
}
if ( input_bytes = = - 1 ) {
// The input is external. We either did not find the tx in mapWallet, or we did but couldn't compute the input size with wallet data
if ( ! coin_control . GetExternalOutput ( outpoint , txout ) ) {
// Not ours, and we don't have solving data.
return false ;
2021-02-10 18:06:01 -03:00
}
2019-10-18 18:17:17 -03:00
input_bytes = CalculateMaximumSignedInputSize ( txout , & coin_control . m_external_provider , /* use_max_sig */ true ) ;
}
CInputCoin coin ( outpoint , txout , input_bytes ) ;
nValueFromPresetInputs + = coin . txout . nValue ;
if ( coin . m_input_bytes < = 0 ) {
return false ; // Not solvable, can't estimate size for fee
}
coin . effective_value = coin . txout . nValue - coin_selection_params . m_effective_feerate . GetFee ( coin . m_input_bytes ) ;
if ( coin_selection_params . m_subtract_fee_outputs ) {
value_to_select - = coin . txout . nValue ;
2021-02-10 18:06:01 -03:00
} else {
2019-10-18 18:17:17 -03:00
value_to_select - = coin . effective_value ;
2021-02-10 18:06:01 -03:00
}
2019-10-18 18:17:17 -03:00
setPresetCoins . insert ( coin ) ;
2021-02-10 18:06:01 -03:00
}
// remove preset inputs from vCoins so that Coin Selection doesn't pick them.
for ( std : : vector < COutput > : : iterator it = vCoins . begin ( ) ; it ! = vCoins . end ( ) & & coin_control . HasSelected ( ) ; )
{
if ( setPresetCoins . count ( it - > GetInputCoin ( ) ) )
it = vCoins . erase ( it ) ;
else
+ + it ;
}
unsigned int limit_ancestor_count = 0 ;
unsigned int limit_descendant_count = 0 ;
2021-02-12 20:01:22 -03:00
wallet . chain ( ) . getPackageLimits ( limit_ancestor_count , limit_descendant_count ) ;
2021-02-10 18:06:01 -03:00
const size_t max_ancestors = ( size_t ) std : : max < int64_t > ( 1 , limit_ancestor_count ) ;
const size_t max_descendants = ( size_t ) std : : max < int64_t > ( 1 , limit_descendant_count ) ;
const bool fRejectLongChains = gArgs . GetBoolArg ( " -walletrejectlongchains " , DEFAULT_WALLET_REJECT_LONG_CHAINS ) ;
// form groups from remaining coins; note that preset coins will not
// automatically have their associated (same address) coins included
if ( coin_control . m_avoid_partial_spends & & vCoins . size ( ) > OUTPUT_GROUP_MAX_ENTRIES ) {
// Cases where we have 101+ outputs all pointing to the same destination may result in
// privacy leaks as they will potentially be deterministically sorted. We solve that by
// explicitly shuffling the outputs before processing
Shuffle ( vCoins . begin ( ) , vCoins . end ( ) , FastRandomContext ( ) ) ;
}
// 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.
const bool res = [ & ] {
// Pre-selected inputs already cover the target amount.
if ( value_to_select < = 0 ) return true ;
// If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
// confirmations on outputs received from other wallets and only spend confirmed change.
2021-02-12 20:01:22 -03:00
if ( AttemptSelection ( wallet , value_to_select , CoinEligibilityFilter ( 1 , 6 , 0 ) , vCoins , setCoinsRet , nValueRet , coin_selection_params ) ) return true ;
if ( AttemptSelection ( wallet , value_to_select , CoinEligibilityFilter ( 1 , 1 , 0 ) , vCoins , setCoinsRet , nValueRet , coin_selection_params ) ) return true ;
2021-02-10 18:06:01 -03:00
// Fall back to using zero confirmation change (but with as few ancestors in the mempool as
// possible) if we cannot fund the transaction otherwise.
2021-02-12 20:01:22 -03:00
if ( wallet . m_spend_zero_conf_change ) {
if ( AttemptSelection ( wallet , value_to_select , CoinEligibilityFilter ( 0 , 1 , 2 ) , vCoins , setCoinsRet , nValueRet , coin_selection_params ) ) return true ;
if ( AttemptSelection ( wallet , value_to_select , CoinEligibilityFilter ( 0 , 1 , std : : min ( ( size_t ) 4 , max_ancestors / 3 ) , std : : min ( ( size_t ) 4 , max_descendants / 3 ) ) ,
2021-02-10 18:06:01 -03:00
vCoins , setCoinsRet , nValueRet , coin_selection_params ) ) {
return true ;
}
2021-02-12 20:01:22 -03:00
if ( AttemptSelection ( wallet , value_to_select , CoinEligibilityFilter ( 0 , 1 , max_ancestors / 2 , max_descendants / 2 ) ,
2021-02-10 18:06:01 -03:00
vCoins , setCoinsRet , nValueRet , coin_selection_params ) ) {
return true ;
}
// If partial groups are allowed, relax the requirement of spending OutputGroups (groups
// of UTXOs sent to the same address, which are obviously controlled by a single wallet)
// in their entirety.
2021-02-12 20:01:22 -03:00
if ( AttemptSelection ( wallet , value_to_select , CoinEligibilityFilter ( 0 , 1 , max_ancestors - 1 , max_descendants - 1 , true /* include_partial_groups */ ) ,
2021-02-10 18:06:01 -03:00
vCoins , setCoinsRet , nValueRet , coin_selection_params ) ) {
return true ;
}
// Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
// received from other wallets.
if ( coin_control . m_include_unsafe_inputs
2021-02-12 20:01:22 -03:00
& & AttemptSelection ( wallet , value_to_select ,
2021-02-10 18:06:01 -03:00
CoinEligibilityFilter ( 0 /* conf_mine */ , 0 /* conf_theirs */ , max_ancestors - 1 , max_descendants - 1 , true /* include_partial_groups */ ) ,
vCoins , setCoinsRet , nValueRet , coin_selection_params ) ) {
return true ;
}
// Try with unlimited ancestors/descendants. The transaction will still need to meet
// mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but
// OutputGroups use heuristics that may overestimate ancestor/descendant counts.
2021-02-12 20:01:22 -03:00
if ( ! fRejectLongChains & & AttemptSelection ( wallet , value_to_select ,
2021-02-10 18:06:01 -03:00
CoinEligibilityFilter ( 0 , 1 , std : : numeric_limits < uint64_t > : : max ( ) , std : : numeric_limits < uint64_t > : : max ( ) , true /* include_partial_groups */ ) ,
vCoins , setCoinsRet , nValueRet , coin_selection_params ) ) {
return true ;
}
}
// Coin Selection failed.
return false ;
} ( ) ;
2021-05-20 15:21:15 -04:00
// AttemptSelection clears setCoinsRet, so add the preset inputs from coin_control to the coinset
2021-02-10 18:06:01 -03:00
util : : insert ( setCoinsRet , setPresetCoins ) ;
// add preset inputs to the total value selected
nValueRet + = nValueFromPresetInputs ;
return res ;
}
static bool IsCurrentForAntiFeeSniping ( interfaces : : Chain & chain , const uint256 & block_hash )
{
if ( chain . isInitialBlockDownload ( ) ) {
return false ;
}
constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60 ; // in seconds
int64_t block_time ;
CHECK_NONFATAL ( chain . findBlock ( block_hash , FoundBlock ( ) . time ( block_time ) ) ) ;
if ( block_time < ( GetTime ( ) - MAX_ANTI_FEE_SNIPING_TIP_AGE ) ) {
return false ;
}
return true ;
}
/**
* Return a height - based locktime for new transactions ( uses the height of the
* current chain tip unless we are not synced with the current chain
*/
static uint32_t GetLocktimeForNewTransaction ( interfaces : : Chain & chain , const uint256 & block_hash , int block_height )
{
uint32_t locktime ;
// Discourage fee sniping.
//
// For a large miner the value of the transactions in the best block and
// the mempool can exceed the cost of deliberately attempting to mine two
// blocks to orphan the current best block. By setting nLockTime such that
// only the next block can include the transaction, we discourage this
// practice as the height restricted and limited blocksize gives miners
// considering fee sniping fewer options for pulling off this attack.
//
// A simple way to think about this is from the wallet's point of view we
// always want the blockchain to move forward. By setting nLockTime this
// way we're basically making the statement that we only want this
// transaction to appear in the next block; we don't want to potentially
// encourage reorgs by allowing transactions to appear at lower heights
// than the next block in forks of the best chain.
//
// Of course, the subsidy is high enough, and transaction volume low
// enough, that fee sniping isn't a problem yet, but by implementing a fix
// now we ensure code won't be written that makes assumptions about
// nLockTime that preclude a fix later.
if ( IsCurrentForAntiFeeSniping ( chain , block_hash ) ) {
locktime = block_height ;
// Secondly occasionally randomly pick a nLockTime even further back, so
// that transactions that are delayed after signing for whatever reason,
// e.g. high-latency mix networks and some CoinJoin implementations, have
// better privacy.
if ( GetRandInt ( 10 ) = = 0 )
locktime = std : : max ( 0 , ( int ) locktime - GetRandInt ( 100 ) ) ;
} else {
// If our chain is lagging behind, we can't discourage fee sniping nor help
// the privacy of high-latency transactions. To avoid leaking a potentially
// unique "nLockTime fingerprint", set nLockTime to a constant.
locktime = 0 ;
}
assert ( locktime < LOCKTIME_THRESHOLD ) ;
return locktime ;
}
2021-02-12 20:01:22 -03:00
static bool CreateTransactionInternal (
CWallet & wallet ,
2021-02-10 18:06:01 -03:00
const std : : vector < CRecipient > & vecSend ,
CTransactionRef & tx ,
CAmount & nFeeRet ,
int & nChangePosInOut ,
bilingual_str & error ,
const CCoinControl & coin_control ,
FeeCalculation & fee_calc_out ,
2021-02-12 20:01:22 -03:00
bool sign ) EXCLUSIVE_LOCKS_REQUIRED ( wallet . cs_wallet )
2021-02-10 18:06:01 -03:00
{
2021-02-12 20:01:22 -03:00
AssertLockHeld ( wallet . cs_wallet ) ;
2021-05-20 14:51:50 -04:00
2021-05-17 16:26:40 -04:00
CMutableTransaction txNew ; // The resulting transaction that we make
2021-02-12 20:01:22 -03:00
txNew . nLockTime = GetLocktimeForNewTransaction ( wallet . chain ( ) , wallet . GetLastBlockHash ( ) , wallet . GetLastBlockHeight ( ) ) ;
2021-05-17 16:26:40 -04:00
CoinSelectionParams coin_selection_params ; // Parameters for coin selection, init with dummy
coin_selection_params . m_avoid_partial_spends = coin_control . m_avoid_partial_spends ;
2021-05-20 16:54:23 -04:00
// Set the long term feerate estimate to the wallet's consolidate feerate
2021-02-12 20:01:22 -03:00
coin_selection_params . m_long_term_feerate = wallet . m_consolidate_feerate ;
2021-05-20 16:54:23 -04:00
2021-05-17 16:20:40 -04:00
CAmount recipients_sum = 0 ;
2021-02-12 20:01:22 -03:00
const OutputType change_type = wallet . TransactionChangeType ( coin_control . m_change_type ? * coin_control . m_change_type : wallet . m_default_change_type , vecSend ) ;
ReserveDestination reservedest ( & wallet , change_type ) ;
2021-05-17 16:22:30 -04:00
unsigned int outputs_to_subtract_fee_from = 0 ; // The number of outputs which we are subtracting the fee from
2021-05-17 16:29:31 -04:00
for ( const auto & recipient : vecSend ) {
2021-05-17 16:20:40 -04:00
recipients_sum + = recipient . nAmount ;
2021-02-10 18:06:01 -03:00
2021-05-17 16:29:31 -04:00
if ( recipient . fSubtractFeeFromAmount ) {
2021-05-17 16:22:30 -04:00
outputs_to_subtract_fee_from + + ;
2021-05-17 16:29:31 -04:00
coin_selection_params . m_subtract_fee_outputs = true ;
}
2021-02-10 18:06:01 -03:00
}
2021-05-20 14:53:36 -04:00
// Create change script that will be used if we need change
// TODO: pass in scriptChange instead of reservedest so
// change transaction isn't always pay-to-bitcoin-address
CScript scriptChange ;
// coin control: send change to custom address
if ( ! std : : get_if < CNoDestination > ( & coin_control . destChange ) ) {
scriptChange = GetScriptForDestination ( coin_control . destChange ) ;
} else { // no coin control: send change to newly generated address
// Note: We use a new key here to keep it from being obvious which side is the change.
// The drawback is that by not reusing a previous key, the change may be lost if a
// backup is restored, if the backup doesn't have the new private key for the change.
// If we reused the old key, it would be possible to add code to look for and
// rediscover unknown transactions that were written with keys of ours to recover
// post-backup change.
// Reserve a new key pair from key pool. If it fails, provide a dummy
// destination in case we don't need change.
CTxDestination dest ;
2021-06-23 16:54:13 -04:00
bilingual_str dest_err ;
2021-06-12 21:36:05 -04:00
if ( ! reservedest . GetReservedDestination ( dest , true , dest_err ) ) {
2021-06-23 16:54:13 -04:00
error = _ ( " Transaction needs a change address, but we can't generate it. " ) + Untranslated ( " " ) + dest_err ;
2021-05-20 14:53:36 -04:00
}
scriptChange = GetScriptForDestination ( dest ) ;
// A valid destination implies a change script (and
// vice-versa). An empty change script will abort later, if the
// change keypool ran out, but change is required.
CHECK_NONFATAL ( IsValidDestination ( dest ) ! = scriptChange . empty ( ) ) ;
}
CTxOut change_prototype_txout ( 0 , scriptChange ) ;
coin_selection_params . change_output_size = GetSerializeSize ( change_prototype_txout ) ;
// Get size of spending the change output
2021-02-12 20:01:22 -03:00
int change_spend_size = CalculateMaximumSignedInputSize ( change_prototype_txout , & wallet ) ;
2021-05-20 14:53:36 -04:00
// If the wallet doesn't know how to sign change output, assume p2sh-p2wpkh
// as lower-bound to allow BnB to do it's thing
if ( change_spend_size = = - 1 ) {
coin_selection_params . change_spend_size = DUMMY_NESTED_P2WPKH_INPUT_SIZE ;
} else {
coin_selection_params . change_spend_size = ( size_t ) change_spend_size ;
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Set discard feerate
2021-02-12 20:01:22 -03:00
coin_selection_params . m_discard_feerate = GetDiscardRate ( wallet ) ;
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Get the fee rate to use effective values in coin selection
2021-05-17 16:26:40 -04:00
FeeCalculation feeCalc ;
2021-02-12 20:01:22 -03:00
coin_selection_params . m_effective_feerate = GetMinimumFeeRate ( wallet , coin_control , & feeCalc ) ;
2021-05-20 14:53:36 -04:00
// Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
// provided one
if ( coin_control . m_feerate & & coin_selection_params . m_effective_feerate > * coin_control . m_feerate ) {
error = strprintf ( _ ( " Fee rate (%s) is lower than the minimum fee rate setting (%s) " ) , coin_control . m_feerate - > ToString ( FeeEstimateMode : : SAT_VB ) , coin_selection_params . m_effective_feerate . ToString ( FeeEstimateMode : : SAT_VB ) ) ;
return false ;
}
2021-02-12 20:01:22 -03:00
if ( feeCalc . reason = = FeeReason : : FALLBACK & & ! wallet . m_allow_fallback_fee ) {
2021-05-20 14:53:36 -04:00
// eventually allow a fallback fee
error = _ ( " Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. " ) ;
return false ;
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Calculate the cost of change
// Cost of change is the cost of creating the change output + cost of spending the change output in the future.
// For creating the change output now, we use the effective feerate.
// For spending the change output in the future, we use the discard feerate for now.
// So cost of change = (change output size * effective feerate) + (size of spending change output * discard feerate)
coin_selection_params . m_change_fee = coin_selection_params . m_effective_feerate . GetFee ( coin_selection_params . change_output_size ) ;
coin_selection_params . m_cost_of_change = coin_selection_params . m_discard_feerate . GetFee ( coin_selection_params . change_spend_size ) + coin_selection_params . m_change_fee ;
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// vouts to the payees
if ( ! coin_selection_params . m_subtract_fee_outputs ) {
coin_selection_params . tx_noinputs_size = 11 ; // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 output count, 1 witness overhead (dummy, flag, stack size)
}
for ( const auto & recipient : vecSend )
{
CTxOut txout ( recipient . nAmount , recipient . scriptPubKey ) ;
// Include the fee cost for outputs.
2021-05-20 14:51:50 -04:00
if ( ! coin_selection_params . m_subtract_fee_outputs ) {
2021-05-20 14:53:36 -04:00
coin_selection_params . tx_noinputs_size + = : : GetSerializeSize ( txout , PROTOCOL_VERSION ) ;
2021-05-20 14:51:50 -04:00
}
2021-05-20 14:53:36 -04:00
2021-02-12 20:01:22 -03:00
if ( IsDust ( txout , wallet . chain ( ) . relayDustFee ( ) ) )
2021-05-20 14:51:50 -04:00
{
2021-05-20 14:53:36 -04:00
error = _ ( " Transaction amount too small " ) ;
return false ;
}
txNew . vout . push_back ( txout ) ;
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Include the fees for things that aren't inputs, excluding the change output
const CAmount not_input_fees = coin_selection_params . m_effective_feerate . GetFee ( coin_selection_params . tx_noinputs_size ) ;
2021-05-17 16:20:40 -04:00
CAmount selection_target = recipients_sum + not_input_fees ;
2021-05-20 14:51:50 -04:00
2021-05-17 16:26:40 -04:00
// Get available coins
std : : vector < COutput > vAvailableCoins ;
2021-02-12 20:01:22 -03:00
AvailableCoins ( wallet , vAvailableCoins , & coin_control , 1 , MAX_MONEY , MAX_MONEY , 0 ) ;
2021-05-17 16:26:40 -04:00
2021-05-20 14:53:36 -04:00
// Choose coins to use
CAmount inputs_sum = 0 ;
2021-05-17 16:26:40 -04:00
std : : set < CInputCoin > setCoins ;
2021-02-12 20:01:22 -03:00
if ( ! SelectCoins ( wallet , vAvailableCoins , /* nTargetValue */ selection_target , setCoins , inputs_sum , coin_control , coin_selection_params ) )
2021-05-20 14:53:36 -04:00
{
error = _ ( " Insufficient funds " ) ;
return false ;
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Always make a change output
// We will reduce the fee from this change output later, and remove the output if it is too small.
2021-05-17 16:20:40 -04:00
const CAmount change_and_fee = inputs_sum - recipients_sum ;
2021-05-20 14:53:36 -04:00
assert ( change_and_fee > = 0 ) ;
CTxOut newTxOut ( change_and_fee , scriptChange ) ;
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
if ( nChangePosInOut = = - 1 )
{
// Insert change txn at random position:
nChangePosInOut = GetRandInt ( txNew . vout . size ( ) + 1 ) ;
}
else if ( ( unsigned int ) nChangePosInOut > txNew . vout . size ( ) )
{
error = _ ( " Change index out of range " ) ;
return false ;
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
assert ( nChangePosInOut ! = - 1 ) ;
auto change_position = txNew . vout . insert ( txNew . vout . begin ( ) + nChangePosInOut , newTxOut ) ;
2021-02-10 18:06:01 -03:00
2021-05-17 16:31:06 -04:00
// Shuffle selected coins and fill in final vin
std : : vector < CInputCoin > selected_coins ( setCoins . begin ( ) , setCoins . end ( ) ) ;
Shuffle ( selected_coins . begin ( ) , selected_coins . end ( ) , FastRandomContext ( ) ) ;
// Note how the sequence number is set to non-maxint so that
// the nLockTime set above actually works.
2021-05-20 14:53:36 -04:00
//
2021-05-17 16:31:06 -04:00
// BIP125 defines opt-in RBF as any nSequence < maxint-1, so
// we use the highest possible value in that range (maxint-2)
// to avoid conflicting with other possible uses of nSequence,
// and in the spirit of "smallest possible change from prior
// behavior."
2021-02-12 20:01:22 -03:00
const uint32_t nSequence = coin_control . m_signal_bip125_rbf . value_or ( wallet . m_signal_rbf ) ? MAX_BIP125_RBF_SEQUENCE : ( CTxIn : : SEQUENCE_FINAL - 1 ) ;
2021-05-17 16:31:06 -04:00
for ( const auto & coin : selected_coins ) {
txNew . vin . push_back ( CTxIn ( coin . outpoint , CScript ( ) , nSequence ) ) ;
2021-05-20 14:53:36 -04:00
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Calculate the transaction fee
2019-10-18 18:17:17 -03:00
TxSize tx_sizes = CalculateMaximumSignedTxSize ( CTransaction ( txNew ) , & wallet , & coin_control ) ;
2021-05-17 16:26:40 -04:00
int nBytes = tx_sizes . vsize ;
2021-05-20 14:53:36 -04:00
if ( nBytes < 0 ) {
2019-10-18 18:17:17 -03:00
error = _ ( " Missing solving data for estimating transaction size " ) ;
2021-05-20 14:53:36 -04:00
return false ;
}
nFeeRet = coin_selection_params . m_effective_feerate . GetFee ( nBytes ) ;
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Subtract fee from the change output if not subtracting it from recipient outputs
CAmount fee_needed = nFeeRet ;
2021-05-17 16:29:31 -04:00
if ( ! coin_selection_params . m_subtract_fee_outputs ) {
2021-05-20 14:53:36 -04:00
change_position - > nValue - = fee_needed ;
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// We want to drop the change to fees if:
// 1. The change output would be dust
// 2. The change is within the (almost) exact match window, i.e. it is less than or equal to the cost of the change output (cost_of_change)
CAmount change_amount = change_position - > nValue ;
if ( IsDust ( * change_position , coin_selection_params . m_discard_feerate ) | | change_amount < = coin_selection_params . m_cost_of_change )
{
nChangePosInOut = - 1 ;
change_amount = 0 ;
txNew . vout . erase ( change_position ) ;
// Because we have dropped this change, the tx size and required fee will be different, so let's recalculate those
2019-10-18 18:17:17 -03:00
tx_sizes = CalculateMaximumSignedTxSize ( CTransaction ( txNew ) , & wallet , & coin_control ) ;
2021-05-20 14:51:50 -04:00
nBytes = tx_sizes . vsize ;
2021-05-20 14:53:36 -04:00
fee_needed = coin_selection_params . m_effective_feerate . GetFee ( nBytes ) ;
}
2021-02-10 18:06:01 -03:00
2021-08-11 22:05:51 -04:00
// The only time that fee_needed should be less than the amount available for fees (in change_and_fee - change_amount) is when
// we are subtracting the fee from the outputs. If this occurs at any other time, it is a bug.
assert ( coin_selection_params . m_subtract_fee_outputs | | fee_needed < = change_and_fee - change_amount ) ;
2021-05-20 14:53:36 -04:00
// Update nFeeRet in case fee_needed changed due to dropping the change output
if ( fee_needed < = change_and_fee - change_amount ) {
nFeeRet = change_and_fee - change_amount ;
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Reduce output values for subtractFeeFromAmount
2021-05-17 16:29:31 -04:00
if ( coin_selection_params . m_subtract_fee_outputs ) {
2021-05-20 14:53:36 -04:00
CAmount to_reduce = fee_needed + change_amount - change_and_fee ;
int i = 0 ;
bool fFirst = true ;
for ( const auto & recipient : vecSend )
2021-05-20 14:51:50 -04:00
{
2021-05-20 14:53:36 -04:00
if ( i = = nChangePosInOut ) {
+ + i ;
}
CTxOut & txout = txNew . vout [ i ] ;
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
if ( recipient . fSubtractFeeFromAmount )
2021-02-10 18:06:01 -03:00
{
2021-05-17 16:22:30 -04:00
txout . nValue - = to_reduce / outputs_to_subtract_fee_from ; // Subtract fee equally from each selected recipient
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
if ( fFirst ) // first receiver pays the remainder not divisible by output count
2021-02-10 18:06:01 -03:00
{
2021-05-20 14:53:36 -04:00
fFirst = false ;
2021-05-17 16:22:30 -04:00
txout . nValue - = to_reduce % outputs_to_subtract_fee_from ;
2021-05-20 14:53:36 -04:00
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Error if this output is reduced to be below dust
2021-02-12 20:01:22 -03:00
if ( IsDust ( txout , wallet . chain ( ) . relayDustFee ( ) ) ) {
2021-05-20 14:53:36 -04:00
if ( txout . nValue < 0 ) {
error = _ ( " The transaction amount is too small to pay the fee " ) ;
} else {
error = _ ( " The transaction amount is too small to send after the fee has been deducted " ) ;
2021-02-10 18:06:01 -03:00
}
2021-05-20 14:53:36 -04:00
return false ;
2021-02-10 18:06:01 -03:00
}
}
2021-05-20 14:53:36 -04:00
+ + i ;
2021-05-20 14:51:50 -04:00
}
2021-05-20 14:53:36 -04:00
nFeeRet = fee_needed ;
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Give up if change keypool ran out and change is required
if ( scriptChange . empty ( ) & & nChangePosInOut ! = - 1 ) {
return false ;
}
2021-02-10 18:06:01 -03:00
2021-02-12 20:01:22 -03:00
if ( sign & & ! wallet . SignTransaction ( txNew ) ) {
2021-05-20 14:53:36 -04:00
error = _ ( " Signing transaction failed " ) ;
return false ;
}
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Return the constructed transaction data.
tx = MakeTransactionRef ( std : : move ( txNew ) ) ;
2021-02-10 18:06:01 -03:00
2021-05-20 14:53:36 -04:00
// Limit size
if ( ( sign & & GetTransactionWeight ( * tx ) > MAX_STANDARD_TX_WEIGHT ) | |
( ! sign & & tx_sizes . weight > MAX_STANDARD_TX_WEIGHT ) )
{
error = _ ( " Transaction too large " ) ;
return false ;
2021-02-10 18:06:01 -03:00
}
2021-02-12 20:01:22 -03:00
if ( nFeeRet > wallet . m_default_max_tx_fee ) {
2021-02-10 18:06:01 -03:00
error = TransactionErrorString ( TransactionError : : MAX_FEE_EXCEEDED ) ;
return false ;
}
if ( gArgs . GetBoolArg ( " -walletrejectlongchains " , DEFAULT_WALLET_REJECT_LONG_CHAINS ) ) {
// Lastly, ensure this tx will pass the mempool's chain limits
2021-02-12 20:01:22 -03:00
if ( ! wallet . chain ( ) . checkChainLimits ( tx ) ) {
2021-02-10 18:06:01 -03:00
error = _ ( " Transaction has too long of a mempool chain " ) ;
return false ;
}
}
// Before we return success, we assume any change key will be used to prevent
// accidental re-use.
reservedest . KeepDestination ( ) ;
fee_calc_out = feeCalc ;
2021-02-12 20:01:22 -03:00
wallet . WalletLogPrintf ( " Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason: \" %s \" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) \n " ,
2021-02-10 18:06:01 -03:00
nFeeRet , nBytes , feeCalc . returnedTarget , feeCalc . desiredTarget , StringForFeeReason ( feeCalc . reason ) , feeCalc . est . decay ,
feeCalc . est . pass . start , feeCalc . est . pass . end ,
( feeCalc . est . pass . totalConfirmed + feeCalc . est . pass . inMempool + feeCalc . est . pass . leftMempool ) > 0.0 ? 100 * feeCalc . est . pass . withinTarget / ( feeCalc . est . pass . totalConfirmed + feeCalc . est . pass . inMempool + feeCalc . est . pass . leftMempool ) : 0.0 ,
feeCalc . est . pass . withinTarget , feeCalc . est . pass . totalConfirmed , feeCalc . est . pass . inMempool , feeCalc . est . pass . leftMempool ,
feeCalc . est . fail . start , feeCalc . est . fail . end ,
( feeCalc . est . fail . totalConfirmed + feeCalc . est . fail . inMempool + feeCalc . est . fail . leftMempool ) > 0.0 ? 100 * feeCalc . est . fail . withinTarget / ( feeCalc . est . fail . totalConfirmed + feeCalc . est . fail . inMempool + feeCalc . est . fail . leftMempool ) : 0.0 ,
feeCalc . est . fail . withinTarget , feeCalc . est . fail . totalConfirmed , feeCalc . est . fail . inMempool , feeCalc . est . fail . leftMempool ) ;
return true ;
}
2021-02-12 20:01:22 -03:00
bool CreateTransaction (
CWallet & wallet ,
2021-02-10 18:06:01 -03:00
const std : : vector < CRecipient > & vecSend ,
CTransactionRef & tx ,
CAmount & nFeeRet ,
int & nChangePosInOut ,
bilingual_str & error ,
const CCoinControl & coin_control ,
FeeCalculation & fee_calc_out ,
bool sign )
{
2021-05-17 16:23:08 -04:00
if ( vecSend . empty ( ) ) {
error = _ ( " Transaction must have at least one recipient " ) ;
return false ;
}
if ( std : : any_of ( vecSend . cbegin ( ) , vecSend . cend ( ) , [ ] ( const auto & recipient ) { return recipient . nAmount < 0 ; } ) ) {
error = _ ( " Transaction amounts must not be negative " ) ;
return false ;
}
2021-02-12 20:01:22 -03:00
LOCK ( wallet . cs_wallet ) ;
2021-05-20 14:51:50 -04:00
2021-02-10 18:06:01 -03:00
int nChangePosIn = nChangePosInOut ;
Assert ( ! tx ) ; // tx is an out-param. TODO change the return type from bool to tx (or nullptr)
2021-02-12 20:01:22 -03:00
bool res = CreateTransactionInternal ( wallet , vecSend , tx , nFeeRet , nChangePosInOut , error , coin_control , fee_calc_out , sign ) ;
2021-02-10 18:06:01 -03:00
// try with avoidpartialspends unless it's enabled already
2021-02-12 20:01:22 -03:00
if ( res & & nFeeRet > 0 /* 0 means non-functional fee rate estimation */ & & wallet . m_max_aps_fee > - 1 & & ! coin_control . m_avoid_partial_spends ) {
2021-02-10 18:06:01 -03:00
CCoinControl tmp_cc = coin_control ;
tmp_cc . m_avoid_partial_spends = true ;
CAmount nFeeRet2 ;
CTransactionRef tx2 ;
int nChangePosInOut2 = nChangePosIn ;
bilingual_str error2 ; // fired and forgotten; if an error occurs, we discard the results
2021-02-12 20:01:22 -03:00
if ( CreateTransactionInternal ( wallet , vecSend , tx2 , nFeeRet2 , nChangePosInOut2 , error2 , tmp_cc , fee_calc_out , sign ) ) {
2021-02-10 18:06:01 -03:00
// if fee of this alternative one is within the range of the max fee, we use this one
2021-02-12 20:01:22 -03:00
const bool use_aps = nFeeRet2 < = nFeeRet + wallet . m_max_aps_fee ;
wallet . WalletLogPrintf ( " Fee non-grouped = %lld, grouped = %lld, using %s \n " , nFeeRet , nFeeRet2 , use_aps ? " grouped " : " non-grouped " ) ;
2021-02-10 18:06:01 -03:00
if ( use_aps ) {
tx = tx2 ;
nFeeRet = nFeeRet2 ;
nChangePosInOut = nChangePosInOut2 ;
}
}
}
return res ;
}
2021-02-12 20:01:22 -03:00
bool FundTransaction ( CWallet & wallet , CMutableTransaction & tx , CAmount & nFeeRet , int & nChangePosInOut , bilingual_str & error , bool lockUnspents , const std : : set < int > & setSubtractFeeFromOutputs , CCoinControl coinControl )
2021-02-10 18:06:01 -03:00
{
std : : vector < CRecipient > vecSend ;
// Turn the txout set into a CRecipient vector.
for ( size_t idx = 0 ; idx < tx . vout . size ( ) ; idx + + ) {
const CTxOut & txOut = tx . vout [ idx ] ;
CRecipient recipient = { txOut . scriptPubKey , txOut . nValue , setSubtractFeeFromOutputs . count ( idx ) = = 1 } ;
vecSend . push_back ( recipient ) ;
}
coinControl . fAllowOtherInputs = true ;
for ( const CTxIn & txin : tx . vin ) {
coinControl . Select ( txin . prevout ) ;
}
// Acquire the locks to prevent races to the new locked unspents between the
// CreateTransaction call and LockCoin calls (when lockUnspents is true).
2021-02-12 20:01:22 -03:00
LOCK ( wallet . cs_wallet ) ;
2021-02-10 18:06:01 -03:00
CTransactionRef tx_new ;
FeeCalculation fee_calc_out ;
2021-02-12 20:01:22 -03:00
if ( ! CreateTransaction ( wallet , vecSend , tx_new , nFeeRet , nChangePosInOut , error , coinControl , fee_calc_out , false ) ) {
2021-02-10 18:06:01 -03:00
return false ;
}
if ( nChangePosInOut ! = - 1 ) {
tx . vout . insert ( tx . vout . begin ( ) + nChangePosInOut , tx_new - > vout [ nChangePosInOut ] ) ;
}
// Copy output sizes from new transaction; they may have had the fee
// subtracted from them.
for ( unsigned int idx = 0 ; idx < tx . vout . size ( ) ; idx + + ) {
tx . vout [ idx ] . nValue = tx_new - > vout [ idx ] . nValue ;
}
// Add new txins while keeping original txin scriptSig/order.
for ( const CTxIn & txin : tx_new - > vin ) {
if ( ! coinControl . IsSelected ( txin . prevout ) ) {
tx . vin . push_back ( txin ) ;
}
if ( lockUnspents ) {
2021-02-12 20:01:22 -03:00
wallet . LockCoin ( txin . prevout ) ;
2021-02-10 18:06:01 -03:00
}
}
return true ;
}