I'm not sure this is the right data structure here. I think we can do this more cleanly with a std::map<Wtxid, size_t> and populate it below in the
for (size_t i = 0; i < cmpctblock.prefilledtxn.size(); i++) { loop. Instead of calling pool->exists for each prefill (which takes the pool lock each time), we can take call GetIter after we take the pool lock later. This lets us avoid sorting the vector as well.
<details><summary>A quick example of how it could look</summary>
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index e2522f8781..7765353da1 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -16,6 +16,7 @@
#include <util/log.h>
#include <validation.h>
+#include <map>
#include <unordered_map>
CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, uint64_t nonce)
@@ -70,21 +71,9 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
header = cmpctblock.header;
txn_available.resize(cmpctblock.BlockTxCount());
- std::vector<Wtxid> extra_wtxids{};
-
- bool debug_log = util::log::ShouldDebugLog(BCLog::CMPCTBLOCK);
-
- if (debug_log) {
- prefilled_count = cmpctblock.prefilledtxn.size();
-
- // A sorted vec of extra_txn's for cheaply checking if prefills
- // were redundant with the extrapool.
- for (const auto& [id, tx] : extra_txn) {
- extra_wtxids.push_back(id);
- }
- std::sort(extra_wtxids.begin(), extra_wtxids.end());
- }
-
+ const bool debug_log{util::log::ShouldDebugLog(BCLog::CMPCTBLOCK)};
+ // Prefills not already in the mempool, used to check extra-pool redundancy.
+ std::map<Wtxid, size_t> leftover_prefills;
int32_t lastprefilledindex = -1;
for (size_t i = 0; i < cmpctblock.prefilledtxn.size(); i++) {
@@ -102,20 +91,14 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
}
if (debug_log) {
- size_t tx_size = cmpctblock.prefilledtxn[i].tx->ComputeTotalSize();
+ const CTransactionRef& tx{cmpctblock.prefilledtxn[i].tx};
+ const size_t tx_size{tx->ComputeTotalSize()};
prefilled_size += tx_size;
-
- auto tx_wtxid = cmpctblock.prefilledtxn[i].tx->GetWitnessHash();
- if (pool->exists(tx_wtxid)) {
- redundant_prefilled_mp_count++;
- redundant_prefilled_mp_size += tx_size;
- } else if (std::binary_search(extra_wtxids.begin(), extra_wtxids.end(), tx_wtxid)) {
- redundant_prefilled_ep_count++;
- redundant_prefilled_ep_size += tx_size;
- }
+ leftover_prefills.emplace(tx->GetWitnessHash(), tx_size);
}
txn_available[lastprefilledindex] = cmpctblock.prefilledtxn[i].tx;
}
+ if (debug_log) prefilled_count = cmpctblock.prefilledtxn.size();
// Calculate map of txids -> positions and check mempool to see what we have (or don't)
// Because well-formed cmpctblock messages will have a (relatively) uniform distribution
@@ -148,6 +131,17 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
size_t available_count = 0;
{
LOCK(pool->cs);
+ if (debug_log) {
+ for (auto it{leftover_prefills.begin()}; it != leftover_prefills.end();) {
+ if (pool->GetIter(it->first)) {
+ ++redundant_prefilled_mp_count;
+ redundant_prefilled_mp_size += it->second;
+ it = leftover_prefills.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
for (const auto& [wtxid, txit] : pool->txns_randomized) {
uint64_t shortid = cmpctblock.GetShortID(wtxid);
std::unordered_map<uint64_t, uint16_t>::iterator idit = shorttxids.find(shortid);
@@ -201,7 +195,16 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
break;
}
- if (util::log::ShouldDebugLog(BCLog::CMPCTBLOCK)) {
+ if (debug_log) {
+ for (const auto& [id, tx] : extra_txn) {
+ if (!tx) continue;
+ const auto it{leftover_prefills.find(id)};
+ if (it == leftover_prefills.end()) continue;
+ ++redundant_prefilled_ep_count;
+ redundant_prefilled_ep_size += it->second;
+ leftover_prefills.erase(it);
+ }
+
Assume(txn_available.size() == tx_source.size());
for (size_t i = 0; i < txn_available.size(); i++) {
switch (tx_source[i]) {
</details>