If you think unordered_map is indeed faster (I'll measure it once my benchmarking servers will be available), we could change the std::set instances as well - and given that they're array based, we might as well pre-allocate them.
<details>
<summary>Details</summary>
diff --git a/src/test/fuzz/package_eval.cpp b/src/test/fuzz/package_eval.cpp
--- a/src/test/fuzz/package_eval.cpp (revision 147655098edde6feffbbe2c601d5874a7d3a3c5c)
+++ b/src/test/fuzz/package_eval.cpp (date 1742211475064)
@@ -57,9 +57,9 @@
}
struct OutpointsUpdater final : public CValidationInterface {
- std::set<COutPoint>& m_mempool_outpoints;
+ std::unordered_set<COutPoint, SaltedOutpointHasher>& m_mempool_outpoints;
- explicit OutpointsUpdater(std::set<COutPoint>& r)
+ explicit OutpointsUpdater(std::unordered_set<COutPoint, SaltedOutpointHasher>& r)
: m_mempool_outpoints{r} {}
void TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t /* mempool_sequence */) override
@@ -67,6 +67,7 @@
// for coins spent we always want to be able to rbf so they're not removed
// outputs from this tx can now be spent
+ m_mempool_outpoints.reserve(m_mempool_outpoints.size() + tx.info.m_tx->vout.size());
for (uint32_t index{0}; index < tx.info.m_tx->vout.size(); ++index) {
m_mempool_outpoints.insert(COutPoint{tx.info.m_tx->GetHash(), index});
}
@@ -75,6 +76,7 @@
void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t /* mempool_sequence */) override
{
// outpoints spent by this tx are now available
+ m_mempool_outpoints.reserve(m_mempool_outpoints.size() + tx->vin.size());
for (const auto& input : tx->vin) {
// Could already exist if this was a replacement
m_mempool_outpoints.insert(input.prevout);
@@ -200,8 +202,10 @@
MockTime(fuzzed_data_provider, chainstate);
// All RBF-spendable outpoints outside of the unsubmitted package
- std::set<COutPoint> mempool_outpoints;
+ std::unordered_set<COutPoint, SaltedOutpointHasher> mempool_outpoints;
+ mempool_outpoints.reserve(g_outpoints_coinbase_init_mature.size());
std::unordered_map<COutPoint, CAmount, SaltedOutpointHasher> outpoints_value;
+ outpoints_value.reserve(g_outpoints_coinbase_init_mature.size());
for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
Assert(mempool_outpoints.insert(outpoint).second);
outpoints_value[outpoint] = 50 * COIN;
@@ -226,8 +230,10 @@
// Make small packages
const auto num_txs = outpoint_to_rbf ? 1 : fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4);
+ txs.reserve(num_txs);
- std::set<COutPoint> package_outpoints;
+ std::unordered_set<COutPoint, SaltedOutpointHasher> package_outpoints;
+ package_outpoints.reserve((num_txs - 1) * 4);
while (txs.size() < num_txs) {
// Create transaction to add to the mempool
txs.emplace_back([&] {
@@ -355,8 +361,10 @@
MockTime(fuzzed_data_provider, chainstate);
// All RBF-spendable outpoints outside of the unsubmitted package
- std::set<COutPoint> mempool_outpoints;
+ std::unordered_set<COutPoint, SaltedOutpointHasher> mempool_outpoints;
+ mempool_outpoints.reserve(g_outpoints_coinbase_init_mature.size());
std::unordered_map<COutPoint, CAmount, SaltedOutpointHasher> outpoints_value;
+ outpoints_value.reserve(g_outpoints_coinbase_init_mature.size());
for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
Assert(mempool_outpoints.insert(outpoint).second);
outpoints_value[outpoint] = 50 * COIN;
@@ -378,7 +386,9 @@
// Make packages of 1-to-26 transactions
const auto num_txs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 26);
- std::set<COutPoint> package_outpoints;
+ txs.reserve(num_txs);
+ std::unordered_set<COutPoint, SaltedOutpointHasher> package_outpoints;
+ package_outpoints.reserve((num_txs - 1) * 4);
while (txs.size() < num_txs) {
// Create transaction to add to the mempool
txs.emplace_back([&] {
</details>