Make getting parents/children a function of the mempool, not a mempool entry
What changed, and why it matters
This commit is a straightforward internal code cleanup in Bitcoin Core. It moves two helper functions—one that finds child transactions and one that finds parent transactions—from being methods on individual mempool entries to being methods on the mempool itself. The behavior is essentially the same; only the code organization and the caller syntax change. There is no indication this fixes a security bug or changes network behavior.
No security action required. Treat as normal refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors CTxMemPoolEntry::GetMemPoolChildrenConst() and GetMemPoolParentsConst() into CTxMemPool::GetChildren() and CTxMemPool::GetParents(). New implementations lock the mempool’s cs mutex and query mapNextTx / GetIter to build vectors of entry references. All call sites in RPC, fuzz tests, and mempool test utilities are updated to call through the pool object. No logic changes affecting consensus, P2P, or mempool policy are visible in the diff.
Changed components
src/txmempool.cppsrc/txmempool.hsrc/rpc/mempool.cppsrc/test/fuzz/package_eval.cppsrc/test/util/txmempool.cppInspect captured patch +39 / −5
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index 7a016335..f07f06f8 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -327,7 +327,7 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
info.pushKV("depends", std::move(depends));
UniValue spent(UniValue::VARR);
- for (const CTxMemPoolEntry& child : e.GetMemPoolChildrenConst()) {
+ for (const CTxMemPoolEntry& child : pool.GetChildren(e)) {
spent.push_back(child.GetTx().GetHash().ToString());
}
diff --git a/src/test/fuzz/package_eval.cpp b/src/test/fuzz/package_eval.cpp
index 50f4c416..3f1eeeb3 100644
--- a/src/test/fuzz/package_eval.cpp
+++ b/src/test/fuzz/package_eval.cpp
@@ -174,7 +174,7 @@ std::optional<COutPoint> GetChildEvictingPrevout(const CTxMemPool& tx_pool)
const auto& entry = *Assert(tx_pool.GetEntry(tx_info.tx->GetHash()));
std::vector<uint32_t> dust_indexes{GetDust(*tx_info.tx, tx_pool.m_opts.dust_relay_feerate)};
if (!dust_indexes.empty()) {
- const auto& children = entry.GetMemPoolChildrenConst();
+ const auto& children = tx_pool.GetChildren(entry);
if (!children.empty()) {
Assert(children.size() == 1);
// Find an input that doesn't spend from parent's txid
diff --git a/src/test/util/txmempool.cpp b/src/test/util/txmempool.cpp
index ffa21a41..e85c496d 100644
--- a/src/test/util/txmempool.cpp
+++ b/src/test/util/txmempool.cpp
@@ -157,7 +157,7 @@ void CheckMempoolEphemeralInvariants(const CTxMemPool& tx_pool)
Assert(entry.GetFee() == 0 && entry.GetModifiedFee() == 0);
// Transaction has single dust; make sure it's swept or will not be mined
- const auto& children = entry.GetMemPoolChildrenConst();
+ const auto& children = tx_pool.GetChildren(entry);
// Multiple children should never happen as non-dust-spending child
// can get mined as package
@@ -199,12 +199,12 @@ void CheckMempoolTRUCInvariants(const CTxMemPool& tx_pool)
if (anc_count > 1) {
Assert(entry.GetTxSize() <= TRUC_CHILD_MAX_VSIZE);
// All TRUC transactions must only have TRUC unconfirmed parents.
- const auto& parents = entry.GetMemPoolParentsConst();
+ const auto& parents = tx_pool.GetParents(entry);
Assert(parents.begin()->get().GetSharedTx()->version == TRUC_VERSION);
}
} else if (anc_count > 1) {
// All non-TRUC transactions must only have non-TRUC unconfirmed parents.
- for (const auto& parent : entry.GetMemPoolParentsConst()) {
+ for (const auto& parent : tx_pool.GetParents(entry)) {
Assert(parent.get().GetSharedTx()->version != TRUC_VERSION);
}
}
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 8ba41e94..fb835b1f 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -54,6 +54,38 @@ bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
return true;
}
+std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> CTxMemPool::GetChildren(const CTxMemPoolEntry& entry) const
+{
+ LOCK(cs);
+ std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> ret;
+ setEntries children;
+ auto iter = mapNextTx.lower_bound(COutPoint(entry.GetTx().GetHash(), 0));
+ for (; iter != mapNextTx.end() && iter->first->hash == entry.GetTx().GetHash(); ++iter) {
+ children.insert(iter->second);
+ }
+ for (const auto& child : children) {
+ ret.emplace_back(*child);
+ }
+ return ret;
+}
+
+std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> CTxMemPool::GetParents(const CTxMemPoolEntry& entry) const
+{
+ LOCK(cs);
+ std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> ret;
+ std::set<Txid> inputs;
+ for (const auto& txin : entry.GetTx().vin) {
+ inputs.insert(txin.prevout.hash);
+ }
+ for (const auto& hash : inputs) {
+ std::optional<txiter> piter = GetIter(hash);
+ if (piter) {
+ ret.emplace_back(**piter);
+ }
+ }
+ return ret;
+}
+
void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<Txid>& vHashesToUpdate)
{
AssertLockHeld(cs);
diff --git a/src/txmempool.h b/src/txmempool.h
index 3c488215..addf3e13 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -289,6 +289,8 @@ public:
int64_t GetDescendantCount(txiter it) const { LOCK(cs); return m_txgraph->GetDescendants(*it, TxGraph::Level::MAIN).size(); }
int64_t GetDescendantCount(const CTxMemPoolEntry &e) const { LOCK(cs); return m_txgraph->GetDescendants(e, TxGraph::Level::MAIN).size(); }
int64_t GetAncestorCount(const CTxMemPoolEntry &e) const { LOCK(cs); return m_txgraph->GetAncestors(e, TxGraph::Level::MAIN).size(); }
+ std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> GetChildren(const CTxMemPoolEntry &entry) const;
+ std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> GetParents(const CTxMemPoolEntry &entry) const;
private:
typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap;
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.