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

Code before:
    child.vin.resize(1);

    bilingual_str error;
    CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
    Assert(error.empty());

    // Add a bunch of parent-child pairs to the mempool, and remember them.
    std::vector<CTransaction> mempool_txs;
    size_t iter{0};

    // Keep track of the total vsize of CTxMemPoolEntry's being added to the mempool to avoid overflow
    // Add replacement_vsize since this is added to new diagram during RBF check
    std::optional<CMutableTransaction> replacement_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS);
    if (!replacement_tx) {
        return;
    }
    assert(iter <= g_outpoints.size());
    replacement_tx->vin.resize(1);
    replacement_tx->vin[0].prevout = g_outpoints[iter++];
    CTransaction replacement_tx_final{*replacement_tx};
    auto replacement_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, replacement_tx_final);
    int32_t replacement_vsize = replacement_entry.GetTxSize();
    int64_t running_vsize_total{replacement_vsize};

    LOCK2(cs_main, pool.cs);

    LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)
    {
        // Make sure txns only have one input, and that a unique input is given to avoid circular references
        CMutableTransaction parent;
        assert(iter <= g_outpoints.size());
        parent.vin.resize(1);
        parent.vin[0].prevout = g_outpoints[iter++];
        parent.vout.emplace_back(0, CScript());

        mempool_txs.emplace_back(parent);
        const auto parent_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back());
        running_vsize_total += parent_entry.GetTxSize();
        if (running_vsize_total > std::numeric_limits<int32_t>::max()) {
            // We aren't adding this final tx to mempool, so we don't want to conflict with it
            mempool_txs.pop_back();
            break;
        }
        assert(!pool.GetIter(parent_entry.GetTx().GetHash()));
        AddToMempool(pool, parent_entry);
        if (fuzzed_data_provider.ConsumeBool()) {
            child.vin[0].prevout = COutPoint{mempool_txs.back().GetHash(), 0};
        }
        mempool_txs.emplace_back(child);
        const auto child_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back());
        running_vsize_total += child_entry.GetTxSize();

Review comment (suggestion):
Nit: I find it a bit unintuitive to use a loop variable inside the condition here, and would prefer:

```c++
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS) {
    if (iter >= NUM_ITERS) break;
    ...
```

Code after:
    child.vin.resize(1);

    bilingual_str error;
    CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
    Assert(error.empty());

    // Add a bunch of parent-child pairs to the mempool, and remember them.
    std::vector<CTransaction> mempool_txs;
    uint32_t iter{0};

    // Keep track of the total vsize of CTxMemPoolEntry's being added to the mempool to avoid overflow
    // Add replacement_vsize since this is added to new diagram during RBF check
    std::optional<CMutableTransaction> replacement_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS);
    if (!replacement_tx) {
        return;
    }
    replacement_tx->vin.resize(1);
    replacement_tx->vin[0].prevout = g_outpoints.at(iter++);
    CTransaction replacement_tx_final{*replacement_tx};
    auto replacement_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, replacement_tx_final);
    int32_t replacement_vsize = replacement_entry.GetTxSize();
    int64_t running_vsize_total{replacement_vsize};

    LOCK2(cs_main, pool.cs);

    while (fuzzed_data_provider.ConsumeBool()) {
        if (iter >= NUM_ITERS) break;

        // Make sure txns only have one input, and that a unique input is given to avoid circular references
        CMutableTransaction parent;
        parent.vin.resize(1);
        parent.vin[0].prevout = g_outpoints.at(iter++);
        parent.vout.emplace_back(0, CScript());

        mempool_txs.emplace_back(parent);
        const auto parent_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back());
        running_vsize_total += parent_entry.GetTxSize();
        if (running_vsize_total > std::numeric_limits<int32_t>::max()) {
            // We aren't adding this final tx to mempool, so we don't want to conflict with it
            mempool_txs.pop_back();
            break;
        }
        assert(!pool.GetIter(parent_entry.GetTx().GetHash()));
        AddToMempool(pool, parent_entry);
        if (fuzzed_data_provider.ConsumeBool()) {
            child.vin[0].prevout = COutPoint{mempool_txs.back().GetHash(), 0};
        }
        mempool_txs.emplace_back(child);
        const auto child_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back());
        running_vsize_total += child_entry.GetTxSize();
        if (running_vsize_total > std::numeric_limits<int32_t>::max()) {