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

Code before:
    const auto witness_script{CScript() << key.GetPubKey() << OP_CHECKSIG};
    tx_create_segwit.vout.emplace_back(121212, GetScriptForDestination(WitnessV0KeyHash(key.GetPubKey())));
    tx_create_segwit.vout.emplace_back(131313, GetScriptForDestination(WitnessV0ScriptHash(witness_script)));
    tx_create_segwit.vout.emplace_back(141414, GetScriptForDestination(WitnessV1Taproot{XOnlyPubKey(key.GetPubKey())}));
    prev_txid = tx_create_segwit.GetHash();
    for (unsigned i{0}; i < tx_create_segwit.vout.size(); ++i) {
        tx_max_sigops.vin.emplace_back(COutPoint(prev_txid, i));
    }
    keystore.AddCScript(witness_script);
    for (unsigned i{0}; i < tx_create_segwit.vout.size(); ++i) {
        BOOST_REQUIRE(SignSignature(keystore, CTransaction(tx_create_segwit), tx_max_sigops, tx_max_sigops.vin.size() - 1 - i, SIGHASH_ALL, dummy_sigdata));
    }

    // The transaction now still contains exactly 2500 sigops, the check should pass.
    AddCoins(coins, CTransaction(tx_create_segwit), 0, false);
    BOOST_REQUIRE(::AreInputsStandard(CTransaction(tx_max_sigops), coins));

    // Add one more P2PK input. We'll reach the limit.
    tx_create_p2pk.vout.emplace_back(212121, p2pk_script);
    prev_txid = tx_create_p2pk.GetHash();
    tx_max_sigops.vin.resize(p2sh_inputs_count);
    ++p2pk_inputs_count;
    for (unsigned i{0}; i < p2pk_inputs_count; ++i) {
        tx_max_sigops.vin.emplace_back(COutPoint(prev_txid, i));
    }
    for (unsigned i{0}; i < p2pk_inputs_count; ++i) {
        BOOST_REQUIRE(SignSignature(keystore, CTransaction(tx_create_p2pk), tx_max_sigops, p2sh_inputs_count + i, SIGHASH_ALL, dummy_sigdata));
    }
    AddCoins(coins, CTransaction(tx_create_p2pk), 0, false);
    BOOST_CHECK(p2sh_inputs_count * MAX_P2SH_SIGOPS + p2pk_inputs_count * 1 > MAX_TX_LEGACY_SIGOPS);
    BOOST_CHECK(!::AreInputsStandard(CTransaction(tx_max_sigops), coins));
}

BOOST_AUTO_TEST_SUITE_END()


Review comment (bug):
👍 this is where the test fails correctly without the `!CheckSigopsBIP54(tx, mapInputs)` check.

-----

Would it make sense to add a coinbase tx and vouts to this test to make it more realistic so that it passes `CheckTransaction` as well? Otherwise it's harder to tell if it fails for the right reasons...

And to make sure this only affects policy and not consensus: do we already have tests that check that e.g. 3000 sigops could still be mined? If not, can we add a clause here to make sure that we haven't accidentally changed the consensus, i.e. that we could still mine these non-standard blocks?
```C++
    TxValidationState state;
    BOOST_CHECK(CheckTransaction(CTransaction(tx_max_sigops), state));
    BOOST_CHECK(state.IsValid());
```

Code after:
    // is exclusively on non-witness sigops and therefore those should not be counted.
    CMutableTransaction tx_create_segwit;
    const auto witness_script{CScript() << key.GetPubKey() << OP_CHECKSIG};
    tx_create_segwit.vout.emplace_back(121212, GetScriptForDestination(WitnessV0KeyHash(key.GetPubKey())));
    tx_create_segwit.vout.emplace_back(131313, GetScriptForDestination(WitnessV0ScriptHash(witness_script)));
    tx_create_segwit.vout.emplace_back(141414, GetScriptForDestination(WitnessV1Taproot{XOnlyPubKey(key.GetPubKey())}));
    prev_txid = tx_create_segwit.GetHash();
    for (unsigned i{0}; i < tx_create_segwit.vout.size(); ++i) {
        tx_max_sigops.vin.emplace_back(prev_txid, i);
    }

    // The transaction now still contains exactly 2500 sigops, the check should pass.
    AddCoins(coins, CTransaction(tx_create_segwit), 0, false);
    BOOST_REQUIRE(::AreInputsStandard(CTransaction(tx_max_sigops), coins));

    // Add one more P2PK input. We'll reach the limit.
    tx_create_p2pk.vout.emplace_back(212121, p2pk_script);
    prev_txid = tx_create_p2pk.GetHash();
    tx_max_sigops.vin.resize(p2sh_inputs_count);
    ++p2pk_inputs_count;
    for (unsigned i{0}; i < p2pk_inputs_count; ++i) {
        tx_max_sigops.vin.emplace_back(prev_txid, i);
    }
    AddCoins(coins, CTransaction(tx_create_p2pk), 0, false);
    BOOST_CHECK_GT(p2sh_inputs_count * MAX_P2SH_SIGOPS + p2pk_inputs_count * 1, MAX_TX_LEGACY_SIGOPS);
    BOOST_CHECK(!::AreInputsStandard(CTransaction(tx_max_sigops), coins));
}

BOOST_AUTO_TEST_SUITE_END()