Repository: bitcoin/bitcoin
File: src/validation.cpp (C++)

Code before:
    return true;
}

bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>& workspaces,
                                  PackageValidationState& package_state,
                                  std::map<uint256, MempoolAcceptResult>& results)
{
    AssertLockHeld(cs_main);
    AssertLockHeld(m_pool.cs);
    // Sanity check: none of the transactions should be in the mempool, and none of the transactions
    // should have a same-txid-different-witness equivalent in the mempool.
    assert(std::all_of(workspaces.cbegin(), workspaces.cend(), [this](const auto& ws){
        return !m_pool.exists(GenTxid::Txid(ws.m_ptx->GetHash())); }));

    bool all_submitted = true;
    // ConsensusScriptChecks adds to the script cache and is therefore consensus-critical;
    // CheckInputsFromMempoolAndCache asserts that transactions only spend coins available from the
    // mempool or UTXO set. Submit each transaction to the mempool immediately after calling
    // ConsensusScriptChecks to make the outputs available for subsequent transactions.
    for (Workspace& ws : workspaces) {
        if (!ConsensusScriptChecks(args, ws)) {
            results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
            // Since PolicyScriptChecks() passed, this should never fail.
            Assume(false);
            all_submitted = false;
            package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR,
                                  strprintf("BUG! PolicyScriptChecks succeeded but ConsensusScriptChecks failed: %s",
                                            ws.m_ptx->GetHash().ToString()));
        }

        // Re-calculate mempool ancestors to call addUnchecked(). They may have changed since the
        // last calculation done in PreChecks, since package ancestors have already been submitted.
        {
            auto ancestors{m_pool.CalculateMemPoolAncestors(*ws.m_entry, m_pool.m_opts.limits)};
            if(!ancestors) {
                results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
                // Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail.
                Assume(false);
                all_submitted = false;
                package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR,
                                    strprintf("BUG! Mempool ancestors or descendants were underestimated: %s",
                                                ws.m_ptx->GetHash().ToString()));
            }
            ws.m_ancestors = std::move(ancestors).value_or(ws.m_ancestors);
        }
        // If we call LimitMempoolSize() for each individual Finalize(), the mempool will not take
        // the transaction's descendant feerate into account because it hasn't seen them yet. Also,
        // we risk evicting a transaction that a subsequent package transaction depends on. Instead,
        // allow the mempool to temporarily bypass limits, the maximum package size) while
        // submitting transactions individually and then trim at the very end.
        if (!Finalize(args, ws)) {

Review comment (suggestion):
nitty nit (nonblocking)
```suggestion
    // Don't attempt to process the same conflicts repeatedly during subpackage evaluation:
```

Code after:
    unsigned int currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)};
    if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags,
                                        ws.m_precomputed_txdata, m_active_chainstate.CoinsTip())) {
        LogPrintf("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s\n", hash.ToString(), state.ToString());
        return Assume(false);
    }

    return true;
}

bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
{
    AssertLockHeld(cs_main);
    AssertLockHeld(m_pool.cs);
    const CTransaction& tx = *ws.m_ptx;
    const uint256& hash = ws.m_hash;
    TxValidationState& state = ws.m_state;
    const bool bypass_limits = args.m_bypass_limits;
    std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry;

    // Remove conflicting transactions from the mempool
    for (CTxMemPool::txiter it : m_subpackage.m_all_conflicts)
    {
        LogPrint(BCLog::MEMPOOL, "replacing tx %s (wtxid=%s) with %s (wtxid=%s) for %s additional fees, %d delta bytes\n",
                it->GetTx().GetHash().ToString(),
                it->GetTx().GetWitnessHash().ToString(),
                hash.ToString(),
                tx.GetWitnessHash().ToString(),
                FormatMoney(ws.m_modified_fees - m_subpackage.m_conflicting_fees),
                (int)entry->GetTxSize() - (int)m_subpackage.m_conflicting_size);
        TRACE7(mempool, replaced,
                it->GetTx().GetHash().data(),
                it->GetTxSize(),
                it->GetFee(),
                std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(it->GetTime()).count(),
                hash.data(),
                entry->GetTxSize(),
                entry->GetFee()
        );
        m_subpackage.m_replaced_transactions.push_back(it->GetSharedTx());
    }
    m_pool.RemoveStaged(m_subpackage.m_all_conflicts, false, MemPoolRemovalReason::REPLACED);
    // Don't attempt to process the same conflicts repeatedly during subpackage evaluation:
    // they no longer exist on subsequent calls to Finalize() post-RemoveStaged
    m_subpackage.m_all_conflicts.clear();
    // Store transaction in memory
    m_pool.addUnchecked(*entry, ws.m_ancestors);

    // trim mempool and check if tx was trimmed
    // If we are validating a package, don't trim here because we could evict a previous transaction
    // in the package. LimitMempoolSize() should be called at the very end to make sure the mempool