aboutsummaryrefslogtreecommitdiff
path: root/src/txmempool.cpp
diff options
context:
space:
mode:
authorglozow <gloriajzhao@gmail.com>2022-02-21 11:48:10 +0000
committerMurch <murch@murch.one>2023-03-27 17:35:12 -0400
commit56484f0fdc44261e723563f59df886d5acdd851f (patch)
tree354fbe250f28b741424519a6b9118e88dba5317f /src/txmempool.cpp
parent68e484afbbc2e43ad7f2140275cf4e09e45b80ae (diff)
[mempool] find connected mempool entries with GatherClusters(…)
We limit GatherClusters’s result to a maximum of 500 transactions as clusters can be made arbitrarily large by third parties. Co-authored-by: Murch <murch@murch.one>
Diffstat (limited to 'src/txmempool.cpp')
-rw-r--r--src/txmempool.cpp42
1 files changed, 41 insertions, 1 deletions
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 378123ce0f..2bac419f84 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -24,6 +24,7 @@
#include <validationinterface.h>
#include <cmath>
+#include <numeric>
#include <optional>
#include <string_view>
#include <utility>
@@ -898,6 +899,19 @@ CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<uint256>& hashes) c
return ret;
}
+std::vector<CTxMemPool::txiter> CTxMemPool::GetIterVec(const std::vector<uint256>& txids) const
+{
+ AssertLockHeld(cs);
+ std::vector<txiter> ret;
+ ret.reserve(txids.size());
+ for (const auto& txid : txids) {
+ const auto it{GetIter(txid)};
+ if (!it) return {};
+ ret.push_back(*it);
+ }
+ return ret;
+}
+
bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
{
for (unsigned int i = 0; i < tx.vin.size(); i++)
@@ -1127,7 +1141,6 @@ void CTxMemPool::SetLoadTried(bool load_tried)
m_load_tried = load_tried;
}
-
std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept
{
switch (r) {
@@ -1140,3 +1153,30 @@ std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept
}
assert(false);
}
+
+std::vector<CTxMemPool::txiter> CTxMemPool::GatherClusters(const std::vector<uint256>& txids) const
+{
+ AssertLockHeld(cs);
+ std::vector<txiter> clustered_txs{GetIterVec(txids)};
+ // Use epoch: visiting an entry means we have added it to the clustered_txs vector. It does not
+ // necessarily mean the entry has been processed.
+ WITH_FRESH_EPOCH(m_epoch);
+ for (const auto& it : clustered_txs) {
+ visited(it);
+ }
+ // i = index of where the list of entries to process starts
+ for (size_t i{0}; i < clustered_txs.size(); ++i) {
+ // DoS protection: if there are 500 or more entries to process, just quit.
+ if (clustered_txs.size() > 500) return {};
+ const txiter& tx_iter = clustered_txs.at(i);
+ for (const auto& entries : {tx_iter->GetMemPoolParentsConst(), tx_iter->GetMemPoolChildrenConst()}) {
+ for (const CTxMemPoolEntry& entry : entries) {
+ const auto entry_it = mapTx.iterator_to(entry);
+ if (!visited(entry_it)) {
+ clustered_txs.push_back(entry_it);
+ }
+ }
+ }
+ }
+ return clustered_txs;
+}