txmempool: Add ExtractBestByMiningScoreWithTopology

Add a method for (partially) sorting a batch of transactions (specified as
a std::vector of wtxids) per mempool order, designed for transaction relay.
This commit is contained in:
Anthony Towns
2026-02-19 19:36:25 +10:00
parent 026f70e05f
commit 6cfc65d210
2 changed files with 71 additions and 0 deletions

View File

@@ -553,6 +553,64 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
assert(innerUsage == cachedInnerUsage);
}
std::vector<CTxMemPool::txiter> CTxMemPool::ExtractBestByMiningScoreWithTopology(std::vector<Wtxid>& wtxids, size_t n_to_sort) const
{
/* This function takes a vector of `wtxids`, and returns the
* best mempool entries corresponding to those `wtxids` (by mining
* score/topology). It updates the input `wtxids` so that multiple
* calls with the same vector will drain that vector to empty.
*
* It operates under the following constraints:
* - wtxids that do not correspond to a mempool entry are dropped
* - the return vector contains no duplicates, either with itself
* or with the updated `wtxids` input.
* - the return vector will have `n_to_sort` entries (or `wtxids`
will become empty).
* - the `wtxids` vector will be reduced by at least `n_to_sort`
* entries (or will become empty).
*/
auto cmp = [&](const auto& a, const auto& b) EXCLUSIVE_LOCKS_REQUIRED(cs) noexcept { return m_txgraph->CompareMainOrder(*a, *b) < 0; };
std::vector<txiter> res;
n_to_sort = std::min(wtxids.size(), n_to_sort);
if (n_to_sort > 0) {
res.reserve(wtxids.size());
std::sort(wtxids.begin(), wtxids.end());
for (auto it = wtxids.begin(); it != wtxids.end(); ++it) {
// skip duplicates
auto itnext = it + 1;
if (itnext != wtxids.end() && *it == *itnext) continue;
if (auto i{GetIter(*it)}; i.has_value()) {
res.push_back(i.value());
}
}
wtxids.clear();
if (!res.empty()) {
auto begin = res.begin();
auto end = res.end();
auto middle = end;
if (n_to_sort >= res.size()) {
// use regular sort when sorting everything
std::sort(begin, end, cmp);
} else {
middle = begin + n_to_sort;
std::partial_sort(begin, middle, end, cmp);
}
auto it = middle;
while (it != end) {
wtxids.push_back((*it)->GetTx().GetWitnessHash());
++it;
}
res.erase(middle, end);
}
}
return res;
}
bool CTxMemPool::CompareMiningScoreWithTopology(const Wtxid& hasha, const Wtxid& hashb) const
{
/* Return `true` if hasha should be considered sooner than hashb, namely when: