@ -2600,8 +2600,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
scriptChange = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
scriptChange = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
}
}
CTxOut change_prototype_txout ( 0 , scriptChange ) ;
size_t change_prototype_size = GetSerializeSize ( change_prototype_txout , SER_DISK , 0 ) ;
nFeeRet = 0 ;
nFeeRet = 0 ;
bool pick_new_inputs = true ;
CAmount nValueIn = 0 ;
// Start with no fee and loop until there is enough fee
// Start with no fee and loop until there is enough fee
while ( true )
while ( true )
{
{
@ -2647,15 +2651,18 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
}
}
// Choose coins to use
// Choose coins to use
CAmount nValueIn = 0 ;
if ( pick_new_inputs ) {
nValueIn = 0 ;
setCoins . clear ( ) ;
setCoins . clear ( ) ;
if ( ! SelectCoins ( vAvailableCoins , nValueToSelect , setCoins , nValueIn , coinControl ) )
if ( ! SelectCoins ( vAvailableCoins , nValueToSelect , setCoins , nValueIn , coinControl ) )
{
{
strFailReason = _ ( " Insufficient funds " ) ;
strFailReason = _ ( " Insufficient funds " ) ;
return false ;
return false ;
}
}
}
const CAmount nChange = nValueIn - nValueToSelect ;
const CAmount nChange = nValueIn - nValueToSelect ;
if ( nChange > 0 )
if ( nChange > 0 )
{
{
// Fill a vout to ourself
// Fill a vout to ourself
@ -2739,16 +2746,30 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
}
}
if ( nFeeRet > = nFeeNeeded ) {
if ( nFeeRet > = nFeeNeeded ) {
// Reduce fee to only the needed amount if we have change
// Reduce fee to only the needed amount if possible. This
// output to increase. This prevents potential overpayment
// prevents potential overpayment in fees if the coins
// in fees if the coins selected to meet nFeeNeeded result
// selected to meet nFeeNeeded result in a transaction tha t
// in a transaction that requires less fee than the prior
// requires less fee than the prior iteration.
// iteration.
// TODO: The case where nSubtractFeeFromAmount > 0 remains
// TODO: The case where nSubtractFeeFromAmount > 0 remains
// to be addressed because it requires returning the fee to
// to be addressed because it requires returning the fee to
// the payees and not the change output.
// the payees and not the change output.
// TODO: The case where there is no change output remains
// to be addressed so we avoid creating too small an output.
// If we have no change and a big enough excess fee, then
// try to construct transaction again only without picking
// new inputs. We now know we only need the smaller fee
// (because of reduced tx size) and so we should add a
// change output. Only try this once.
CAmount fee_needed_for_change = GetMinimumFee ( change_prototype_size , currentConfirmationTarget , : : mempool , : : feeEstimator , nullptr , false /* ignoreGlobalPayTxFee */ , conservative_estimate ) ;
CAmount minimum_value_for_change = GetDustThreshold ( change_prototype_txout , : : dustRelayFee ) ;
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 ) {
pick_new_inputs = false ;
nFeeRet = nFeeNeeded + fee_needed_for_change ;
continue ;
}
// If we have change output already, just increase it
if ( nFeeRet > nFeeNeeded & & nChangePosInOut ! = - 1 & & nSubtractFeeFromAmount = = 0 ) {
if ( nFeeRet > nFeeNeeded & & nChangePosInOut ! = - 1 & & nSubtractFeeFromAmount = = 0 ) {
CAmount extraFeePaid = nFeeRet - nFeeNeeded ;
CAmount extraFeePaid = nFeeRet - nFeeNeeded ;
std : : vector < CTxOut > : : iterator change_position = txNew . vout . begin ( ) + nChangePosInOut ;
std : : vector < CTxOut > : : iterator change_position = txNew . vout . begin ( ) + nChangePosInOut ;
@ -2757,6 +2778,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
}
}
break ; // Done, enough fee included.
break ; // Done, enough fee included.
}
}
else if ( ! pick_new_inputs ) {
// This shouldn't happen, we should have had enough excess
// fee to pay for the new output and still meet nFeeNeeded
strFailReason = _ ( " Transaction fee and change calculation failed " ) ;
return false ;
}
// Try to reduce change to include necessary fee
// Try to reduce change to include necessary fee
if ( nChangePosInOut ! = - 1 & & nSubtractFeeFromAmount = = 0 ) {
if ( nChangePosInOut ! = - 1 & & nSubtractFeeFromAmount = = 0 ) {