The tapscript/disabled_checkmultisig and tapscript/disabled_checkmultisigverify spenders in feature_taproot.py run OP_CHECKMULTISIG(VERIFY) on a Schnorr signature (0 OP_SWAP 1 <pubkey> 1 OP_CHECKMULTISIG). An implementation which forgets to disable these opcodes in tapscript still fails the case, because a 64 byte Schnorr signature is not a valid DER signature. So the asset tests generated from these spenders cannot tell whether the opcodes are disabled. This came up while running script_assets_test.json against a third-party implementation which executed OP_CHECKMULTISIG in tapscript and passed every case.
This PR does two things:
Adds a 0-of-0 variant for both opcodes (
OP_DROP 0 0 0 OP_CHECKMULTISIGandOP_DROP 0 0 0 OP_CHECKMULTISIGVERIFY 1). It needs no signature and leaves a single1on the stack, so it succeeds when the opcode is executed and fails only because of the tapscript rule. Checked against the implementation above: it accepts the new failure case while its fixed version rejects it withSCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG.Writes the expected script error of a failure case into the JSON dump (
"error"), taken from theerr_msgthe spender already declares and whichblock_submitalready checks against the node.script_assets_testthen checks the error under exactly the listed flags. Until now a failure case could only be checked for failing, not for failing for the stated reason. A superset of the flags may fail earlier for another reason, so the check is limited to the exact flag set. Consumers which do not know the field are unaffected, and spenders withouterr_msgget no field.
Verified by running feature_taproot.py --dumptests and test_bitcoin --run_test=script_assets_tests on the regenerated dump (2897 vectors, 2410 of them with an error field).