From bd31a92d671610e1173a4e6f0c761d94724441ae Mon Sep 17 00:00:00 2001 From: Bruno Garcia Date: Thu, 22 Jan 2026 10:05:27 -0300 Subject: [PATCH] script: use SCRIPT_ERR_SCRIPTNUM for CScriptNum errors --- src/script/interpreter.cpp | 4 + src/test/data/script_tests.json | 132 ++++++++++++++--------------- src/test/script_tests.cpp | 1 + test/functional/feature_taproot.py | 5 +- 4 files changed, 74 insertions(+), 68 deletions(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index b7978cacc5b..49fa2bd9502 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1223,6 +1223,10 @@ bool EvalScript(std::vector >& stack, const CScript& return set_error(serror, SCRIPT_ERR_STACK_SIZE); } } + catch (const scriptnum_error&) + { + return set_error(serror, SCRIPT_ERR_SCRIPTNUM); + } catch (...) { return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json index 1af2293866e..29227cf01c0 100644 --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -859,10 +859,10 @@ ["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], ["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], -["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "UNKNOWN_ERROR", "arithmetic operands must be in range [-2^31...2^31] "], -["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "UNKNOWN_ERROR", "arithmetic operands must be in range [-2^31...2^31] "], -["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "UNKNOWN_ERROR", "NUMEQUAL must be in numeric range"], -["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "UNKNOWN_ERROR", "NOT is an arithmetic operand"], +["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "SCRIPTNUM", "arithmetic operands must be in range [-2^31...2^31] "], +["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "SCRIPTNUM", "arithmetic operands must be in range [-2^31...2^31] "], +["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "SCRIPTNUM", "NUMEQUAL must be in numeric range"], +["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "SCRIPTNUM", "NOT is an arithmetic operand"], ["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], @@ -1016,14 +1016,14 @@ ["1","RESERVED2", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED2 is reserved"], ["1","0xba", "P2SH,STRICTENC", "BAD_OPCODE", "0xba == MAX_OPCODE + 1"], -["2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], -["2147483648", "NEGATE 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], -["-2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "Because we use a sign bit, -2147483648 is also 5 bytes"], -["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], -["2147483648", "1SUB 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], +["2147483648", "1ADD 1", "P2SH,STRICTENC", "SCRIPTNUM", "We cannot do math on 5-byte integers"], +["2147483648", "NEGATE 1", "P2SH,STRICTENC", "SCRIPTNUM", "We cannot do math on 5-byte integers"], +["-2147483648", "1ADD 1", "P2SH,STRICTENC", "SCRIPTNUM", "Because we use a sign bit, -2147483648 is also 5 bytes"], +["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "SCRIPTNUM", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], +["2147483648", "1SUB 1", "P2SH,STRICTENC", "SCRIPTNUM", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], -["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"], -["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do BOOLAND on 5-byte integers"], +["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "SCRIPTNUM", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"], +["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "SCRIPTNUM", "We cannot do BOOLAND on 5-byte integers"], ["1", "1 ENDIF", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "ENDIF without IF"], ["1", "IF 1", "P2SH,STRICTENC", "UNBALANCED_CONDITIONAL", "IF without ENDIF"], @@ -1169,66 +1169,66 @@ ["MINIMALDATA enforcement for numeric arguments"], -["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 0"], -["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 0"], -["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "0x80 (negative zero) numequals 0"], -["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 0"], -["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 5"], -["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals 5"], -["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals -5"], -["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "numequals -5"], -["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xffff"], -["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xff7f"], -["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xffffff"], -["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR", "Minimal encoding is 0xffff7f"], +["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "numequals 0"], +["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "numequals 0"], +["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "0x80 (negative zero) numequals 0"], +["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "numequals 0"], +["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "numequals 5"], +["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "numequals 5"], +["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "numequals -5"], +["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "numequals -5"], +["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "Minimal encoding is 0xffff"], +["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "Minimal encoding is 0xff7f"], +["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "Minimal encoding is 0xffffff"], +["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM", "Minimal encoding is 0xffff7f"], ["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"], -["1 0x02 0x0000", "PICK DROP", "MINIMALDATA", "UNKNOWN_ERROR"], -["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000", "ABS DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["1 0x02 0x0000", "PICK DROP", "MINIMALDATA", "SCRIPTNUM"], +["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000", "ABS DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA", "SCRIPTNUM"], -["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA", "SCRIPTNUM"], -["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA", "SCRIPTNUM"], -["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "UNKNOWN_ERROR"], -["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "UNKNOWN_ERROR"], +["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "SCRIPTNUM"], +["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA", "SCRIPTNUM"], ["Order of CHECKMULTISIG evaluation tests, inverted by swapping the order of"], @@ -2551,7 +2551,7 @@ ["CHECKSEQUENCEVERIFY tests"], ["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on an empty stack"], ["-1", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"], -["0x0100", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"], +["0x0100", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY,MINIMALDATA", "SCRIPTNUM", "CSV fails if stack top is not minimally encoded"], ["0", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], ["0x050000000001", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"], diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 589588501c5..6313640944e 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -95,6 +95,7 @@ static ScriptErrorDesc script_errors[]={ {SCRIPT_ERR_TAPSCRIPT_EMPTY_PUBKEY, "TAPSCRIPT_EMPTY_PUBKEY"}, {SCRIPT_ERR_OP_CODESEPARATOR, "OP_CODESEPARATOR"}, {SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"}, + {SCRIPT_ERR_SCRIPTNUM, "SCRIPTNUM"} }; static std::string FormatScriptFlags(script_verify_flags flags) diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py index d27961442af..8891e0f9994 100755 --- a/test/functional/feature_taproot.py +++ b/test/functional/feature_taproot.py @@ -640,6 +640,7 @@ ERR_BAD_OPCODE = {"err_msg": "Opcode missing or not understood"} ERR_EVAL_FALSE = {"err_msg": "Script evaluated without error but finished with a false/empty top stack element"} ERR_WITNESS_PROGRAM_WITNESS_EMPTY = {"err_msg": "Witness program was passed an empty witness"} ERR_CHECKSIGVERIFY = {"err_msg": "Script failed an OP_CHECKSIGVERIFY operation"} +ERR_SCRIPT_NUM = {"err_msg": "Script number overflowed or is non-minimally encoded"} VALID_SIGHASHES_ECDSA = [ SIGHASH_ALL, @@ -1060,8 +1061,8 @@ def spenders_taproot_active(): add_spender(spenders, "tapscript/emptypk/checksigadd", leaf="t9", **SINGLE_SIG, **common, failure={"leaf": "t10"}, **ERR_TAPSCRIPT_EMPTY_PUBKEY) add_spender(spenders, "tapscript/emptypk/checksigadd", leaf="t35", standard=False, **SINGLE_SIG, **common, failure={"leaf": "t10"}, **ERR_TAPSCRIPT_EMPTY_PUBKEY) # Test that OP_CHECKSIGADD results are as expected - add_spender(spenders, "tapscript/checksigaddresults", leaf="t28", **SINGLE_SIG, **common, failure={"leaf": "t27"}, err_msg="unknown error") - add_spender(spenders, "tapscript/checksigaddoversize", leaf="t29", **SINGLE_SIG, **common, failure={"leaf": "t27"}, err_msg="unknown error") + add_spender(spenders, "tapscript/checksigaddresults", leaf="t28", **SINGLE_SIG, **common, failure={"leaf": "t27"}, **ERR_SCRIPT_NUM) + add_spender(spenders, "tapscript/checksigaddoversize", leaf="t29", **SINGLE_SIG, **common, failure={"leaf": "t27"}, **ERR_SCRIPT_NUM) # Test that OP_CHECKSIGADD requires 3 stack elements. add_spender(spenders, "tapscript/checksigadd3args", leaf="t9", **SINGLE_SIG, **common, failure={"leaf": "t11"}, **ERR_INVALID_STACK_OPERATION) # Test that empty signatures do not cause script failure in OP_CHECKSIG and OP_CHECKSIGADD (but do fail with empty pubkey, and do fail OP_CHECKSIGVERIFY)