From 1a8494d16c7b1c21dec384438c18ac08a469bb61 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Sat, 29 Nov 2025 14:02:11 -0500 Subject: [PATCH] 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 --- src/kernel/mempool_entry.h | 2 -- src/txmempool.cpp | 13 ++++++++----- src/txmempool.h | 23 +---------------------- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/src/kernel/mempool_entry.h b/src/kernel/mempool_entry.h index 3053a77c3e6..58824f7a80c 100644 --- a/src/kernel/mempool_entry.h +++ b/src/kernel/mempool_entry.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -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; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 4dc692bfd86..2486270bc0d 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -56,15 +56,18 @@ bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp) std::vector CTxMemPool::GetChildren(const CTxMemPoolEntry& entry) const { - LOCK(cs); std::vector 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; } diff --git a/src/txmempool.h b/src/txmempool.h index 996a1fe081e..9feeee3e31f 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -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& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch); + void UpdateTransactionsFromBlock(const std::vector& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); std::vector 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 it) const EXCLUSIVE_LOCKS_REQUIRED(cs, m_epoch) - { - assert(m_epoch.guarded()); // verify guard even when it==nullopt - return !it || visited(*it); - } - /* * CTxMemPool::ChangeSet: *