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

Code before:
        const auto error_message{util::ErrorString(ancestors).original};

        // Carve-out is not allowed in this context; fail
        if (!args.m_allow_carveouts) {
            return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
        }

        // Contracting/payment channels CPFP carve-out:
        // If the new transaction is relatively small (up to 40k weight)
        // and has at most one ancestor (ie ancestor limit of 2, including
        // the new transaction), allow it if its parent has exactly the
        // descendant limit descendants. The transaction also cannot be v3,
        // as its topology restrictions do not allow a second child.
        //
        // This allows protocols which rely on distrusting counterparties
        // being able to broadcast descendants of an unconfirmed transaction
        // to be secure by simply only having two immediately-spendable
        // outputs - one for each counterparty. For more info on the uses for
        // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
        CTxMemPool::Limits cpfp_carve_out_limits{
            .ancestor_count = 2,
            .ancestor_size_vbytes = maybe_rbf_limits.ancestor_size_vbytes,
            .descendant_count = maybe_rbf_limits.descendant_count + 1,
            .descendant_size_vbytes = maybe_rbf_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT,
        };
        if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx->nVersion == 3) {
            return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
        }
        if (auto ancestors_retry{m_pool.CalculateMemPoolAncestors(*entry, cpfp_carve_out_limits)}) {
            ws.m_ancestors = std::move(*ancestors_retry);
        } else {
            return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
        }
    }

    // Even though just checking direct mempool parents for inheritance would be sufficient, we
    // check using the full ancestor set here because it's more convenient to use what we have
    // already calculated.
    if (const auto err{SingleV3Checks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
        // Single transaction contexts only.
        if (args.m_allow_sibling_eviction && err->second != nullptr) {
            // We should only be considering where replacement is considered valid as well.
            Assume(args.m_allow_replacement);

            // Potential sibling eviction. Add the sibling to our list of mempool conflicts to be
            // included in RBF checks.
            ws.m_conflicts.insert(err->second->GetHash());
            // Adding the sibling to m_iters_conflicting here means that it doesn't count towards
            // RBF Carve Out above. This is correct, since removing to-be-replaced transactions from
            // the descendant count is done separately in SingleV3Checks for v3 transactions.
            ws.m_iters_conflicting.insert(m_pool.GetIter(err->second->GetHash()).value());

Review comment (suggestion):
few remaining spots that I can see:
```
src/test/fuzz/package_eval.cpp:176:                tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? 3 : CTransaction::CURRENT_VERSION;
src/test/fuzz/tx_pool.cpp:229:            tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ? 3 : CTransaction::CURRENT_VERSION;
src/test/txvalidation_tests.cpp:289:        mtx_many_sigops.nVersion = 3;
src/test/util/txmempool.cpp:121:        if (tx_info.tx->nVersion == 3) {
src/test/util/txmempool.cpp:136:                Assert(parents.begin()->get().GetSharedTx()->nVersion == 3);
src/test/util/txmempool.cpp:141:                Assert(parent.get().GetSharedTx()->nVersion != 3);
```

can also use this constant

Code after:
        const auto error_message{util::ErrorString(ancestors).original};

        // Carve-out is not allowed in this context; fail
        if (!args.m_allow_carveouts) {
            return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
        }

        // Contracting/payment channels CPFP carve-out:
        // If the new transaction is relatively small (up to 40k weight)
        // and has at most one ancestor (ie ancestor limit of 2, including
        // the new transaction), allow it if its parent has exactly the
        // descendant limit descendants. The transaction also cannot be v3,
        // as its topology restrictions do not allow a second child.
        //
        // This allows protocols which rely on distrusting counterparties
        // being able to broadcast descendants of an unconfirmed transaction
        // to be secure by simply only having two immediately-spendable
        // outputs - one for each counterparty. For more info on the uses for
        // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
        CTxMemPool::Limits cpfp_carve_out_limits{
            .ancestor_count = 2,
            .ancestor_size_vbytes = maybe_rbf_limits.ancestor_size_vbytes,
            .descendant_count = maybe_rbf_limits.descendant_count + 1,
            .descendant_size_vbytes = maybe_rbf_limits.descendant_size_vbytes + EXTRA_DESCENDANT_TX_SIZE_LIMIT,
        };
        if (ws.m_vsize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || ws.m_ptx->nVersion == TRUC_VERSION) {
            return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
        }
        if (auto ancestors_retry{m_pool.CalculateMemPoolAncestors(*entry, cpfp_carve_out_limits)}) {
            ws.m_ancestors = std::move(*ancestors_retry);
        } else {
            return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", error_message);
        }
    }

    // Even though just checking direct mempool parents for inheritance would be sufficient, we
    // check using the full ancestor set here because it's more convenient to use what we have
    // already calculated.
    if (const auto err{SingleV3Checks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
        // Single transaction contexts only.
        if (args.m_allow_sibling_eviction && err->second != nullptr) {
            // We should only be considering where replacement is considered valid as well.
            Assume(args.m_allow_replacement);

            // Potential sibling eviction. Add the sibling to our list of mempool conflicts to be
            // included in RBF checks.
            ws.m_conflicts.insert(err->second->GetHash());
            // Adding the sibling to m_iters_conflicting here means that it doesn't count towards
            // RBF Carve Out above. This is correct, since removing to-be-replaced transactions from
            // the descendant count is done separately in SingleV3Checks for v3 transactions.
            ws.m_iters_conflicting.insert(m_pool.GetIter(err->second->GetHash()).value());