@ -2469,9 +2469,9 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
CReserveKey reservekey ( this ) ;
CReserveKey reservekey ( this ) ;
CWalletTx wtx ;
CWalletTx wtx ;
if ( ! CreateTransaction ( vecSend , wtx , reservekey , nFeeRet , nChangePosInOut , strFailReason , & coinControl , false ) )
if ( ! CreateTransaction ( vecSend , wtx , reservekey , nFeeRet , nChangePosInOut , strFailReason , coinControl , false ) ) {
return false ;
return false ;
}
if ( nChangePosInOut ! = - 1 )
if ( nChangePosInOut ! = - 1 )
tx . vout . insert ( tx . vout . begin ( ) + nChangePosInOut , wtx . tx - > vout [ nChangePosInOut ] ) ;
tx . vout . insert ( tx . vout . begin ( ) + nChangePosInOut , wtx . tx - > vout [ nChangePosInOut ] ) ;
@ -2502,7 +2502,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
}
}
bool CWallet : : CreateTransaction ( const std : : vector < CRecipient > & vecSend , CWalletTx & wtxNew , CReserveKey & reservekey , CAmount & nFeeRet ,
bool CWallet : : CreateTransaction ( const std : : vector < CRecipient > & vecSend , CWalletTx & wtxNew , CReserveKey & reservekey , CAmount & nFeeRet ,
int & nChangePosInOut , std : : string & strFailReason , const CCoinControl * coinC ontrol, bool sign )
int & nChangePosInOut , std : : string & strFailReason , const CCoinControl & coin_c ontrol, bool sign )
{
{
CAmount nValue = 0 ;
CAmount nValue = 0 ;
int nChangePosRequest = nChangePosInOut ;
int nChangePosRequest = nChangePosInOut ;
@ -2567,7 +2567,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
LOCK2 ( cs_main , cs_wallet ) ;
LOCK2 ( cs_main , cs_wallet ) ;
{
{
std : : vector < COutput > vAvailableCoins ;
std : : vector < COutput > vAvailableCoins ;
AvailableCoins ( vAvailableCoins , true , coinC ontrol) ;
AvailableCoins ( vAvailableCoins , true , & coin_c ontrol) ;
// Create change script that will be used if we need change
// Create change script that will be used if we need change
// TODO: pass in scriptChange instead of reservekey so
// TODO: pass in scriptChange instead of reservekey so
@ -2575,12 +2575,9 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
CScript scriptChange ;
CScript scriptChange ;
// coin control: send change to custom address
// coin control: send change to custom address
if ( coinControl & & ! boost : : get < CNoDestination > ( & coinControl - > destChange ) )
if ( ! boost : : get < CNoDestination > ( & coin_control . destChange ) ) {
scriptChange = GetScriptForDestination ( coinControl - > destChange ) ;
scriptChange = GetScriptForDestination ( coin_control . destChange ) ;
} else { // no coin control: send change to newly generated address
// no coin control: send change to newly generated address
else
{
// Note: We use a new key here to keep it from being obvious which side is the change.
// 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
// 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.
// backup is restored, if the backup doesn't have the new private key for the change.
@ -2654,7 +2651,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
if ( pick_new_inputs ) {
if ( pick_new_inputs ) {
nValueIn = 0 ;
nValueIn = 0 ;
setCoins . clear ( ) ;
setCoins . clear ( ) ;
if ( ! SelectCoins ( vAvailableCoins , nValueToSelect , setCoins , nValueIn , coinC ontrol) )
if ( ! SelectCoins ( vAvailableCoins , nValueToSelect , setCoins , nValueIn , & coin_c ontrol) )
{
{
strFailReason = _ ( " Insufficient funds " ) ;
strFailReason = _ ( " Insufficient funds " ) ;
return false ;
return false ;
@ -2705,8 +2702,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
// to avoid conflicting with other possible uses of nSequence,
// to avoid conflicting with other possible uses of nSequence,
// and in the spirit of "smallest possible change from prior
// and in the spirit of "smallest possible change from prior
// behavior."
// behavior."
bool rbf = coinControl ? coinControl - > signalRbf : fWalletRbf ;
const uint32_t nSequence = coin_control . signalRbf ? MAX_BIP125_RBF_SEQUENCE : ( std : : numeric_limits < unsigned int > : : max ( ) - 1 ) ;
const uint32_t nSequence = rbf ? MAX_BIP125_RBF_SEQUENCE : ( std : : numeric_limits < unsigned int > : : max ( ) - 1 ) ;
for ( const auto & coin : setCoins )
for ( const auto & coin : setCoins )
txNew . vin . push_back ( CTxIn ( coin . outpoint , CScript ( ) ,
txNew . vin . push_back ( CTxIn ( coin . outpoint , CScript ( ) ,
nSequence ) ) ;
nSequence ) ) ;
@ -2725,17 +2721,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
vin . scriptWitness . SetNull ( ) ;
vin . scriptWitness . SetNull ( ) ;
}
}
// Allow to override the default confirmation target over the CoinControl instance
CAmount nFeeNeeded = GetMinimumFee ( nBytes , coin_control , : : mempool , : : feeEstimator , & feeCalc ) ;
int currentConfirmationTarget = nTxConfirmTarget ;
if ( coinControl & & coinControl - > nConfirmTarget > 0 )
currentConfirmationTarget = coinControl - > nConfirmTarget ;
// Allow to override the default fee estimate mode over the CoinControl instance
bool conservative_estimate = CalculateEstimateType ( coinControl ? coinControl - > m_fee_mode : FeeEstimateMode : : UNSET , rbf ) ;
CAmount nFeeNeeded = GetMinimumFee ( nBytes , currentConfirmationTarget , : : mempool , : : feeEstimator , & feeCalc , false /* ignoreGlobalPayTxFee */ , conservative_estimate ) ;
if ( coinControl & & coinControl - > fOverrideFeeRate )
nFeeNeeded = coinControl - > nFeeRate . GetFee ( nBytes ) ;
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
// because we must be at the maximum allowed fee.
@ -2760,7 +2746,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
// new inputs. We now know we only need the smaller fee
// new inputs. We now know we only need the smaller fee
// (because of reduced tx size) and so we should add a
// (because of reduced tx size) and so we should add a
// change output. Only try this once.
// change output. Only try this once.
CAmount fee_needed_for_change = GetMinimumFee ( change_prototype_size , currentConfirmationTarget , : : mempool , : : feeEstimator , nullptr , false /* ignoreGlobalPayTxFee */ , conservative_estimate ) ;
CAmount fee_needed_for_change = GetMinimumFee ( change_prototype_size , coin_control , : : mempool , : : feeEstimator , nullptr ) ;
CAmount minimum_value_for_change = GetDustThreshold ( change_prototype_txout , : : dustRelayFee ) ;
CAmount minimum_value_for_change = GetDustThreshold ( change_prototype_txout , : : dustRelayFee ) ;
CAmount max_excess_fee = fee_needed_for_change + minimum_value_for_change ;
CAmount max_excess_fee = fee_needed_for_change + minimum_value_for_change ;
if ( nFeeRet > nFeeNeeded + max_excess_fee & & nChangePosInOut = = - 1 & & nSubtractFeeFromAmount = = 0 & & pick_new_inputs ) {
if ( nFeeRet > nFeeNeeded + max_excess_fee & & nChangePosInOut = = - 1 & & nSubtractFeeFromAmount = = 0 & & pick_new_inputs ) {
@ -2936,33 +2922,61 @@ CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
return std : : max ( minTxFee . GetFee ( nTxBytes ) , : : minRelayTxFee . GetFee ( nTxBytes ) ) ;
return std : : max ( minTxFee . GetFee ( nTxBytes ) , : : minRelayTxFee . GetFee ( nTxBytes ) ) ;
}
}
CAmount CWallet : : GetMinimumFee ( unsigned int nTxBytes , unsigned int nConfirmTarget , const CTxMemPool & pool , const CBlockPolicyEstimator & estimator , FeeCalculation * feeCalc , bool ignoreGlobalPayTxFee , bool conservative_estimate )
CAmount CWallet : : GetMinimumFee ( unsigned int nTxBytes , const CCoinControl & coin_control , const CTxMemPool & pool , const CBlockPolicyEstimator & estimator , FeeCalculation * feeCalc )
{
{
// payTxFee is the user-set global for desired feerate
/* User control of how to calculate fee uses the following parameter precedence:
CAmount nFeeNeeded = payTxFee . GetFee ( nTxBytes ) ;
1. coin_control . m_feerate
// User didn't set: use -txconfirmtarget to estimate...
2. coin_control . m_confirm_target
if ( nFeeNeeded = = 0 | | ignoreGlobalPayTxFee ) {
3. payTxFee ( user - set global variable )
nFeeNeeded = estimator . estimateSmartFee ( nConfirmTarget , feeCalc , pool , conservative_estimate ) . GetFee ( nTxBytes ) ;
4. nTxConfirmTarget ( user - set global variable )
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
The first parameter that is set is used .
if ( nFeeNeeded = = 0 ) {
*/
nFeeNeeded = fallbackFee . GetFee ( nTxBytes ) ;
CAmount fee_needed ;
if ( coin_control . m_feerate ) { // 1.
fee_needed = coin_control . m_feerate - > GetFee ( nTxBytes ) ;
if ( feeCalc ) feeCalc - > reason = FeeReason : : PAYTXFEE ;
// Allow to override automatic min/max check over coin control instance
if ( coin_control . fOverrideFeeRate ) return fee_needed ;
}
else if ( ! coin_control . m_confirm_target & & : : payTxFee ! = CFeeRate ( 0 ) ) { // 3. TODO: remove magic value of 0 for global payTxFee
fee_needed = : : payTxFee . GetFee ( nTxBytes ) ;
if ( feeCalc ) feeCalc - > reason = FeeReason : : PAYTXFEE ;
}
else { // 2. or 4.
// We will use smart fee estimation
unsigned int target = coin_control . m_confirm_target ? * coin_control . m_confirm_target : : : nTxConfirmTarget ;
// By default estimates are economical iff we are signaling opt-in-RBF
bool conservative_estimate = ! coin_control . signalRbf ;
// Allow to override the default fee estimate mode over the CoinControl instance
if ( coin_control . m_fee_mode = = FeeEstimateMode : : CONSERVATIVE ) conservative_estimate = true ;
else if ( coin_control . m_fee_mode = = FeeEstimateMode : : ECONOMICAL ) conservative_estimate = false ;
fee_needed = estimator . estimateSmartFee ( target , feeCalc , conservative_estimate ) . GetFee ( nTxBytes ) ;
if ( fee_needed = = 0 ) {
// if we don't have enough data for estimateSmartFee, then use fallbackFee
fee_needed = fallbackFee . GetFee ( nTxBytes ) ;
if ( feeCalc ) feeCalc - > reason = FeeReason : : FALLBACK ;
if ( feeCalc ) feeCalc - > reason = FeeReason : : FALLBACK ;
}
}
} else {
// Obey mempool min fee when using smart fee estimation
if ( feeCalc ) feeCalc - > reason = FeeReason : : PAYTXFEE ;
CAmount min_mempool_fee = pool . GetMinFee ( GetArg ( " -maxmempool " , DEFAULT_MAX_MEMPOOL_SIZE ) * 1000000 ) . GetFee ( nTxBytes ) ;
if ( fee_needed < min_mempool_fee ) {
fee_needed = min_mempool_fee ;
if ( feeCalc ) feeCalc - > reason = FeeReason : : MEMPOOL_MIN ;
}
}
}
// prevent user from paying a fee below minRelayTxFee or minTxFee
// prevent user from paying a fee below minRelayTxFee or minTxFee
CAmount requiredFee = GetRequiredFee ( nTxBytes ) ;
CAmount required_f ee = GetRequiredFee ( nTxBytes ) ;
if ( requiredFee > nFeeNeeded ) {
if ( required_fee > fee_n eeded ) {
nFeeNeeded = requiredFee ;
fee_needed = required_f ee;
if ( feeCalc ) feeCalc - > reason = FeeReason : : REQUIRED ;
if ( feeCalc ) feeCalc - > reason = FeeReason : : REQUIRED ;
}
}
// But always obey the maximum
// But always obey the maximum
if ( nFeeNeeded > maxTxFee ) {
if ( fee_n eeded > maxTxFee ) {
nFeeNeeded = maxTxFee ;
fee_n eeded = maxTxFee ;
if ( feeCalc ) feeCalc - > reason = FeeReason : : MAXTXFEE ;
if ( feeCalc ) feeCalc - > reason = FeeReason : : MAXTXFEE ;
}
}
return nFeeNeeded ;
return fee_n eeded;
}
}
@ -4200,15 +4214,3 @@ bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState&
{
{
return : : AcceptToMemoryPool ( mempool , state , tx , true , NULL , NULL , false , nAbsurdFee ) ;
return : : AcceptToMemoryPool ( mempool , state , tx , true , NULL , NULL , false , nAbsurdFee ) ;
}
}
bool CalculateEstimateType ( FeeEstimateMode mode , bool opt_in_rbf ) {
switch ( mode ) {
case FeeEstimateMode : : UNSET :
return ! opt_in_rbf ; // Allow for lower fees if RBF is an option
case FeeEstimateMode : : CONSERVATIVE :
return true ;
case FeeEstimateMode : : ECONOMICAL :
return false ;
}
return true ;
}