Rework CTxMemPool::GetChildren() to not use epochs

This is likely slightly slower, but this was the last place we were using
epochs instead of sets to deduplicate, and this is only used by the RPC code
and in tests, and should not be CPU-performance critical. Eliminating this
allows us to save 8 bytes in CTxMemPoolEntry.

Co-Authored-By: Pieter Wuille <bitcoin-dev@wuille.net>
This commit is contained in:
Suhas Daftuar 2025-11-29 14:02:11 -05:00 committed by Pieter Wuille
parent 7b48b09b7f
commit 1a8494d16c
3 changed files with 9 additions and 29 deletions

View File

@ -12,7 +12,6 @@
#include <policy/settings.h>
#include <primitives/transaction.h>
#include <txgraph.h>
#include <util/epochguard.h>
#include <util/overflow.h>
#include <chrono>
@ -138,7 +137,6 @@ public:
bool GetSpendsCoinbase() const { return spendsCoinbase; }
mutable size_t idx_randomized; //!< Index in mempool's txns_randomized
mutable Epoch::Marker m_epoch_marker; //!< epoch when last touched, useful for graph algorithms
};
using CTxMemPoolEntryRef = CTxMemPoolEntry::CTxMemPoolEntryRef;

View File

@ -56,15 +56,18 @@ bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> CTxMemPool::GetChildren(const CTxMemPoolEntry& entry) const
{
LOCK(cs);
std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> ret;
WITH_FRESH_EPOCH(m_epoch);
auto iter = mapNextTx.lower_bound(COutPoint(entry.GetTx().GetHash(), 0));
for (; iter != mapNextTx.end() && iter->first->hash == entry.GetTx().GetHash(); ++iter) {
if (!visited(iter->second)) {
const auto& hash = entry.GetTx().GetHash();
{
LOCK(cs);
auto iter = mapNextTx.lower_bound(COutPoint(hash, 0));
for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) {
ret.emplace_back(*(iter->second));
}
}
std::ranges::sort(ret, CompareIteratorByHash{});
auto removed = std::ranges::unique(ret, [](auto& a, auto& b) noexcept { return &a.get() == &b.get(); });
ret.erase(removed.begin(), removed.end());
return ret;
}

View File

@ -20,7 +20,6 @@
#include <primitives/transaction_identifier.h>
#include <sync.h>
#include <txgraph.h>
#include <util/epochguard.h>
#include <util/feefrac.h>
#include <util/hasher.h>
#include <util/result.h>
@ -197,7 +196,6 @@ protected:
mutable int64_t lastRollingFeeUpdate GUARDED_BY(cs){GetTime()};
mutable bool blockSinceLastRollingFeeBump GUARDED_BY(cs){false};
mutable double rollingMinimumFeeRate GUARDED_BY(cs){0}; //!< minimum fee to get into the pool, decreases exponentially
mutable Epoch m_epoch GUARDED_BY(cs){};
// In-memory counter for external mempool tracking purposes.
// This number is incremented once every time a transaction
@ -394,7 +392,7 @@ public:
* @param[in] vHashesToUpdate The set of txids from the
* disconnected block that have been accepted back into the mempool.
*/
void UpdateTransactionsFromBlock(const std::vector<Txid>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch);
void UpdateTransactionsFromBlock(const std::vector<Txid>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
std::vector<FeePerWeight> GetFeerateDiagram() const EXCLUSIVE_LOCKS_REQUIRED(cs);
FeePerWeight GetMainChunkFeerate(const CTxMemPoolEntry& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs) {
@ -592,25 +590,6 @@ private:
/* Removal from the mempool also triggers removal of the entry's Ref from txgraph. */
void removeUnchecked(txiter entry, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
/** visited marks a CTxMemPoolEntry as having been traversed
* during the lifetime of the most recently created Epoch::Guard
* and returns false if we are the first visitor, true otherwise.
*
* An Epoch::Guard must be held when visited is called or an assert will be
* triggered.
*
*/
bool visited(const txiter it) const EXCLUSIVE_LOCKS_REQUIRED(cs, m_epoch)
{
return m_epoch.visited(it->m_epoch_marker);
}
bool visited(std::optional<txiter> it) const EXCLUSIVE_LOCKS_REQUIRED(cs, m_epoch)
{
assert(m_epoch.guarded()); // verify guard even when it==nullopt
return !it || visited(*it);
}
/*
* CTxMemPool::ChangeSet:
*