@ -831,15 +831,42 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return state . Invalid ( false , REJECT_ALREADY_KNOWN , " txn-already-in-mempool " ) ;
// Check for conflicts with in-memory transactions
set < uint256 > setConflicts ;
{
LOCK ( pool . cs ) ; // protect pool.mapNextTx
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + )
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
{
COutPoint outpoint = tx . vin [ i ] . prevout ;
if ( pool . mapNextTx . count ( outpoint ) )
if ( pool . mapNextTx . count ( txin . prevout ) )
{
// Disable replacement feature for now
return state . Invalid ( false , REJECT_CONFLICT , " txn-mempool-conflict " ) ;
const CTransaction * ptxConflicting = pool . mapNextTx [ txin . prevout ] . ptx ;
if ( ! setConflicts . count ( ptxConflicting - > GetHash ( ) ) )
{
// Allow opt-out of transaction replacement by setting
// nSequence >= maxint-1 on all inputs.
//
// maxint-1 is picked to still allow use of nLockTime by
// non-replacable transactions. All inputs rather than just one
// is for the sake of multi-party protocols, where we don't
// want a single party to be able to disable replacement.
//
// The opt-out ignores descendants as anyone relying on
// first-seen mempool behavior should be checking all
// unconfirmed ancestors anyway; doing otherwise is hopelessly
// insecure.
bool fReplacementOptOut = true ;
BOOST_FOREACH ( const CTxIn & txin , ptxConflicting - > vin )
{
if ( txin . nSequence < std : : numeric_limits < unsigned int > : : max ( ) - 1 )
{
fReplacementOptOut = false ;
break ;
}
}
if ( fReplacementOptOut )
return state . Invalid ( false , REJECT_CONFLICT , " txn-mempool-conflict " ) ;
setConflicts . insert ( ptxConflicting - > GetHash ( ) ) ;
}
}
}
}
@ -957,6 +984,82 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return state . DoS ( 0 , false , REJECT_NONSTANDARD , " too-long-mempool-chain " , false , errString ) ;
}
// A transaction that spends outputs that would be replaced by it is invalid. Now
// that we have the set of all ancestors we can detect this
// pathological case by making sure setConflicts and setAncestors don't
// intersect.
BOOST_FOREACH ( CTxMemPool : : txiter ancestorIt , setAncestors )
{
const uint256 & hashAncestor = ancestorIt - > GetTx ( ) . GetHash ( ) ;
if ( setConflicts . count ( hashAncestor ) )
{
return state . DoS ( 10 , error ( " AcceptToMemoryPool: %s spends conflicting transaction %s " ,
hash . ToString ( ) ,
hashAncestor . ToString ( ) ) ,
REJECT_INVALID , " bad-txns-spends-conflicting-tx " ) ;
}
}
// Check if it's economically rational to mine this transaction rather
// than the ones it replaces.
CAmount nConflictingFees = 0 ;
size_t nConflictingSize = 0 ;
if ( setConflicts . size ( ) )
{
LOCK ( pool . cs ) ;
// For efficiency we simply sum up the pre-calculated
// fees/size-with-descendants values from the mempool package
// tracking; this does mean the pathological case of diamond tx
// graphs will be overcounted.
BOOST_FOREACH ( const uint256 hashConflicting , setConflicts )
{
CTxMemPool : : txiter mi = pool . mapTx . find ( hashConflicting ) ;
if ( mi = = pool . mapTx . end ( ) )
continue ;
nConflictingFees + = mi - > GetFeesWithDescendants ( ) ;
nConflictingSize + = mi - > GetSizeWithDescendants ( ) ;
}
// First of all we can't allow a replacement unless it pays greater
// fees than the transactions it conflicts with - if we did the
// bandwidth used by those conflicting transactions would not be
// paid for
if ( nFees < nConflictingFees )
{
return state . DoS ( 0 , error ( " AcceptToMemoryPool: rejecting replacement %s, less fees than conflicting txs; %s < %s " ,
hash . ToString ( ) , FormatMoney ( nFees ) , FormatMoney ( nConflictingFees ) ) ,
REJECT_INSUFFICIENTFEE , " insufficient fee " ) ;
}
// Secondly in addition to paying more fees than the conflicts the
// new transaction must additionally pay for its own bandwidth.
CAmount nDeltaFees = nFees - nConflictingFees ;
if ( nDeltaFees < : : minRelayTxFee . GetFee ( nSize ) )
{
return state . DoS ( 0 ,
error ( " AcceptToMemoryPool: rejecting replacement %s, not enough additional fees to relay; %s < %s " ,
hash . ToString ( ) ,
FormatMoney ( nDeltaFees ) ,
FormatMoney ( : : minRelayTxFee . GetFee ( nSize ) ) ) ,
REJECT_INSUFFICIENTFEE , " insufficient fee " ) ;
}
// Finally replace only if we end up with a larger fees-per-kb than
// the replacements.
CFeeRate oldFeeRate ( nConflictingFees , nConflictingSize ) ;
CFeeRate newFeeRate ( nFees , nSize ) ;
if ( newFeeRate < = oldFeeRate )
{
return state . DoS ( 0 ,
error ( " AcceptToMemoryPool: rejecting replacement %s; new feerate %s <= old feerate %s " ,
hash . ToString ( ) ,
newFeeRate . ToString ( ) ,
oldFeeRate . ToString ( ) ) ,
REJECT_INSUFFICIENTFEE , " insufficient fee " ) ;
}
}
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if ( ! CheckInputs ( tx , state , view , true , STANDARD_SCRIPT_VERIFY_FLAGS , true ) )
@ -977,6 +1080,19 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
__func__ , hash . ToString ( ) , FormatStateMessage ( state ) ) ;
}
// Remove conflicting transactions from the mempool
list < CTransaction > ltxConflicted ;
pool . removeConflicts ( tx , ltxConflicted ) ;
BOOST_FOREACH ( const CTransaction & txConflicted , ltxConflicted )
{
LogPrint ( " mempool " , " replacing tx %s with %s for %s BTC additional fees, %d delta bytes \n " ,
txConflicted . GetHash ( ) . ToString ( ) ,
hash . ToString ( ) ,
FormatMoney ( nFees - nConflictingFees ) ,
( int ) nSize - ( int ) nConflictingSize ) ;
}
// Store transaction in memory
pool . addUnchecked ( hash , entry , setAncestors , ! IsInitialBlockDownload ( ) ) ;