Repository: bitcoin/bitcoin
File: src/test/fuzz/tx_pool.cpp (C++)

Code before:
    auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};

    MockTime(fuzzed_data_provider, chainstate);

    // All RBF-spendable outpoints
    std::set<COutPoint> outpoints_rbf;
    // All outpoints counting toward the total supply (subset of outpoints_rbf)
    std::set<COutPoint> outpoints_supply;
    for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
        Assert(outpoints_supply.insert(outpoint).second);
    }
    outpoints_rbf = outpoints_supply;

    // The sum of the values of all spendable outpoints
    constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};

    SetMempoolConstraints(*node.args, fuzzed_data_provider);
    auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
    while (true) {
        if (tx_pool_) {
            break;
        } else {
            // Ensure this harness is updated when additional mempool construction failure paths are introduced
            assert(util::ErrorString(tx_pool_).original.starts_with("-maxmempool must be at least"));
            SetMempoolConstraints(*node.args, fuzzed_data_provider);
            tx_pool_ =  MakeMempool(fuzzed_data_provider, node);
        }
    }

    MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.value().get());

    chainstate.SetMempool(&tx_pool);

    // Helper to query an amount
    const CCoinsViewMemPool amount_view{WITH_LOCK(::cs_main, return &chainstate.CoinsTip()), tx_pool};
    const auto GetAmount = [&](const COutPoint& outpoint) {
        Coin c;
        Assert(amount_view.GetCoin(outpoint, c));
        return c.out.nValue;
    };

    LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
    {
        {
            // Total supply is the mempool fee + all outpoints
            CAmount supply_now{WITH_LOCK(tx_pool.cs, return tx_pool.GetTotalFee())};
            for (const auto& op : outpoints_supply) {
                supply_now += GetAmount(op);
            }
            Assert(supply_now == SUPPLY_TOTAL);
        }

Review comment (bug):
Since we're resetting all constraints on every loop, is this not overly verbose? (+below)

<details>
<summary>git diff on 364456f659</summary>

```diff
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 1400fadea0..7ddc45c4b4 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -200,17 +200,10 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
     // The sum of the values of all spendable outpoints
     constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
 
-    SetMempoolConstraints(*node.args, fuzzed_data_provider);
-    auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
-    while (true) {
-        if (tx_pool_) {
-            break;
-        } else {
-            // Ensure this harness is updated when additional mempool construction failure paths are introduced
-            assert(util::ErrorString(tx_pool_).original.starts_with("-maxmempool must be at least"));
-            SetMempoolConstraints(*node.args, fuzzed_data_provider);
-            tx_pool_ =  MakeMempool(fuzzed_data_provider, node);
-        }
+    util::Result<std::unique_ptr<CTxMemPool>> tx_pool_;
+    while (!tx_pool_) {
+        SetMempoolConstraints(*node.args, fuzzed_data_provider);
+        tx_pool_ = MakeMempool(fuzzed_data_provider, node);
     }
 
     MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.value().get());

```
</details>

Code after:
FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
{
    FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
    const auto& node = g_setup->m_node;
    auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};

    MockTime(fuzzed_data_provider, chainstate);

    // All RBF-spendable outpoints
    std::set<COutPoint> outpoints_rbf;
    // All outpoints counting toward the total supply (subset of outpoints_rbf)
    std::set<COutPoint> outpoints_supply;
    for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
        Assert(outpoints_supply.insert(outpoint).second);
    }
    outpoints_rbf = outpoints_supply;

    // The sum of the values of all spendable outpoints
    constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};

    SetMempoolConstraints(*node.args, fuzzed_data_provider);
    auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
    MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());

    chainstate.SetMempool(&tx_pool);

    // Helper to query an amount
    const CCoinsViewMemPool amount_view{WITH_LOCK(::cs_main, return &chainstate.CoinsTip()), tx_pool};
    const auto GetAmount = [&](const COutPoint& outpoint) {
        Coin c;
        Assert(amount_view.GetCoin(outpoint, c));
        return c.out.nValue;
    };

    LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
    {
        {
            // Total supply is the mempool fee + all outpoints
            CAmount supply_now{WITH_LOCK(tx_pool.cs, return tx_pool.GetTotalFee())};
            for (const auto& op : outpoints_supply) {
                supply_now += GetAmount(op);
            }
            Assert(supply_now == SUPPLY_TOTAL);
        }
        Assert(!outpoints_supply.empty());

        // Create transaction to add to the mempool
        const CTransactionRef tx = [&] {
            CMutableTransaction tx_mut;
            tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? 3 : CTransaction::CURRENT_VERSION;
            tx_mut.nLockTime = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();