@ -23,7 +23,7 @@
// calculation, but we should be able to refactor after priority is removed).
// calculation, but we should be able to refactor after priority is removed).
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
// be IsAllFromMe).
// be IsAllFromMe).
int64_t CalculateMaximumSignedTxSize ( const CTransaction & tx , const CWallet * pW allet)
int64_t CalculateMaximumSignedTxSize ( const CTransaction & tx , const CWallet * w allet)
{
{
CMutableTransaction txNew ( tx ) ;
CMutableTransaction txNew ( tx ) ;
std : : vector < CInputCoin > vCoins ;
std : : vector < CInputCoin > vCoins ;
@ -31,11 +31,11 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWal
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
// wallet, with a valid index into the vout array.
// wallet, with a valid index into the vout array.
for ( auto & input : tx . vin ) {
for ( auto & input : tx . vin ) {
const auto mi = pW allet- > mapWallet . find ( input . prevout . hash ) ;
const auto mi = w allet- > mapWallet . find ( input . prevout . hash ) ;
assert ( mi ! = pW allet- > mapWallet . end ( ) & & input . prevout . n < mi - > second . tx - > vout . size ( ) ) ;
assert ( mi ! = w allet- > mapWallet . end ( ) & & input . prevout . n < mi - > second . tx - > vout . size ( ) ) ;
vCoins . emplace_back ( CInputCoin ( & ( mi - > second ) , input . prevout . n ) ) ;
vCoins . emplace_back ( CInputCoin ( & ( mi - > second ) , input . prevout . n ) ) ;
}
}
if ( ! pW allet- > DummySignTx ( txNew , vCoins ) ) {
if ( ! w allet- > DummySignTx ( txNew , vCoins ) ) {
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
// implies that we can sign for every input.
// implies that we can sign for every input.
return - 1 ;
return - 1 ;
@ -43,10 +43,10 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWal
return GetVirtualTransactionSize ( txNew ) ;
return GetVirtualTransactionSize ( txNew ) ;
}
}
bool C FeeBumper: : preconditionChecks ( const CWallet * pW allet, const CWalletTx & wtx ) {
bool FeeBumper : : preconditionChecks ( const CWallet * w allet, const CWalletTx & wtx ) {
if ( pW allet- > HasWalletSpend ( wtx . GetHash ( ) ) ) {
if ( w allet- > HasWalletSpend ( wtx . GetHash ( ) ) ) {
vE rrors. push_back ( " Transaction has descendants in the wallet " ) ;
e rrors. push_back ( " Transaction has descendants in the wallet " ) ;
currentR esult = BumpFeeResult : : INVALID_PARAMETER ;
current_r esult = BumpFeeResult : : INVALID_PARAMETER ;
return false ;
return false ;
}
}
@ -54,58 +54,58 @@ bool CFeeBumper::preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx
LOCK ( mempool . cs ) ;
LOCK ( mempool . cs ) ;
auto it_mp = mempool . mapTx . find ( wtx . GetHash ( ) ) ;
auto it_mp = mempool . mapTx . find ( wtx . GetHash ( ) ) ;
if ( it_mp ! = mempool . mapTx . end ( ) & & it_mp - > GetCountWithDescendants ( ) > 1 ) {
if ( it_mp ! = mempool . mapTx . end ( ) & & it_mp - > GetCountWithDescendants ( ) > 1 ) {
vE rrors. push_back ( " Transaction has descendants in the mempool " ) ;
e rrors. push_back ( " Transaction has descendants in the mempool " ) ;
currentR esult = BumpFeeResult : : INVALID_PARAMETER ;
current_r esult = BumpFeeResult : : INVALID_PARAMETER ;
return false ;
return false ;
}
}
}
}
if ( wtx . GetDepthInMainChain ( ) ! = 0 ) {
if ( wtx . GetDepthInMainChain ( ) ! = 0 ) {
vE rrors. push_back ( " Transaction has been mined, or is conflicted with a mined transaction " ) ;
e rrors. push_back ( " Transaction has been mined, or is conflicted with a mined transaction " ) ;
currentR esult = BumpFeeResult : : WALLET_ERROR ;
current_r esult = BumpFeeResult : : WALLET_ERROR ;
return false ;
return false ;
}
}
return true ;
return true ;
}
}
C FeeBumper: : C FeeBumper( const CWallet * pW allet, const uint256 txidI n , const CCoinControl & coin_control , CAmount totalF ee )
FeeBumper : : FeeBumper ( const CWallet * w allet, const uint256 txid_i n , const CCoinControl & coin_control , CAmount total_f ee )
:
:
txid ( std : : move ( txidI n ) ) ,
txid ( std : : move ( txid_i n ) ) ,
nOldF ee( 0 ) ,
old_f ee( 0 ) ,
nNewF ee ( 0 )
new_f ee ( 0 )
{
{
vE rrors. clear ( ) ;
e rrors. clear ( ) ;
bumpedT xid . SetNull ( ) ;
bumped_t xid . SetNull ( ) ;
AssertLockHeld ( pW allet- > cs_wallet ) ;
AssertLockHeld ( w allet- > cs_wallet ) ;
auto it = pW allet- > mapWallet . find ( txid ) ;
auto it = w allet- > mapWallet . find ( txid ) ;
if ( it = = pW allet- > mapWallet . end ( ) ) {
if ( it = = w allet- > mapWallet . end ( ) ) {
vE rrors. push_back ( " Invalid or non-wallet transaction id " ) ;
e rrors. push_back ( " Invalid or non-wallet transaction id " ) ;
currentR esult = BumpFeeResult : : INVALID_ADDRESS_OR_KEY ;
current_r esult = BumpFeeResult : : INVALID_ADDRESS_OR_KEY ;
return ;
return ;
}
}
const CWalletTx & wtx = it - > second ;
const CWalletTx & wtx = it - > second ;
if ( ! preconditionChecks ( pW allet, wtx ) ) {
if ( ! preconditionChecks ( w allet, wtx ) ) {
return ;
return ;
}
}
if ( ! SignalsOptInRBF ( * wtx . tx ) ) {
if ( ! SignalsOptInRBF ( * wtx . tx ) ) {
vE rrors. push_back ( " Transaction is not BIP 125 replaceable " ) ;
e rrors. push_back ( " Transaction is not BIP 125 replaceable " ) ;
currentR esult = BumpFeeResult : : WALLET_ERROR ;
current_r esult = BumpFeeResult : : WALLET_ERROR ;
return ;
return ;
}
}
if ( wtx . mapValue . count ( " replaced_by_txid " ) ) {
if ( wtx . mapValue . count ( " replaced_by_txid " ) ) {
vE rrors. push_back ( strprintf ( " Cannot bump transaction %s which was already bumped by transaction %s " , txid . ToString ( ) , wtx . mapValue . at ( " replaced_by_txid " ) ) ) ;
e rrors. push_back ( strprintf ( " Cannot bump transaction %s which was already bumped by transaction %s " , txid . ToString ( ) , wtx . mapValue . at ( " replaced_by_txid " ) ) ) ;
currentR esult = BumpFeeResult : : WALLET_ERROR ;
current_r esult = BumpFeeResult : : WALLET_ERROR ;
return ;
return ;
}
}
// check that original tx consists entirely of our inputs
// check that original tx consists entirely of our inputs
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
if ( ! pW allet- > IsAllFromMe ( * wtx . tx , ISMINE_SPENDABLE ) ) {
if ( ! w allet- > IsAllFromMe ( * wtx . tx , ISMINE_SPENDABLE ) ) {
vE rrors. push_back ( " Transaction contains inputs that don't belong to this wallet " ) ;
e rrors. push_back ( " Transaction contains inputs that don't belong to this wallet " ) ;
currentR esult = BumpFeeResult : : WALLET_ERROR ;
current_r esult = BumpFeeResult : : WALLET_ERROR ;
return ;
return ;
}
}
@ -113,33 +113,33 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
// if there was no change output or multiple change outputs, fail
// if there was no change output or multiple change outputs, fail
int nOutput = - 1 ;
int nOutput = - 1 ;
for ( size_t i = 0 ; i < wtx . tx - > vout . size ( ) ; + + i ) {
for ( size_t i = 0 ; i < wtx . tx - > vout . size ( ) ; + + i ) {
if ( pW allet- > IsChange ( wtx . tx - > vout [ i ] ) ) {
if ( w allet- > IsChange ( wtx . tx - > vout [ i ] ) ) {
if ( nOutput ! = - 1 ) {
if ( nOutput ! = - 1 ) {
vE rrors. push_back ( " Transaction has multiple change outputs " ) ;
e rrors. push_back ( " Transaction has multiple change outputs " ) ;
currentR esult = BumpFeeResult : : WALLET_ERROR ;
current_r esult = BumpFeeResult : : WALLET_ERROR ;
return ;
return ;
}
}
nOutput = i ;
nOutput = i ;
}
}
}
}
if ( nOutput = = - 1 ) {
if ( nOutput = = - 1 ) {
vE rrors. push_back ( " Transaction does not have a change output " ) ;
e rrors. push_back ( " Transaction does not have a change output " ) ;
currentR esult = BumpFeeResult : : WALLET_ERROR ;
current_r esult = BumpFeeResult : : WALLET_ERROR ;
return ;
return ;
}
}
// Calculate the expected size of the new transaction.
// Calculate the expected size of the new transaction.
int64_t txSize = GetVirtualTransactionSize ( * ( wtx . tx ) ) ;
int64_t txSize = GetVirtualTransactionSize ( * ( wtx . tx ) ) ;
const int64_t maxNewTxSize = CalculateMaximumSignedTxSize ( * wtx . tx , pW allet) ;
const int64_t maxNewTxSize = CalculateMaximumSignedTxSize ( * wtx . tx , w allet) ;
if ( maxNewTxSize < 0 ) {
if ( maxNewTxSize < 0 ) {
vE rrors. push_back ( " Transaction contains inputs that cannot be signed " ) ;
e rrors. push_back ( " Transaction contains inputs that cannot be signed " ) ;
currentR esult = BumpFeeResult : : INVALID_ADDRESS_OR_KEY ;
current_r esult = BumpFeeResult : : INVALID_ADDRESS_OR_KEY ;
return ;
return ;
}
}
// calculate the old fee and fee-rate
// calculate the old fee and fee-rate
nOldF ee = wtx . GetDebit ( ISMINE_SPENDABLE ) - wtx . tx - > GetValueOut ( ) ;
old_f ee = wtx . GetDebit ( ISMINE_SPENDABLE ) - wtx . tx - > GetValueOut ( ) ;
CFeeRate nOldFeeRate ( nOldF ee, txSize ) ;
CFeeRate nOldFeeRate ( old_f ee, txSize ) ;
CFeeRate nNewFeeRate ;
CFeeRate nNewFeeRate ;
// The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
// The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
// future proof against changes to network wide policy for incremental relay
// future proof against changes to network wide policy for incremental relay
@ -149,26 +149,26 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
walletIncrementalRelayFee = : : incrementalRelayFee ;
walletIncrementalRelayFee = : : incrementalRelayFee ;
}
}
if ( totalF ee > 0 ) {
if ( total_f ee > 0 ) {
CAmount minTotalFee = nOldFeeRate . GetFee ( maxNewTxSize ) + : : incrementalRelayFee . GetFee ( maxNewTxSize ) ;
CAmount minTotalFee = nOldFeeRate . GetFee ( maxNewTxSize ) + : : incrementalRelayFee . GetFee ( maxNewTxSize ) ;
if ( totalF ee < minTotalFee ) {
if ( total_f ee < minTotalFee ) {
vE rrors. push_back ( strprintf ( " Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s) " ,
e rrors. push_back ( strprintf ( " Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s) " ,
FormatMoney ( minTotalFee ) , FormatMoney ( nOldFeeRate . GetFee ( maxNewTxSize ) ) , FormatMoney ( : : incrementalRelayFee . GetFee ( maxNewTxSize ) ) ) ) ;
FormatMoney ( minTotalFee ) , FormatMoney ( nOldFeeRate . GetFee ( maxNewTxSize ) ) , FormatMoney ( : : incrementalRelayFee . GetFee ( maxNewTxSize ) ) ) ) ;
currentR esult = BumpFeeResult : : INVALID_PARAMETER ;
current_r esult = BumpFeeResult : : INVALID_PARAMETER ;
return ;
return ;
}
}
CAmount requiredFee = GetRequiredFee ( maxNewTxSize ) ;
CAmount requiredFee = GetRequiredFee ( maxNewTxSize ) ;
if ( totalF ee < requiredFee ) {
if ( total_f ee < requiredFee ) {
vE rrors. push_back ( strprintf ( " Insufficient totalFee (cannot be less than required fee %s) " ,
e rrors. push_back ( strprintf ( " Insufficient totalFee (cannot be less than required fee %s) " ,
FormatMoney ( requiredFee ) ) ) ;
FormatMoney ( requiredFee ) ) ) ;
currentR esult = BumpFeeResult : : INVALID_PARAMETER ;
current_r esult = BumpFeeResult : : INVALID_PARAMETER ;
return ;
return ;
}
}
nNewFee = totalF ee ;
new_fee = total_f ee ;
nNewFeeRate = CFeeRate ( totalF ee , maxNewTxSize ) ;
nNewFeeRate = CFeeRate ( total_f ee , maxNewTxSize ) ;
} else {
} else {
nNewF ee = GetMinimumFee ( maxNewTxSize , coin_control , mempool , : : feeEstimator , nullptr /* FeeCalculation */ ) ;
new_f ee = GetMinimumFee ( maxNewTxSize , coin_control , mempool , : : feeEstimator , nullptr /* FeeCalculation */ ) ;
nNewFeeRate = CFeeRate ( nNewF ee , maxNewTxSize ) ;
nNewFeeRate = CFeeRate ( new_f ee , maxNewTxSize ) ;
// New fee rate must be at least old rate + minimum incremental relay rate
// New fee rate must be at least old rate + minimum incremental relay rate
// walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
// walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
@ -177,15 +177,15 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
// add 1 satoshi to the result, because it may have been rounded down.
// add 1 satoshi to the result, because it may have been rounded down.
if ( nNewFeeRate . GetFeePerK ( ) < nOldFeeRate . GetFeePerK ( ) + 1 + walletIncrementalRelayFee . GetFeePerK ( ) ) {
if ( nNewFeeRate . GetFeePerK ( ) < nOldFeeRate . GetFeePerK ( ) + 1 + walletIncrementalRelayFee . GetFeePerK ( ) ) {
nNewFeeRate = CFeeRate ( nOldFeeRate . GetFeePerK ( ) + 1 + walletIncrementalRelayFee . GetFeePerK ( ) ) ;
nNewFeeRate = CFeeRate ( nOldFeeRate . GetFeePerK ( ) + 1 + walletIncrementalRelayFee . GetFeePerK ( ) ) ;
nNewF ee = nNewFeeRate . GetFee ( maxNewTxSize ) ;
new_f ee = nNewFeeRate . GetFee ( maxNewTxSize ) ;
}
}
}
}
// Check that in all cases the new fee doesn't violate maxTxFee
// Check that in all cases the new fee doesn't violate maxTxFee
if ( nNewF ee > maxTxFee ) {
if ( new_f ee > maxTxFee ) {
vE rrors. push_back ( strprintf ( " Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s) " ,
e rrors. push_back ( strprintf ( " Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s) " ,
FormatMoney ( nNewF ee ) , FormatMoney ( maxTxFee ) ) ) ;
FormatMoney ( new_f ee ) , FormatMoney ( maxTxFee ) ) ) ;
currentR esult = BumpFeeResult : : WALLET_ERROR ;
current_r esult = BumpFeeResult : : WALLET_ERROR ;
return ;
return ;
}
}
@ -193,29 +193,29 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
// This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
// This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
// in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
// in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
// moment earlier. In this case, we report an error to the user, who may use totalF ee to make an adjustment.
// moment earlier. In this case, we report an error to the user, who may use total_f ee to make an adjustment.
CFeeRate minMempoolFeeRate = mempool . GetMinFee ( gArgs . GetArg ( " -maxmempool " , DEFAULT_MAX_MEMPOOL_SIZE ) * 1000000 ) ;
CFeeRate minMempoolFeeRate = mempool . GetMinFee ( gArgs . GetArg ( " -maxmempool " , DEFAULT_MAX_MEMPOOL_SIZE ) * 1000000 ) ;
if ( nNewFeeRate . GetFeePerK ( ) < minMempoolFeeRate . GetFeePerK ( ) ) {
if ( nNewFeeRate . GetFeePerK ( ) < minMempoolFeeRate . GetFeePerK ( ) ) {
vE rrors. push_back ( strprintf (
e rrors. push_back ( strprintf (
" New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "
" New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "
" the totalFee value should be at least %s or the settxfee value should be at least %s to add transaction " ,
" the totalFee value should be at least %s or the settxfee value should be at least %s to add transaction " ,
FormatMoney ( nNewFeeRate . GetFeePerK ( ) ) ,
FormatMoney ( nNewFeeRate . GetFeePerK ( ) ) ,
FormatMoney ( minMempoolFeeRate . GetFeePerK ( ) ) ,
FormatMoney ( minMempoolFeeRate . GetFeePerK ( ) ) ,
FormatMoney ( minMempoolFeeRate . GetFee ( maxNewTxSize ) ) ,
FormatMoney ( minMempoolFeeRate . GetFee ( maxNewTxSize ) ) ,
FormatMoney ( minMempoolFeeRate . GetFeePerK ( ) ) ) ) ;
FormatMoney ( minMempoolFeeRate . GetFeePerK ( ) ) ) ) ;
currentR esult = BumpFeeResult : : WALLET_ERROR ;
current_r esult = BumpFeeResult : : WALLET_ERROR ;
return ;
return ;
}
}
// Now modify the output to increase the fee.
// Now modify the output to increase the fee.
// If the output is not large enough to pay the fee, fail.
// If the output is not large enough to pay the fee, fail.
CAmount nDelta = nNewFee - nOldF ee ;
CAmount nDelta = new_fee - old_f ee ;
assert ( nDelta > 0 ) ;
assert ( nDelta > 0 ) ;
mtx = * wtx . tx ;
mtx = * wtx . tx ;
CTxOut * poutput = & ( mtx . vout [ nOutput ] ) ;
CTxOut * poutput = & ( mtx . vout [ nOutput ] ) ;
if ( poutput - > nValue < nDelta ) {
if ( poutput - > nValue < nDelta ) {
vE rrors. push_back ( " Change output is too small to bump the fee " ) ;
e rrors. push_back ( " Change output is too small to bump the fee " ) ;
currentR esult = BumpFeeResult : : WALLET_ERROR ;
current_r esult = BumpFeeResult : : WALLET_ERROR ;
return ;
return ;
}
}
@ -223,7 +223,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
poutput - > nValue - = nDelta ;
poutput - > nValue - = nDelta ;
if ( poutput - > nValue < = GetDustThreshold ( * poutput , : : dustRelayFee ) ) {
if ( poutput - > nValue < = GetDustThreshold ( * poutput , : : dustRelayFee ) ) {
LogPrint ( BCLog : : RPC , " Bumping fee and discarding dust output \n " ) ;
LogPrint ( BCLog : : RPC , " Bumping fee and discarding dust output \n " ) ;
nNewF ee + = poutput - > nValue ;
new_f ee + = poutput - > nValue ;
mtx . vout . erase ( mtx . vout . begin ( ) + nOutput ) ;
mtx . vout . erase ( mtx . vout . begin ( ) + nOutput ) ;
}
}
@ -234,36 +234,36 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
}
}
}
}
currentR esult = BumpFeeResult : : OK ;
current_r esult = BumpFeeResult : : OK ;
}
}
bool C FeeBumper: : signTransaction ( CWallet * pW allet)
bool FeeBumper : : signTransaction ( CWallet * w allet)
{
{
return pW allet- > SignTransaction ( mtx ) ;
return w allet- > SignTransaction ( mtx ) ;
}
}
bool C FeeBumper: : commit ( CWallet * pW allet)
bool FeeBumper : : commit ( CWallet * w allet)
{
{
AssertLockHeld ( pW allet- > cs_wallet ) ;
AssertLockHeld ( w allet- > cs_wallet ) ;
if ( ! vE rrors. empty ( ) | | currentR esult ! = BumpFeeResult : : OK ) {
if ( ! e rrors. empty ( ) | | current_r esult ! = BumpFeeResult : : OK ) {
return false ;
return false ;
}
}
auto it = txid . IsNull ( ) ? pW allet- > mapWallet . end ( ) : pW allet- > mapWallet . find ( txid ) ;
auto it = txid . IsNull ( ) ? w allet- > mapWallet . end ( ) : w allet- > mapWallet . find ( txid ) ;
if ( it = = pW allet- > mapWallet . end ( ) ) {
if ( it = = w allet- > mapWallet . end ( ) ) {
vE rrors. push_back ( " Invalid or non-wallet transaction id " ) ;
e rrors. push_back ( " Invalid or non-wallet transaction id " ) ;
currentR esult = BumpFeeResult : : MISC_ERROR ;
current_r esult = BumpFeeResult : : MISC_ERROR ;
return false ;
return false ;
}
}
CWalletTx & oldWtx = it - > second ;
CWalletTx & oldWtx = it - > second ;
// make sure the transaction still has no descendants and hasn't been mined in the meantime
// make sure the transaction still has no descendants and hasn't been mined in the meantime
if ( ! preconditionChecks ( pW allet, oldWtx ) ) {
if ( ! preconditionChecks ( w allet, oldWtx ) ) {
return false ;
return false ;
}
}
CWalletTx wtxBumped ( pW allet, MakeTransactionRef ( std : : move ( mtx ) ) ) ;
CWalletTx wtxBumped ( w allet, MakeTransactionRef ( std : : move ( mtx ) ) ) ;
// commit/broadcast the tx
// commit/broadcast the tx
CReserveKey reservekey ( pW allet) ;
CReserveKey reservekey ( w allet) ;
wtxBumped . mapValue = oldWtx . mapValue ;
wtxBumped . mapValue = oldWtx . mapValue ;
wtxBumped . mapValue [ " replaces_txid " ] = oldWtx . GetHash ( ) . ToString ( ) ;
wtxBumped . mapValue [ " replaces_txid " ] = oldWtx . GetHash ( ) . ToString ( ) ;
wtxBumped . vOrderForm = oldWtx . vOrderForm ;
wtxBumped . vOrderForm = oldWtx . vOrderForm ;
@ -271,26 +271,26 @@ bool CFeeBumper::commit(CWallet *pWallet)
wtxBumped . fTimeReceivedIsTxTime = true ;
wtxBumped . fTimeReceivedIsTxTime = true ;
wtxBumped . fFromMe = true ;
wtxBumped . fFromMe = true ;
CValidationState state ;
CValidationState state ;
if ( ! pW allet- > CommitTransaction ( wtxBumped , reservekey , g_connman . get ( ) , state ) ) {
if ( ! w allet- > CommitTransaction ( wtxBumped , reservekey , g_connman . get ( ) , state ) ) {
// NOTE: CommitTransaction never returns false, so this should never happen.
// NOTE: CommitTransaction never returns false, so this should never happen.
vE rrors. push_back ( strprintf ( " The transaction was rejected: %s " , state . GetRejectReason ( ) ) ) ;
e rrors. push_back ( strprintf ( " The transaction was rejected: %s " , state . GetRejectReason ( ) ) ) ;
return false ;
return false ;
}
}
bumpedT xid = wtxBumped . GetHash ( ) ;
bumped_t xid = wtxBumped . GetHash ( ) ;
if ( state . IsInvalid ( ) ) {
if ( state . IsInvalid ( ) ) {
// This can happen if the mempool rejected the transaction. Report
// This can happen if the mempool rejected the transaction. Report
// what happened in the "errors" response.
// what happened in the "errors" response.
vE rrors. push_back ( strprintf ( " The transaction was rejected: %s " , FormatStateMessage ( state ) ) ) ;
e rrors. push_back ( strprintf ( " The transaction was rejected: %s " , FormatStateMessage ( state ) ) ) ;
}
}
// mark the original tx as bumped
// mark the original tx as bumped
if ( ! pW allet- > MarkReplaced ( oldWtx . GetHash ( ) , wtxBumped . GetHash ( ) ) ) {
if ( ! w allet- > MarkReplaced ( oldWtx . GetHash ( ) , wtxBumped . GetHash ( ) ) ) {
// TODO: see if JSON-RPC has a standard way of returning a response
// TODO: see if JSON-RPC has a standard way of returning a response
// along with an exception. It would be good to return information about
// along with an exception. It would be good to return information about
// wtxBumped to the caller even if marking the original transaction
// wtxBumped to the caller even if marking the original transaction
// replaced does not succeed for some reason.
// replaced does not succeed for some reason.
vE rrors. push_back ( " Created new bumpfee transaction but could not mark the original transaction as replaced " ) ;
e rrors. push_back ( " Created new bumpfee transaction but could not mark the original transaction as replaced " ) ;
}
}
return true ;
return true ;
}
}