From 54c6f3c1da01090aee9691a2c2bee0984a054ce8 Mon Sep 17 00:00:00 2001 From: glozow Date: Thu, 30 Sep 2021 09:08:40 +0100 Subject: [PATCH] [mempool] speed up check() by using coins cache and iterating in topo order No behavior changes. Before, we're always adding transactions to the "check later" queue if they have any parents in the mempool. But there's no reason to do this if all of its inputs are already available from mempoolDuplicate. Instead, check for inputs, and only mark fDependsWait=true if the parents haven't been processed yet. Reduce the amount of "check later" transactions by looking at ancestors before descendants. Do this by iterating through them in ascending order by ancestor count. This works because a child will always have more in-mempool ancestors than its parent. We should never have any entries in the "check later" queue after this commit. --- src/txmempool.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5a93f30c8a..10f7f66263 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -693,13 +693,14 @@ void CTxMemPool::check(CChainState& active_chainstate) const uint64_t checkTotal = 0; CAmount check_total_fee{0}; uint64_t innerUsage = 0; + uint64_t prev_ancestor_count{0}; CCoinsViewCache& active_coins_tip = active_chainstate.CoinsTip(); CCoinsViewCache mempoolDuplicate(const_cast(&active_coins_tip)); const int64_t spendheight = active_chainstate.m_chain.Height() + 1; std::list waitingOnDependants; - for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { + for (const auto& it : GetSortedDepthAndScore()) { unsigned int i = 0; checkTotal += it->GetTxSize(); check_total_fee += it->GetFee(); @@ -714,7 +715,7 @@ void CTxMemPool::check(CChainState& active_chainstate) const if (it2 != mapTx.end()) { const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); - fDependsWait = true; + if (!mempoolDuplicate.HaveCoin(txin.prevout)) fDependsWait = true; setParentCheck.insert(*it2); } else { assert(active_coins_tip.HaveCoin(txin.prevout)); @@ -751,6 +752,9 @@ void CTxMemPool::check(CChainState& active_chainstate) const assert(it->GetSizeWithAncestors() == nSizeCheck); assert(it->GetSigOpCostWithAncestors() == nSigOpCheck); assert(it->GetModFeesWithAncestors() == nFeesCheck); + // Sanity check: we are walking in ascending ancestor count order. + assert(prev_ancestor_count <= it->GetCountWithAncestors()); + prev_ancestor_count = it->GetCountWithAncestors(); // Check children against mapNextTx CTxMemPoolEntry::Children setChildrenCheck;