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

Code before:
    }

    // Only MAX_DUST_OUTPUTS_PER_TX dust is permitted(on otherwise valid ephemeral dust)
    if (GetDust(tx, dust_relay_fee).size() > MAX_DUST_OUTPUTS_PER_TX) {
        reason = "dust";
        return false;
    }

    // only one OP_RETURN txout is permitted
    if (nDataOut > 1) {
        reason = "multi-op-return";
        return false;
    }

    return true;
}

/**
 * Check the total number of non-witness sigops across the whole transaction, as per BIP54.
 */
static bool CheckSigopsBIP54(const CTransaction& tx, const CCoinsViewCache& inputs)
{
    Assert(!tx.IsCoinBase());

    unsigned int sigops{0};
    for (unsigned i{0}; i < tx.vin.size(); ++i) {
        const auto& prev_txo{inputs.AccessCoin(tx.vin[i].prevout).out};

        // Unlike the existing block wide sigop limit, BIP54 counts sigops when they are actually executed.
        // This means sigops in the spent scriptpubkey count toward the limit.
        // `fAccurate` means correctly accounting sigops for CHECKMULTISIGs with 16 pubkeys or less. This
        // method of accounting was introduced by BIP16, and BIP54 reuses it.
        sigops += tx.vin[i].scriptSig.GetSigOpCount(/*fAccurate=*/true);
        sigops += prev_txo.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);

        if (sigops > MAX_TX_LEGACY_SIGOPS) {
            return false;
        }
    }

    return true;
}

/**
 * Check transaction inputs.
 *
 * This does three things:
 *  * Prevents mempool acceptance of spends of future
 *    segwit versions we don't know how to validate
 *  * Mitigates a potential denial-of-service attack with
 *    P2SH scripts with a crazy number of expensive

Review comment (performance):
Since it's a brand new helper function and you're not moving code, let's embrace the future:

```diff
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 48dfa14a8f..327aa5a5cf 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -176,15 +176,15 @@ static bool CheckSigopsBIP54(const CTransaction& tx, const CCoinsViewCache& inpu
     Assert(!tx.IsCoinBase());

     unsigned int sigops{0};
-    for (unsigned i{0}; i < tx.vin.size(); ++i) {
-        const auto& prev_txo{inputs.AccessCoin(tx.vin[i].prevout).out};
+    for (const CTxIn& input : tx.vin) {
+        const auto& prev_txo{inputs.AccessCoin(input.prevout).out};

         // Unlike the existing block wide sigop limit, BIP54 counts sigops when they are actually executed.
         // This means sigops in the spent scriptpubkey count toward the limit.
         // `fAccurate` means correctly accounting sigops for CHECKMULTISIGs with 16 pubkeys or less. This
         // method of accounting was introduced by BIP16, and BIP54 reuses it.
-        sigops += tx.vin[i].scriptSig.GetSigOpCount(/*fAccurate=*/true);
-        sigops += prev_txo.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
+        sigops += input.scriptSig.GetSigOpCount(/*fAccurate=*/true);
+        sigops += prev_txo.scriptPubKey.GetSigOpCount(input.scriptSig);

         if (sigops > MAX_TX_LEGACY_SIGOPS) {
             return false;
```

Code after:
        }
    }

    // Only MAX_DUST_OUTPUTS_PER_TX dust is permitted(on otherwise valid ephemeral dust)
    if (GetDust(tx, dust_relay_fee).size() > MAX_DUST_OUTPUTS_PER_TX) {
        reason = "dust";
        return false;
    }

    return true;
}

/**
 * Check the total number of non-witness sigops across the whole transaction, as per BIP54.
 */
static bool CheckSigopsBIP54(const CTransaction& tx, const CCoinsViewCache& inputs)
{
    Assert(!tx.IsCoinBase());

    unsigned int sigops{0};
    for (const auto& txin: tx.vin) {
        const auto& prev_txo{inputs.AccessCoin(txin.prevout).out};

        // Unlike the existing block wide sigop limit which counts sigops present in the block
        // itself (including the scriptPubKey which is not executed until spending later), BIP54
        // counts sigops in the block where they are potentially executed (only).
        // This means sigops in the spent scriptPubKey count toward the limit.
        // `fAccurate` means correctly accounting sigops for CHECKMULTISIGs(VERIFY) with 16 pubkeys
        // or fewer. This method of accounting was introduced by BIP16, and BIP54 reuses it.
        // The GetSigOpCount call on the previous scriptPubKey counts both bare and P2SH sigops.
        sigops += txin.scriptSig.GetSigOpCount(/*fAccurate=*/true);
        sigops += prev_txo.scriptPubKey.GetSigOpCount(txin.scriptSig);

        if (sigops > MAX_TX_LEGACY_SIGOPS) {
            return false;
        }
    }

    return true;
}

/**
 * Check transaction inputs.
 *
 * This does three things:
 *  * Prevents mempool acceptance of spends of future
 *    segwit versions we don't know how to validate
 *  * Mitigates a potential denial-of-service attack with
 *    P2SH scripts with a crazy number of expensive
 *    CHECKSIG/CHECKMULTISIG operations.
 *  * Prevents spends of unknown/irregular scriptPubKeys,