Reimplement GetTransactionAncestry() to not rely on cached data
What changed, and why it matters
This commit changes how Bitcoin Core counts a transaction's ancestors in the memory pool (mempool). Previously it read pre-calculated cached numbers stored with each transaction; now it recalculates them on demand by walking the transaction graph. The change is described by the project as a refactoring step to remove cached ancestor data from mempool entries. There is no direct evidence in the commit that this fixes a security vulnerability.
Treat as a routine refactor. Reviewers may want to verify that CalculateAncestorData() produces identical results to the cached values under concurrency and graph-update edge cases, since any divergence could affect fee-based transaction selection or RPC results. No immediate security response is indicated by the supplied materials.
Security signals we found
Refactor of mempool ancestor-fee calculation, which affects transaction-selection and fee-estimation logic
Removal of dependency on cached ancestor statistics
No explicit security claim, CVE, bug fix, or vulnerability description in commit message or diff
Evidence from the diff
GetTransactionAncestry() no longer uses CTxMemPoolEntry’s cached ancestor count, size, and modified-fee fields. A new private helper CalculateAncestorData() uses m_txgraph->GetAncestors() to dynamically collect ancestors and sum their sizes and modified fees. The public API and output values are intended to remain equivalent. The commit is a small, localized refactor (+22/-3 lines) in src/txmempool.cpp/h.
Changed components
src/txmempool.cppsrc/txmempool.hCTxMemPool::GetTransactionAncestryCTxMemPool::CalculateAncestorDatamempool ancestor/descendant statisticsInspect captured patch +22 / −3
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 326ff79f..85feb8b2 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -1217,15 +1217,31 @@ uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
return maximum;
}
+std::tuple<size_t, size_t, CAmount> CTxMemPool::CalculateAncestorData(const CTxMemPoolEntry& entry) const
+{
+ auto ancestors = m_txgraph->GetAncestors(entry, TxGraph::Level::MAIN);
+
+ size_t ancestor_count = ancestors.size();
+ size_t ancestor_size = 0;
+ CAmount ancestor_fees = 0;
+ for (auto tx: ancestors) {
+ const CTxMemPoolEntry& anc = static_cast<const CTxMemPoolEntry&>(*tx);
+ ancestor_size += anc.GetTxSize();
+ ancestor_fees += anc.GetModifiedFee();
+ }
+ return {ancestor_count, ancestor_size, ancestor_fees};
+}
+
void CTxMemPool::GetTransactionAncestry(const Txid& txid, size_t& ancestors, size_t& descendants, size_t* const ancestorsize, CAmount* const ancestorfees) const {
LOCK(cs);
auto it = mapTx.find(txid);
ancestors = descendants = 0;
if (it != mapTx.end()) {
- ancestors = it->GetCountWithAncestors();
- if (ancestorsize) *ancestorsize = it->GetSizeWithAncestors();
- if (ancestorfees) *ancestorfees = it->GetModFeesWithAncestors();
+ auto [ancestor_count, ancestor_size, ancestor_fees] = CalculateAncestorData(*it);
descendants = CalculateDescendantMaximum(it);
+ ancestors = ancestor_count;
+ if (ancestorsize) *ancestorsize = ancestor_size;
+ if (ancestorfees) *ancestorfees = ancestor_fees;
}
}
diff --git a/src/txmempool.h b/src/txmempool.h
index fb2a4669..df4d50a4 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -285,6 +285,9 @@ public:
using Limits = kernel::MemPoolLimits;
uint64_t CalculateDescendantMaximum(txiter entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+
+ std::tuple<size_t, size_t, CAmount> CalculateAncestorData(const CTxMemPoolEntry& entry) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+
private:
typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap;
Why this scored 18/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.