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

Code before:
    }

    auto outpoints_updater = std::make_shared<OutpointsUpdater>(mempool_outpoints);
    node.validation_signals->RegisterSharedValidationInterface(outpoints_updater);

    auto tx_pool_{MakeEphemeralMempool(node)};
    MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());

    chainstate.SetMempool(&tx_pool);

    LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
    {
        Assert(!mempool_outpoints.empty());

        std::vector<CTransactionRef> txs;

        // Find something we may want to double-spend with two input single tx
        std::optional<COutPoint> outpoint_to_rbf{GetChildEvictingPrevout(tx_pool)};
        bool should_rbf_eph_spend = outpoint_to_rbf && fuzzed_data_provider.ConsumeBool();

        // Make small packages
        const auto num_txs = should_rbf_eph_spend ? 1 : (size_t) fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 4);

        std::set<COutPoint> package_outpoints;
        while (txs.size() < num_txs) {

            // Last transaction in a package needs to be a child of parents to get further in validation
            // so the last transaction to be generated(in a >1 package) must spend all package-made outputs
            // Note that this test currently only spends package outputs in last transaction.
            bool last_tx = num_txs > 1 && txs.size() == num_txs - 1;

            // Create transaction to add to the mempool
            const CTransactionRef tx = [&] {
                CMutableTransaction tx_mut;
                tx_mut.version = CTransaction::CURRENT_VERSION;
                tx_mut.nLockTime = 0;
                // Last tx will sweep half or more of all outpoints from package
                const auto num_in = should_rbf_eph_spend ? 2 :
                    last_tx ? fuzzed_data_provider.ConsumeIntegralInRange<int>(package_outpoints.size()/2 + 1, package_outpoints.size()) :
                    fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 4);
                auto num_out = should_rbf_eph_spend ? 1 : fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 4);

                auto& outpoints = last_tx ? package_outpoints : mempool_outpoints;

                Assert((int)outpoints.size() >= num_in && num_in > 0);

                CAmount amount_in{0};
                for (int i = 0; i < num_in; ++i) {
                    // Pop random outpoint
                    auto pop = outpoints.begin();
                    std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints.size() - 1));

Review comment (suggestion):
nit: Could emplace movable `CTransaction`, apologies for not including it in my original suggestion.
```suggestion
            txs.emplace_back([&] {
```

Code after:
    }

    auto outpoints_updater = std::make_shared<OutpointsUpdater>(mempool_outpoints);
    node.validation_signals->RegisterSharedValidationInterface(outpoints_updater);

    auto tx_pool_{MakeEphemeralMempool(node)};
    MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());

    chainstate.SetMempool(&tx_pool);

    LIMITED_WHILE(fuzzed_data_provider.remaining_bytes() > 0, 300)
    {
        Assert(!mempool_outpoints.empty());

        std::vector<CTransactionRef> txs;

        // Find something we may want to double-spend with two input single tx
        std::optional<COutPoint> outpoint_to_rbf{fuzzed_data_provider.ConsumeBool() ? GetChildEvictingPrevout(tx_pool) : std::nullopt};

        // Make small packages
        const auto num_txs = outpoint_to_rbf ? 1 : (size_t) fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 4);

        std::set<COutPoint> package_outpoints;
        while (txs.size() < num_txs) {
            // Create transaction to add to the mempool
            txs.emplace_back([&] {
                CMutableTransaction tx_mut;
                tx_mut.version = CTransaction::CURRENT_VERSION;
                tx_mut.nLockTime = 0;
                // Last transaction in a package needs to be a child of parents to get further in validation
                // so the last transaction to be generated(in a >1 package) must spend all package-made outputs
                // Note that this test currently only spends package outputs in last transaction.
                bool last_tx = num_txs > 1 && txs.size() == num_txs - 1;
                const auto num_in = outpoint_to_rbf ? 2 :
                    last_tx ? fuzzed_data_provider.ConsumeIntegralInRange<int>(package_outpoints.size()/2 + 1, package_outpoints.size()) :
                    fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 4);
                const auto num_out = outpoint_to_rbf ? 1 : fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 4);

                auto& outpoints = last_tx ? package_outpoints : mempool_outpoints;

                Assert((int)outpoints.size() >= num_in && num_in > 0);

                CAmount amount_in{0};
                for (int i = 0; i < num_in; ++i) {
                    // Pop random outpoint. We erase them to avoid double-spending
                    // while in this loop, but later add them back (unless last_tx).
                    auto pop = outpoints.begin();
                    std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints.size() - 1));
                    auto outpoint = *pop;

                    if (i == 0 && outpoint_to_rbf) {