Allow moving CTxMemPoolEntry objects, disallow copying
What changed, and why it matters
This is a small internal code-quality change in Bitcoin Core's memory pool (mempool) data structure. It removes an explicit-copy helper and makes the object movable instead of copyable. There is no direct evidence this fixes an exploitable security bug; it is best understood as a defensive cleanup that prevents accidental expensive or incorrect copying of mempool entries.
Treat as a routine defensive/maintenance patch. Review downstream mempool code for any remaining reliance on CTxMemPoolEntry copying that may have been hidden by the ExplicitCopyTag mechanism, but no urgent security action is indicated.
Security signals we found
Disallows implicit/explicit copying of CTxMemPoolEntry, which may prevent accidental double-accounting or stale-state bugs in mempool logic
Enables move semantics, reducing risk of performance-related resource exhaustion from large object copies
No direct vulnerability pattern (use-after-free, overflow, auth bypass) is present in the diff
Evidence from the diff
The commit modifies CTxMemPoolEntry so that copy construction is deleted (previously defaulted and accessible only through an ExplicitCopyTag), move construction is defaulted (previously deleted), and the ExplicitCopyTag/ExplicitCopy mechanism is removed. A fuzz test is updated to use push_back with a temporary instead of emplace_back with the tag. The change enforces that mempool entries are never silently copied and can be moved efficiently.
Changed components
src/kernel/mempool_entry.hsrc/test/fuzz/policy_estimator.cppInspect captured patch +3 / −9
diff --git a/src/kernel/mempool_entry.h b/src/kernel/mempool_entry.h
index 51a1f266..40aa77b5 100644
--- a/src/kernel/mempool_entry.h
+++ b/src/kernel/mempool_entry.h
@@ -71,10 +71,7 @@ public:
typedef std::set<CTxMemPoolEntryRef, CompareIteratorByHash> Children;
private:
- CTxMemPoolEntry(const CTxMemPoolEntry&) = default;
- struct ExplicitCopyTag {
- explicit ExplicitCopyTag() = default;
- };
+ CTxMemPoolEntry(const CTxMemPoolEntry&) = delete;
const CTransactionRef tx;
mutable Parents m_parents;
@@ -127,13 +124,10 @@ public:
nModFeesWithAncestors{nFee},
nSigOpCostWithAncestors{sigOpCost} {}
- CTxMemPoolEntry(ExplicitCopyTag, const CTxMemPoolEntry& entry) : CTxMemPoolEntry(entry) {}
CTxMemPoolEntry& operator=(const CTxMemPoolEntry&) = delete;
- CTxMemPoolEntry(CTxMemPoolEntry&&) = delete;
+ CTxMemPoolEntry(CTxMemPoolEntry&&) = default;
CTxMemPoolEntry& operator=(CTxMemPoolEntry&&) = delete;
- static constexpr ExplicitCopyTag ExplicitCopy{};
-
const CTransaction& GetTx() const { return *this->tx; }
CTransactionRef GetSharedTx() const { return this->tx; }
const CAmount& GetFee() const { return nFee; }
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 8455a232..cfd50cf8 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -74,7 +74,7 @@ FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator)
break;
}
const CTransaction tx{*mtx};
- mempool_entries.emplace_back(CTxMemPoolEntry::ExplicitCopy, ConsumeTxMemPoolEntry(fuzzed_data_provider, tx, current_height));
+ mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx, current_height));
}
std::vector<RemovedMempoolTransactionInfo> txs;
txs.reserve(mempool_entries.size());
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.