@@ -32,7 +32,6 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
3232 nTxSize = ::GetSerializeSize (tx, SER_NETWORK, PROTOCOL_VERSION);
3333 nModSize = tx.CalculateModifiedSize (nTxSize);
3434 nUsageSize = tx.DynamicMemoryUsage ();
35- feeRate = CFeeRate (nFee, nTxSize);
3635}
3736
3837CTxMemPoolEntry::CTxMemPoolEntry (const CTxMemPoolEntry& other)
@@ -49,9 +48,10 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
4948 return dResult;
5049}
5150
52- CTxMemPool::CTxMemPool (const CFeeRate& _minRelayFee) :
53- nTransactionsUpdated(0 )
51+ CTxMemPool::CTxMemPool (const CFeeRate& _minRelayFee)
5452{
53+ clear ();
54+
5555 // Sanity checks off by default for performance, because otherwise
5656 // accepting transactions becomes O(N^2) where N is the number
5757 // of transactions in the pool
@@ -109,6 +109,19 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
109109 return true ;
110110}
111111
112+ void CTxMemPool::removeUnchecked (const uint256& hash)
113+ {
114+ indexed_transaction_set::iterator it = mapTx.find (hash);
115+
116+ BOOST_FOREACH (const CTxIn& txin, it->GetTx ().vin )
117+ mapNextTx.erase (txin.prevout );
118+
119+ totalTxSize -= it->GetTxSize ();
120+ cachedInnerUsage -= it->DynamicMemoryUsage ();
121+ mapTx.erase (it);
122+ nTransactionsUpdated++;
123+ minerPolicyEstimator->removeTx (hash);
124+ }
112125
113126void CTxMemPool::remove (const CTransaction &origTx, std::list<CTransaction>& removed, bool fRecursive )
114127{
@@ -144,15 +157,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
144157 txToRemove.push_back (it->second .ptx ->GetHash ());
145158 }
146159 }
147- BOOST_FOREACH (const CTxIn& txin, tx.vin )
148- mapNextTx.erase (txin.prevout );
149-
150160 removed.push_back (tx);
151- totalTxSize -= mapTx.find (hash)->GetTxSize ();
152- cachedInnerUsage -= mapTx.find (hash)->DynamicMemoryUsage ();
153- mapTx.erase (hash);
154- nTransactionsUpdated++;
155- minerPolicyEstimator->removeTx (hash);
161+ removeUnchecked (hash);
156162 }
157163 }
158164}
@@ -435,3 +441,104 @@ size_t CTxMemPool::DynamicMemoryUsage() const {
435441 // Estimate the overhead of mapTx to be 6 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.
436442 return memusage::MallocUsage (sizeof (CTxMemPoolEntry) + 6 * sizeof (void *)) * mapTx.size () + memusage::DynamicUsage (mapNextTx) + memusage::DynamicUsage (mapDeltas) + cachedInnerUsage;
437443}
444+
445+ size_t CTxMemPool::GuessDynamicMemoryUsage (const CTxMemPoolEntry& entry) const {
446+ return memusage::MallocUsage (sizeof (CTxMemPoolEntry) + 5 * sizeof (void *)) + entry.DynamicMemoryUsage () + memusage::IncrementalDynamicUsage (mapNextTx) * entry.GetTx ().vin .size ();
447+ }
448+
449+ bool CTxMemPool::StageTrimToSize (size_t sizelimit, const CTxMemPoolEntry& toadd, std::set<uint256>& stage, CAmount& nFeesRemoved) {
450+ size_t nSizeRemoved = 0 ;
451+ std::set<uint256> protect;
452+ BOOST_FOREACH (const CTxIn& in, toadd.GetTx ().vin ) {
453+ protect.insert (in.prevout .hash );
454+ }
455+
456+ size_t expsize = DynamicMemoryUsage () + GuessDynamicMemoryUsage (toadd); // Track the expected resulting memory usage of the mempool.
457+ indexed_transaction_set::nth_index<1 >::type::reverse_iterator it = mapTx.get <1 >().rbegin ();
458+ int fails = 0 ; // Number of mempool transactions iterated over that were not included in the stage.
459+ // Iterate from lowest feerate to highest feerate in the mempool:
460+ while (expsize > sizelimit && it != mapTx.get <1 >().rend ()) {
461+ const uint256& hash = it->GetTx ().GetHash ();
462+ if (stage.count (hash)) {
463+ // If the transaction is already staged for deletion, we know its descendants are already processed, so skip it.
464+ it++;
465+ continue ;
466+ }
467+ if (GetRand (10 )) {
468+ // Only try 1/10 of the transactions, in order to have some chance to avoid very big chains.
469+ it++;
470+ continue ;
471+ }
472+ if (CompareTxMemPoolEntryByFeeRate ()(*it, toadd)) {
473+ // If the transaction's feerate is worse than what we're looking for, we have processed everything in the mempool
474+ // that could improve the staged set. If we don't have an acceptable solution by now, bail out.
475+ return false ;
476+ }
477+ std::deque<uint256> todo; // List of hashes that we still need to process (descendants of 'hash').
478+ std::set<uint256> now; // Set of hashes that will need to be added to stage if 'hash' is included.
479+ CAmount nowfee = 0 ; // Sum of the fees in 'now'.
480+ size_t nowsize = 0 ; // Sum of the tx sizes in 'now'.
481+ size_t nowusage = 0 ; // Sum of the memory usages of transactions in 'now'.
482+ int iternow = 0 ; // Transactions we've inspected so far while determining whether 'hash' is acceptable.
483+ todo.push_back (it->GetTx ().GetHash ()); // Add 'hash' to the todo list, to initiate processing its children.
484+ bool good = true ; // Whether including 'hash' (and all its descendants) is a good idea.
485+ // Iterate breadth-first over all descendants of transaction with hash 'hash'.
486+ while (!todo.empty ()) {
487+ uint256 hashnow = todo.front ();
488+ if (protect.count (hashnow)) {
489+ // If this transaction is in the protected set, we're done with 'hash'.
490+ good = false ;
491+ break ;
492+ }
493+ iternow++; // We only count transactions we actually had to go find in the mempool.
494+ if (iternow + fails > 20 ) {
495+ return false ;
496+ }
497+ const CTxMemPoolEntry* origTx = &*mapTx.find (hashnow);
498+ nowfee += origTx->GetFee ();
499+ if (nFeesRemoved + nowfee > toadd.GetFee ()) {
500+ // If this pushes up to the total fees deleted too high, we're done with 'hash'.
501+ good = false ;
502+ break ;
503+ }
504+ todo.pop_front ();
505+ // Add 'hashnow' to the 'now' set, and update its statistics.
506+ now.insert (hashnow);
507+ nowusage += GuessDynamicMemoryUsage (*origTx);
508+ nowsize += origTx->GetTxSize ();
509+ // Find dependencies of 'hashnow' and them to todo.
510+ std::map<COutPoint, CInPoint>::iterator iter = mapNextTx.lower_bound (COutPoint (hashnow, 0 ));
511+ while (iter != mapNextTx.end () && iter->first .hash == hashnow) {
512+ const uint256& nexthash = iter->second .ptx ->GetHash ();
513+ if (!(stage.count (nexthash) || now.count (nexthash))) {
514+ todo.push_back (nexthash);
515+ }
516+ iter++;
517+ }
518+ }
519+ if (good && (double )nowfee * toadd.GetTxSize () > (double )toadd.GetFee () * nowsize) {
520+ // The new transaction's feerate is below that of the set we're removing.
521+ good = false ;
522+ }
523+ if (good) {
524+ stage.insert (now.begin (), now.end ());
525+ nFeesRemoved += nowfee;
526+ nSizeRemoved += nowsize;
527+ expsize -= nowusage;
528+ } else {
529+ fails += iternow;
530+ if (fails > 10 ) {
531+ // Bail out after traversing 32 transactions that are not acceptable.
532+ return false ;
533+ }
534+ }
535+ it++;
536+ }
537+ return true ;
538+ }
539+
540+ void CTxMemPool::RemoveStaged (std::set<uint256>& stage) {
541+ BOOST_FOREACH (const uint256& hash, stage) {
542+ removeUnchecked (hash);
543+ }
544+ }
0 commit comments