Remove CTxMemPool::GetSortedDepthAndScore

The mempool clusters and linearization permit sorting the mempool topologically
without making use of ancestor counts (as long as the graph is not oversized).

Co-authored-by: Pieter Wuille <pieter@wuille.net>
This commit is contained in:
Suhas Daftuar
2023-09-28 10:20:04 -04:00
parent 21b5cea588
commit feceaa42e8
2 changed files with 14 additions and 50 deletions

View File

@@ -714,11 +714,12 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
uint64_t checkTotal = 0; uint64_t checkTotal = 0;
CAmount check_total_fee{0}; CAmount check_total_fee{0};
uint64_t innerUsage = 0; uint64_t innerUsage = 0;
uint64_t prev_ancestor_count{0};
assert(!m_txgraph->IsOversized(TxGraph::Level::MAIN));
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(&active_coins_tip)); CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(&active_coins_tip));
for (const auto& it : GetSortedDepthAndScore()) { for (const auto& it : GetSortedScoreWithTopology()) {
checkTotal += it->GetTxSize(); checkTotal += it->GetTxSize();
check_total_fee += it->GetFee(); check_total_fee += it->GetFee();
innerUsage += it->DynamicMemoryUsage(); innerUsage += it->DynamicMemoryUsage();
@@ -733,9 +734,10 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
setParentCheck.insert(*it2); setParentCheck.insert(*it2);
} }
// We are iterating through the mempool entries sorted in order by ancestor count. // We are iterating through the mempool entries sorted
// All parents must have been checked before their children and their coins added to // topologically and by mining score. All parents must have been
// the mempoolDuplicate coins cache. // checked before their children and their coins added to the
// mempoolDuplicate coins cache.
assert(mempoolDuplicate.HaveCoin(txin.prevout)); assert(mempoolDuplicate.HaveCoin(txin.prevout));
// Check whether its inputs are marked in mapNextTx. // Check whether its inputs are marked in mapNextTx.
auto it3 = mapNextTx.find(txin.prevout); auto it3 = mapNextTx.find(txin.prevout);
@@ -765,9 +767,6 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
assert(it->GetSizeWithAncestors() == nSizeCheck); assert(it->GetSizeWithAncestors() == nSizeCheck);
assert(it->GetSigOpCostWithAncestors() == nSigOpCheck); assert(it->GetSigOpCostWithAncestors() == nSigOpCheck);
assert(it->GetModFeesWithAncestors() == nFeesCheck); 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 // Check children against mapNextTx
CTxMemPoolEntry::Children setChildrenCheck; CTxMemPoolEntry::Children setChildrenCheck;
@@ -819,23 +818,7 @@ bool CTxMemPool::CompareMiningScoreWithTopology(const Wtxid& hasha, const Wtxid&
return m_txgraph->CompareMainOrder(*i.value(), *j.value()) < 0; return m_txgraph->CompareMainOrder(*i.value(), *j.value()) < 0;
} }
namespace { std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedScoreWithTopology() const
class DepthAndScoreComparator
{
public:
bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator& a, const CTxMemPool::indexed_transaction_set::const_iterator& b)
{
uint64_t counta = a->GetCountWithAncestors();
uint64_t countb = b->GetCountWithAncestors();
if (counta == countb) {
return CompareTxMemPoolEntryByScore()(*a, *b);
}
return counta < countb;
}
};
} // namespace
std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedDepthAndScore() const
{ {
std::vector<indexed_transaction_set::const_iterator> iters; std::vector<indexed_transaction_set::const_iterator> iters;
AssertLockHeld(cs); AssertLockHeld(cs);
@@ -845,7 +828,9 @@ std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::Get
for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) { for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) {
iters.push_back(mi); iters.push_back(mi);
} }
std::sort(iters.begin(), iters.end(), DepthAndScoreComparator()); std::sort(iters.begin(), iters.end(), [this](const auto& a, const auto& b) EXCLUSIVE_LOCKS_REQUIRED(cs) noexcept {
return m_txgraph->CompareMainOrder(*a, *b) < 0;
});
return iters; return iters;
} }
@@ -855,7 +840,7 @@ std::vector<CTxMemPoolEntryRef> CTxMemPool::entryAll() const
std::vector<CTxMemPoolEntryRef> ret; std::vector<CTxMemPoolEntryRef> ret;
ret.reserve(mapTx.size()); ret.reserve(mapTx.size());
for (const auto& it : GetSortedDepthAndScore()) { for (const auto& it : GetSortedScoreWithTopology()) {
ret.emplace_back(*it); ret.emplace_back(*it);
} }
return ret; return ret;
@@ -864,7 +849,7 @@ std::vector<CTxMemPoolEntryRef> CTxMemPool::entryAll() const
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
{ {
LOCK(cs); LOCK(cs);
auto iters = GetSortedDepthAndScore(); auto iters = GetSortedScoreWithTopology();
std::vector<TxMempoolInfo> ret; std::vector<TxMempoolInfo> ret;
ret.reserve(mapTx.size()); ret.reserve(mapTx.size());

View File

@@ -90,27 +90,6 @@ struct mempoolentry_wtxid
} }
}; };
/** \class CompareTxMemPoolEntryByScore
*
* Sort by feerate of entry (fee/size) in descending order
* This is only used for transaction relay, so we use GetFee()
* instead of GetModifiedFee() to avoid leaking prioritization
* information via the sort order.
*/
class CompareTxMemPoolEntryByScore
{
public:
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
FeeFrac f1(a.GetFee(), a.GetTxSize());
FeeFrac f2(b.GetFee(), b.GetTxSize());
if (FeeRateCompare(f1, f2) == 0) {
return b.GetTx().GetHash() < a.GetTx().GetHash();
}
return f1 > f2;
}
};
class CompareTxMemPoolEntryByEntryTime class CompareTxMemPoolEntryByEntryTime
{ {
public: public:
@@ -313,7 +292,7 @@ private:
void UpdateParent(txiter entry, txiter parent, bool add) EXCLUSIVE_LOCKS_REQUIRED(cs); void UpdateParent(txiter entry, txiter parent, bool add) EXCLUSIVE_LOCKS_REQUIRED(cs);
void UpdateChild(txiter entry, txiter child, bool add) EXCLUSIVE_LOCKS_REQUIRED(cs); void UpdateChild(txiter entry, txiter child, bool add) EXCLUSIVE_LOCKS_REQUIRED(cs);
std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const EXCLUSIVE_LOCKS_REQUIRED(cs); std::vector<indexed_transaction_set::const_iterator> GetSortedScoreWithTopology() const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** /**
* Track locally submitted transactions to periodically retry initial broadcast. * Track locally submitted transactions to periodically retry initial broadcast.