@@ -38,6 +38,11 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFe
3838 assert (inChainInputValue <= nValueIn);
3939
4040 feeDelta = 0 ;
41+
42+ nCountWithAncestors = 1 ;
43+ nSizeWithAncestors = nTxSize;
44+ nModFeesWithAncestors = nFee;
45+ nSigOpCountWithAncestors = sigOpCount;
4146}
4247
4348CTxMemPoolEntry::CTxMemPoolEntry (const CTxMemPoolEntry& other)
@@ -58,6 +63,7 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
5863void CTxMemPoolEntry::UpdateFeeDelta (int64_t newFeeDelta)
5964{
6065 nModFeesWithDescendants += newFeeDelta - feeDelta;
66+ nModFeesWithAncestors += newFeeDelta - feeDelta;
6167 feeDelta = newFeeDelta;
6268}
6369
@@ -99,6 +105,8 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
99105 modifyFee += cit->GetModifiedFee ();
100106 modifyCount++;
101107 cachedDescendants[updateIt].insert (cit);
108+ // Update ancestor state for each descendant
109+ mapTx.modify (cit, update_ancestor_state (updateIt->GetTxSize (), updateIt->GetModifiedFee (), 1 , updateIt->GetSigOpCount ()));
102110 }
103111 }
104112 mapTx.modify (updateIt, update_descendant_state (modifySize, modifyFee, modifyCount));
@@ -108,6 +116,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
108116// which has been re-added to the mempool.
109117// for each entry, look for descendants that are outside hashesToUpdate, and
110118// add fee/size information for such descendants to the parent.
119+ // for each such descendant, also update the ancestor state to include the parent.
111120void CTxMemPool::UpdateTransactionsFromBlock (const std::vector<uint256> &vHashesToUpdate)
112121{
113122 LOCK (cs);
@@ -228,6 +237,20 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors
228237 }
229238}
230239
240+ void CTxMemPool::UpdateEntryForAncestors (txiter it, const setEntries &setAncestors)
241+ {
242+ int64_t updateCount = setAncestors.size ();
243+ int64_t updateSize = 0 ;
244+ CAmount updateFee = 0 ;
245+ int updateSigOps = 0 ;
246+ for (const txiter& ancestorIt : setAncestors) {
247+ updateSize += ancestorIt->GetTxSize ();
248+ updateFee += ancestorIt->GetModifiedFee ();
249+ updateSigOps += ancestorIt->GetSigOpCount ();
250+ }
251+ mapTx.modify (it, update_ancestor_state (updateSize, updateFee, updateCount, updateSigOps));
252+ }
253+
231254void CTxMemPool::UpdateChildrenForRemoval (txiter it)
232255{
233256 const setEntries &setMemPoolChildren = GetMemPoolChildren (it);
@@ -236,11 +259,30 @@ void CTxMemPool::UpdateChildrenForRemoval(txiter it)
236259 }
237260}
238261
239- void CTxMemPool::UpdateForRemoveFromMempool (const setEntries &entriesToRemove)
262+ void CTxMemPool::UpdateForRemoveFromMempool (const setEntries &entriesToRemove, bool updateDescendants )
240263{
241264 // For each entry, walk back all ancestors and decrement size associated with this
242265 // transaction
243266 const uint64_t nNoLimit = std::numeric_limits<uint64_t >::max ();
267+ if (updateDescendants) {
268+ // updateDescendants should be true whenever we're not recursively
269+ // removing a tx and all its descendants, eg when a transaction is
270+ // confirmed in a block.
271+ // Here we only update statistics and not data in mapLinks (which
272+ // we need to preserve until we're finished with all operations that
273+ // need to traverse the mempool).
274+ for (const txiter& removeIt : entriesToRemove) {
275+ setEntries setDescendants;
276+ CalculateDescendants (removeIt, setDescendants);
277+ setDescendants.erase (removeIt); // don't update state for self
278+ int64_t modifySize = -((int64_t )removeIt->GetTxSize ());
279+ CAmount modifyFee = -removeIt->GetModifiedFee ();
280+ int modifySigOps = -removeIt->GetSigOpCount ();
281+ for (const txiter& dit : setDescendants) {
282+ mapTx.modify (dit, update_ancestor_state (modifySize, modifyFee, -1 , modifySigOps));
283+ }
284+ }
285+ }
244286 for (const txiter& removeIt : entriesToRemove) {
245287 setEntries setAncestors;
246288 const CTxMemPoolEntry &entry = *removeIt;
@@ -264,10 +306,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove)
264306 // transactions as the set of things to update for removal.
265307 CalculateMemPoolAncestors (entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false );
266308 // Note that UpdateAncestorsOf severs the child links that point to
267- // removeIt in the entries for the parents of removeIt. This is
268- // fine since we don't need to use the mempool children of any entries
269- // to walk back over our ancestors (but we do need the mempool
270- // parents!)
309+ // removeIt in the entries for the parents of removeIt.
271310 UpdateAncestorsOf (false , removeIt, setAncestors);
272311 }
273312 // After updating all the ancestor sizes, we can now sever the link between each
@@ -278,7 +317,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove)
278317 }
279318}
280319
281- void CTxMemPoolEntry::UpdateState (int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
320+ void CTxMemPoolEntry::UpdateDescendantState (int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
282321{
283322 nSizeWithDescendants += modifySize;
284323 assert (int64_t (nSizeWithDescendants) > 0 );
@@ -287,6 +326,17 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t
287326 assert (int64_t (nCountWithDescendants) > 0 );
288327}
289328
329+ void CTxMemPoolEntry::UpdateAncestorState (int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps)
330+ {
331+ nSizeWithAncestors += modifySize;
332+ assert (int64_t (nSizeWithAncestors) > 0 );
333+ nModFeesWithAncestors += modifyFee;
334+ nCountWithAncestors += modifyCount;
335+ assert (int64_t (nCountWithAncestors) > 0 );
336+ nSigOpCountWithAncestors += modifySigOps;
337+ assert (int (nSigOpCountWithAncestors) >= 0 );
338+ }
339+
290340CTxMemPool::CTxMemPool (const CFeeRate& _minReasonableRelayFee) :
291341 nTransactionsUpdated(0 )
292342{
@@ -373,6 +423,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
373423 }
374424 }
375425 UpdateAncestorsOf (true , newit, setAncestors);
426+ UpdateEntryForAncestors (newit, setAncestors);
376427
377428 // Save spent nullifiers
378429 if (tx.IsShieldedTx ()) {
@@ -468,7 +519,7 @@ void CTxMemPool::removeRecursive(const CTransaction& origTx, std::list<CTransact
468519 for (const txiter& it : setAllRemoves) {
469520 removed.emplace_back (it->GetSharedTx ());
470521 }
471- RemoveStaged (setAllRemoves);
522+ RemoveStaged (setAllRemoves, false );
472523 }
473524}
474525
@@ -573,7 +624,7 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
573624 if (it != mapTx.end ()) {
574625 setEntries stage;
575626 stage.insert (it);
576- RemoveStaged (stage);
627+ RemoveStaged (stage, true );
577628 }
578629 removeConflicts (*tx, conflicts);
579630 ClearPrioritisation (tx->GetHash ());
@@ -632,6 +683,8 @@ void CTxMemPool::check(const CCoinsViewCache* pcoins) const
632683 innerUsage += memusage::DynamicUsage (links.parents ) + memusage::DynamicUsage (links.children );
633684 bool fDependsWait = false ;
634685 setEntries setParentCheck;
686+ int64_t parentSizes = 0 ;
687+ unsigned int parentSigOpCount = 0 ;
635688 bool fHasZerocoinSpends = false ;
636689 for (const CTxIn& txin : tx.vin ) {
637690 // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
@@ -640,7 +693,10 @@ void CTxMemPool::check(const CCoinsViewCache* pcoins) const
640693 const CTransaction& tx2 = it2->GetTx ();
641694 assert (tx2.vout .size () > txin.prevout .n && !tx2.vout [txin.prevout .n ].IsNull ());
642695 fDependsWait = true ;
643- setParentCheck.insert (it2);
696+ if (setParentCheck.insert (it2).second ) {
697+ parentSizes += it2->GetTxSize ();
698+ parentSigOpCount += it2->GetSigOpCount ();
699+ }
644700 } else if (!txin.IsZerocoinSpend () && !txin.IsZerocoinPublicSpend ()) {
645701 assert (pcoins->HaveCoin (txin.prevout ));
646702 } else {
@@ -666,18 +722,20 @@ void CTxMemPool::check(const CCoinsViewCache* pcoins) const
666722 }
667723 }
668724 assert (setParentCheck == GetMemPoolParents (it));
725+ // Also check to make sure ancestor size/sigops are >= sum with immediate
726+ // parents.
727+ assert (it->GetSizeWithAncestors () >= parentSizes + it->GetTxSize ());
728+ assert (it->GetSigOpCountWithAncestors () >= parentSigOpCount + it->GetSigOpCount ());
669729 // Check children against mapNextTx
670730 if (!fHasZerocoinSpends ) {
671731 CTxMemPool::setEntries setChildrenCheck;
672732 std::map<COutPoint, CInPoint>::const_iterator iter = mapNextTx.lower_bound (COutPoint (tx.GetHash (), 0 ));
673733 int64_t childSizes = 0 ;
674- CAmount childModFee = 0 ;
675734 for (; iter != mapNextTx.end () && iter->first .hash == tx.GetHash (); ++iter) {
676735 txiter childit = mapTx.find (iter->second .ptx ->GetHash ());
677736 assert (childit != mapTx.end ()); // mapNextTx points to in-mempool transactions
678737 if (setChildrenCheck.insert (childit).second ) {
679738 childSizes += childit->GetTxSize ();
680- childModFee += childit->GetModifiedFee ();
681739 }
682740 }
683741 assert (setChildrenCheck == GetMemPoolChildren (it));
@@ -919,10 +977,10 @@ size_t CTxMemPool::DynamicMemoryUsage() const
919977 memusage::DynamicUsage (mapSaplingNullifiers);
920978}
921979
922- void CTxMemPool::RemoveStaged (setEntries &stage)
980+ void CTxMemPool::RemoveStaged (setEntries &stage, bool updateDescendants )
923981{
924982 AssertLockHeld (cs);
925- UpdateForRemoveFromMempool (stage);
983+ UpdateForRemoveFromMempool (stage, updateDescendants );
926984 for (const txiter& it : stage) {
927985 removeUnchecked (it);
928986 }
@@ -941,7 +999,7 @@ int CTxMemPool::Expire(int64_t time)
941999 for (const txiter& removeit : toremove) {
9421000 CalculateDescendants (removeit, stage);
9431001 }
944- RemoveStaged (stage);
1002+ RemoveStaged (stage, false );
9451003 return stage.size ();
9461004}
9471005
@@ -1052,7 +1110,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
10521110 for (txiter it: stage)
10531111 txn.push_back (it->GetTx ());
10541112 }
1055- RemoveStaged (stage);
1113+ RemoveStaged (stage, false );
10561114 if (pvNoSpendsRemaining) {
10571115 for (const CTransaction& tx: txn) {
10581116 for (const CTxIn& txin: tx.vin ) {
0 commit comments