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

Code before:
    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
        std::optional<CMutableTransaction> parent = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS);
        if (!parent) {
            return;
        }
        assert(iter <= g_outpoints.size());
        parent->vin.resize(1);
        parent->vin[0].prevout = g_outpoints[iter++];

        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;
        }
        pool.addUnchecked(parent_entry);
        if (fuzzed_data_provider.ConsumeBool() && !child->vin.empty()) {
            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()) {
            // We aren't adding this final tx to mempool, so we don't want to conflict with it
            mempool_txs.pop_back();
            break;
        }
        pool.addUnchecked(child_entry);

        if (fuzzed_data_provider.ConsumeBool()) {
            pool.PrioritiseTransaction(mempool_txs.back().GetHash().ToUint256(), fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(-100000, 100000));
        }
    }

    // Pick some transactions at random to be the direct conflicts
    CTxMemPool::setEntries direct_conflicts;
    for (auto& tx : mempool_txs) {
        if (fuzzed_data_provider.ConsumeBool()) {
            direct_conflicts.insert(*pool.GetIter(tx.GetHash()));
        }
    }

    // Calculate all conflicts:

Review comment (suggestion):
Good that you removed the unnecessary `vin.empty()` check.

Until the first time `ConsumeBool()` returns true here, we'll be using a `child` with a default-initialized `vin[0]`. This was true before the change as well. Does some later code hook up default-constructed `CTxIn` to coinbase transactions or something?

It seems unnecessary to have created a `parent` at all if the `ConsumeBool()` returns false. But I guess it's good to test adding unrelated transactions between each `child`.

Code after:
    // 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
    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;
        }
        pool.addUnchecked(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()) {
            // We aren't adding this final tx to mempool, so we don't want to conflict with it
            mempool_txs.pop_back();
            break;
        }
        pool.addUnchecked(child_entry);

        if (fuzzed_data_provider.ConsumeBool()) {
            pool.PrioritiseTransaction(mempool_txs.back().GetHash().ToUint256(), fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(-100000, 100000));
        }
    }

    // Pick some transactions at random to be the direct conflicts
    CTxMemPool::setEntries direct_conflicts;
    for (auto& tx : mempool_txs) {
        if (fuzzed_data_provider.ConsumeBool()) {
            direct_conflicts.insert(*pool.GetIter(tx.GetHash()));
        }
    }

    // Calculate all conflicts: