mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
[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>
This commit is contained in:
parent
68e484afbb
commit
56484f0fdc
2 changed files with 55 additions and 2 deletions
|
@ -24,6 +24,7 @@
|
||||||
#include <validationinterface.h>
|
#include <validationinterface.h>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <numeric>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@ -898,6 +899,19 @@ CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<uint256>& hashes) c
|
||||||
return ret;
|
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
|
bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
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;
|
m_load_tried = load_tried;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept
|
std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept
|
||||||
{
|
{
|
||||||
switch (r) {
|
switch (r) {
|
||||||
|
@ -1140,3 +1153,30 @@ std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept
|
||||||
}
|
}
|
||||||
assert(false);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -522,9 +522,16 @@ public:
|
||||||
/** Returns an iterator to the given hash, if found */
|
/** Returns an iterator to the given hash, if found */
|
||||||
std::optional<txiter> GetIter(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
std::optional<txiter> GetIter(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||||
|
|
||||||
/** Translate a set of hashes into a set of pool iterators to avoid repeated lookups */
|
/** Translate a set of hashes into a set of pool iterators to avoid repeated lookups.
|
||||||
|
* Does not require that all of the hashes correspond to actual transactions in the mempool,
|
||||||
|
* only returns the ones that exist. */
|
||||||
setEntries GetIterSet(const std::set<uint256>& hashes) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
setEntries GetIterSet(const std::set<uint256>& hashes) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||||
|
|
||||||
|
/** Translate a list of hashes into a list of mempool iterators to avoid repeated lookups.
|
||||||
|
* The nth element in txids becomes the nth element in the returned vector. If any of the txids
|
||||||
|
* don't actually exist in the mempool, returns an empty vector. */
|
||||||
|
std::vector<txiter> GetIterVec(const std::vector<uint256>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||||
|
|
||||||
/** Remove a set of transactions from the mempool.
|
/** Remove a set of transactions from the mempool.
|
||||||
* If a transaction is in this set, then all in-mempool descendants must
|
* If a transaction is in this set, then all in-mempool descendants must
|
||||||
* also be in the set, unless this transaction is being removed for being
|
* also be in the set, unless this transaction is being removed for being
|
||||||
|
@ -585,6 +592,12 @@ public:
|
||||||
const Limits& limits,
|
const Limits& limits,
|
||||||
bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||||
|
|
||||||
|
/** Collect the entire cluster of connected transactions for each transaction in txids.
|
||||||
|
* All txids must correspond to transaction entries in the mempool, otherwise this returns an
|
||||||
|
* empty vector. This call will also exit early and return an empty vector if it collects 500 or
|
||||||
|
* more transactions as a DoS protection. */
|
||||||
|
std::vector<txiter> GatherClusters(const std::vector<uint256>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||||
|
|
||||||
/** Calculate all in-mempool ancestors of a set of transactions not already in the mempool and
|
/** Calculate all in-mempool ancestors of a set of transactions not already in the mempool and
|
||||||
* check ancestor and descendant limits. Heuristics are used to estimate the ancestor and
|
* check ancestor and descendant limits. Heuristics are used to estimate the ancestor and
|
||||||
* descendant count of all entries if the package were to be added to the mempool. The limits
|
* descendant count of all entries if the package were to be added to the mempool. The limits
|
||||||
|
|
Loading…
Add table
Reference in a new issue