diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -300,8 +300,6 @@ case OP_2MUL: case OP_2DIV: case OP_MUL: - case OP_DIV: - case OP_MOD: case OP_LSHIFT: case OP_RSHIFT: // Disabled opcodes. @@ -310,6 +308,8 @@ case OP_AND: case OP_OR: case OP_XOR: + case OP_DIV: + case OP_MOD: case OP_BIN2NUM: // Opcodes that have been reenabled. if ((flags & SCRIPT_ENABLE_MONOLITH_OPCODES) == 0) { @@ -926,6 +926,8 @@ case OP_ADD: case OP_SUB: + case OP_DIV: + case OP_MOD: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: @@ -954,6 +956,24 @@ bn = bn1 - bn2; break; + case OP_DIV: + // denominator must not be 0 + if (bn2 == 0) { + return set_error(serror, + SCRIPT_ERR_DIV_BY_ZERO); + } + bn = bn1 / bn2; + break; + + case OP_MOD: + // divisor must not be 0 + if (bn2 == 0) { + return set_error(serror, + SCRIPT_ERR_MOD_BY_ZERO); + } + bn = bn1 % bn2; + break; + case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; diff --git a/src/script/script.h b/src/script/script.h --- a/src/script/script.h +++ b/src/script/script.h @@ -266,6 +266,20 @@ return operator-(rhs.m_value); } + inline CScriptNum operator/(const int64_t &rhs) const { + return CScriptNum(m_value / rhs); + } + inline CScriptNum operator/(const CScriptNum &rhs) const { + return operator/(rhs.m_value); + } + + inline CScriptNum operator%(const int64_t &rhs) const { + return CScriptNum(m_value % rhs); + } + inline CScriptNum operator%(const CScriptNum &rhs) const { + return operator%(rhs.m_value); + } + inline CScriptNum &operator+=(const CScriptNum &rhs) { return operator+=(rhs.m_value); } diff --git a/src/script/script_error.h b/src/script/script_error.h --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -38,6 +38,10 @@ SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, SCRIPT_ERR_UNBALANCED_CONDITIONAL, + /* Divisor errors */ + SCRIPT_ERR_DIV_BY_ZERO, + SCRIPT_ERR_MOD_BY_ZERO, + /* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */ SCRIPT_ERR_NEGATIVE_LOCKTIME, SCRIPT_ERR_UNSATISFIED_LOCKTIME, diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -51,6 +51,10 @@ return "OP_RETURN was encountered"; case SCRIPT_ERR_UNBALANCED_CONDITIONAL: return "Invalid OP_IF construction"; + case SCRIPT_ERR_DIV_BY_ZERO: + return "Invalid division operation"; + case SCRIPT_ERR_MOD_BY_ZERO: + return "Invalid modulo operation"; case SCRIPT_ERR_NEGATIVE_LOCKTIME: return "Negative locktime"; case SCRIPT_ERR_UNSATISFIED_LOCKTIME: diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -873,9 +873,9 @@ ["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MUL disabled"], ["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "MUL disabled"], ["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "DIV disabled"], -["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "DIV disabled"], +["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "DIV enabled"], ["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MOD disabled"], -["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "MOD disabled"], +["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "MOD enabled"], ["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "LSHIFT disabled"], ["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "LSHIFT disabled"], ["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "RSHIFT disabled"], @@ -913,6 +913,34 @@ ["0 1", "XOR 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OPERAND_SIZE", "XOR, different operand size"], ["0x01 0xab 0x01 0xcd", "XOR 0x01 0x66 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "XOR, more complex operands"], +["DIV"], +["1 1", "DIV 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["1 -1", "DIV -1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["-1 1", "DIV -1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["-1 -1", "DIV 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["2 2", "DIV 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["2 -2", "DIV -1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["-2 2", "DIV -1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["-2 -2", "DIV 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0 1", "DIV 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["1 0", "DIV", "P2SH,STRICTENC,MONOLITH_OPCODES", "DIV_BY_ZERO", "DIV, divide by zero"], +["3 2", "DIV 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Round towards zero"], +["3 -2", "DIV -1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Round towards zero"], +["1 1", "DIV DEPTH 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Stack depth correct"], +["1", "DIV", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_STACK_OPERATION", "Not enough operands"], +["0", "DIV", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_STACK_OPERATION", "Not enough operands"], + +["MOD"], +["1 1", "MOD 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["7 -3", "MOD 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["-7 3", "MOD -1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["10 3", "MOD 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0 1", "MOD 0 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["1 0", "MOD", "P2SH,STRICTENC,MONOLITH_OPCODES", "MOD_BY_ZERO", "MOD, modulo by zero"], +["1 1", "MOD DEPTH 1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK", "Stack depth correct"], +["1", "MOD", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_STACK_OPERATION", "Not enough operands"], +["0", "MOD", "P2SH,STRICTENC,MONOLITH_OPCODES", "INVALID_STACK_OPERATION", "Not enough operands"], + ["EQUAL"], ["", "EQUAL NOT", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "EQUAL must error when there are no stack items"], ["0", "EQUAL NOT", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "EQUAL must error when there are not 2 stack items"], @@ -928,13 +956,13 @@ ["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "disabled"], ["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], -["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "disabled"], +["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], ["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 2MUL", "4 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "disabled"], ["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 2DIV", "1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "disabled"], ["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], -["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "disabled"], +["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], ["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "DISABLED_OPCODE", "disabled"], ["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], diff --git a/src/test/monolith_opcodes.cpp b/src/test/monolith_opcodes.cpp --- a/src/test/monolith_opcodes.cpp +++ b/src/test/monolith_opcodes.cpp @@ -12,6 +12,7 @@ #include typedef std::vector valtype; +typedef std::vector stacktype; std::array flagset{0, STANDARD_SCRIPT_VERIFY_FLAGS, MANDATORY_SCRIPT_VERIFY_FLAGS}; @@ -21,15 +22,14 @@ /** * General utility functions to check for script passing/failing. */ -static void -CheckTestResultForAllFlags(const std::vector &original_stack, - const CScript &script, - const std::vector &expected) { +static void CheckTestResultForAllFlags(const stacktype &original_stack, + const CScript &script, + const stacktype &expected) { BaseSignatureChecker sigchecker; for (uint32_t flags : flagset) { ScriptError err = SCRIPT_ERR_OK; - std::vector stack{original_stack}; + stacktype stack{original_stack}; bool r = EvalScript(stack, script, flags | SCRIPT_ENABLE_MONOLITH_OPCODES, sigchecker, &err); @@ -45,61 +45,64 @@ } } -static void CheckErrorForAllFlags(const std::vector &original_stack, - const CScript &script, - ScriptError expected_error) { +static void CheckError(uint32_t flags, const stacktype &original_stack, + const CScript &script, ScriptError expected_error) { BaseSignatureChecker sigchecker; + ScriptError err = SCRIPT_ERR_OK; + stacktype stack{original_stack}; + bool r = EvalScript(stack, script, flags | SCRIPT_ENABLE_MONOLITH_OPCODES, + sigchecker, &err); + BOOST_CHECK(!r); + BOOST_CHECK_EQUAL(err, expected_error); + + // Make sure that if we do not pass the monolith flag, opcodes are still + // disabled. + stack = original_stack; + r = EvalScript(stack, script, flags, sigchecker, &err); + BOOST_CHECK(!r); + BOOST_CHECK_EQUAL(err, SCRIPT_ERR_DISABLED_OPCODE); +} +static void CheckErrorForAllFlags(const stacktype &original_stack, + const CScript &script, + ScriptError expected_error) { for (uint32_t flags : flagset) { - ScriptError err = SCRIPT_ERR_OK; - std::vector stack{original_stack}; - bool r = - EvalScript(stack, script, flags | SCRIPT_ENABLE_MONOLITH_OPCODES, - sigchecker, &err); - BOOST_CHECK(!r); - BOOST_CHECK_EQUAL(err, expected_error); - - // Make sure that if we do not pass the monolith flag, opcodes are still - // disabled. - stack = original_stack; - r = EvalScript(stack, script, flags, sigchecker, &err); - BOOST_CHECK(!r); - BOOST_CHECK_EQUAL(err, SCRIPT_ERR_DISABLED_OPCODE); + CheckError(flags, original_stack, script, expected_error); } } -/** - * Bitwise opcodes - */ -static void CheckBitwiseOpError(const std::vector &original_stack, - opcodetype op, ScriptError expected_error) { +static void CheckOpError(const stacktype &original_stack, opcodetype op, + ScriptError expected_error) { CheckErrorForAllFlags(original_stack, CScript() << op, expected_error); } -static void CheckAllBitwiseOpErrors(const std::vector &stack, +static void CheckAllBitwiseOpErrors(const stacktype &stack, ScriptError expected_error) { // Bitwise ops are commutative, so we check both ways. - CheckBitwiseOpError(stack, OP_AND, expected_error); - CheckBitwiseOpError(stack, OP_OR, expected_error); - CheckBitwiseOpError(stack, OP_XOR, expected_error); + CheckOpError(stack, OP_AND, expected_error); + CheckOpError(stack, OP_OR, expected_error); + CheckOpError(stack, OP_XOR, expected_error); } -static void CheckBitwiseOp(const valtype &a, const valtype &b, opcodetype op, - const valtype &expected) { +static void CheckOp(const valtype &a, const valtype &b, opcodetype op, + const valtype &expected) { CheckTestResultForAllFlags({a, b}, CScript() << op, {expected}); } +/** + * Bitwise opcodes + */ static void RunTestForAllBitwiseOpcodes(const valtype &a, const valtype &b, const valtype &expected_and, const valtype &expected_or, const valtype &expected_xor) { // Bitwise ops are commutative, so we check both ways. - CheckBitwiseOp(a, b, OP_AND, expected_and); - CheckBitwiseOp(b, a, OP_AND, expected_and); - CheckBitwiseOp(a, b, OP_OR, expected_or); - CheckBitwiseOp(b, a, OP_OR, expected_or); - CheckBitwiseOp(a, b, OP_XOR, expected_xor); - CheckBitwiseOp(b, a, OP_XOR, expected_xor); + CheckOp(a, b, OP_AND, expected_and); + CheckOp(b, a, OP_AND, expected_and); + CheckOp(a, b, OP_OR, expected_or); + CheckOp(b, a, OP_OR, expected_or); + CheckOp(a, b, OP_XOR, expected_xor); + CheckOp(b, a, OP_XOR, expected_xor); } static void RunTestForAllBitwiseOpcodesSizes(const valtype &a, const valtype &b, @@ -377,7 +380,7 @@ // TODO: Check roundtrip with NUM2BIN when NUM2BIN is implemented. } -static void CheckBin2NumError(const std::vector &original_stack, +static void CheckBin2NumError(const stacktype &original_stack, ScriptError expected_error) { CheckErrorForAllFlags(original_stack, CScript() << OP_BIN2NUM, expected_error); @@ -425,4 +428,130 @@ SCRIPT_ERR_INVALID_NUMBER_RANGE); } +/** + * Binary opcodes. + */ +BOOST_AUTO_TEST_CASE(div_opcode_tests) { + CheckOpError(stacktype{}, OP_DIV, SCRIPT_ERR_INVALID_STACK_OPERATION); + CheckOpError(stacktype{{}}, OP_DIV, SCRIPT_ERR_INVALID_STACK_OPERATION); + + // CheckOps not valid numbers + CheckOpError(stacktype{{0x01, 0x02, 0x03, 0x04, 0x05}, + {0x01, 0x02, 0x03, 0x04, 0x05}}, + OP_DIV, SCRIPT_ERR_UNKNOWN_ERROR); + CheckOpError(stacktype{{0x01, 0x02, 0x03, 0x04, 0x05}, {0x01}}, OP_DIV, + SCRIPT_ERR_UNKNOWN_ERROR); + CheckOpError(stacktype{{0x01, 0x05}, {0x01, 0x02, 0x03, 0x04, 0x05}}, + OP_DIV, SCRIPT_ERR_UNKNOWN_ERROR); + // b == 0 ; b is equal to any type of zero + CheckOpError(stacktype{{0x01, 0x05}, {}}, OP_DIV, SCRIPT_ERR_DIV_BY_ZERO); + CheckOpError(stacktype{{}, {}}, OP_DIV, SCRIPT_ERR_DIV_BY_ZERO); + + for (uint32_t flags : flagset) { + if (flags & SCRIPT_VERIFY_MINIMALDATA) { + CheckError(flags, stacktype{{}, {0x00}}, OP_DIV, + SCRIPT_ERR_UNKNOWN_ERROR); // not minimal encoding + CheckError(flags, stacktype{{}, {0x00, 0x00}}, OP_DIV, + SCRIPT_ERR_UNKNOWN_ERROR); + } else { + CheckError(flags, stacktype{{}, {0x00}}, OP_DIV, + SCRIPT_ERR_DIV_BY_ZERO); + CheckError(flags, stacktype{{}, {0x00, 0x00}}, OP_DIV, + SCRIPT_ERR_DIV_BY_ZERO); + } + } + + // 185377af/85f41b01 =-4 + // 185377af/00001b01 =E69D + CheckOp(valtype{0xaf, 0x77, 0x53, 0x18}, valtype{0x01, 0x1b, 0xf4, 0x85}, + OP_DIV, valtype{0x84}); + CheckOp(valtype{0xaf, 0x77, 0x53, 0x18}, valtype{0x01, 0x1b}, OP_DIV, + valtype{0x9D, 0xE6, 0x00}); + // 15/4 =3 + // 15/-4 =-3 + //-15/4 =-3 + //-15/-4 =3 + CheckOp(valtype{0x0f}, valtype{0x04}, OP_DIV, valtype{0x03}); + CheckOp(valtype{0x0f}, valtype{0x84}, OP_DIV, valtype{0x83}); + CheckOp(valtype{0x8f}, valtype{0x04}, OP_DIV, valtype{0x83}); + CheckOp(valtype{0x8f}, valtype{0x84}, OP_DIV, valtype{0x03}); + // 15000/4 =3750 + // 15000/-4 =-3750 + //-15000/4 =-3750 + //-15000/-4 =3750 + CheckOp(valtype{0x98, 0x3a}, valtype{0x04}, OP_DIV, valtype{0xa6, 0x0e}); + CheckOp(valtype{0x98, 0x3a}, valtype{0x84}, OP_DIV, valtype{0xa6, 0x8e}); + CheckOp(valtype{0x98, 0xba}, valtype{0x04}, OP_DIV, valtype{0xa6, 0x8e}); + CheckOp(valtype{0x98, 0xba}, valtype{0x84}, OP_DIV, valtype{0xa6, 0x0e}); + // 15000/4000 =3 + // 15000/-4000 =-3 + //-15000/4000 =-3 + //-15000/-4000 =3 + CheckOp(valtype{0x98, 0x3a}, valtype{0xa0, 0x0f}, OP_DIV, valtype{0x03}); + CheckOp(valtype{0x98, 0x3a}, valtype{0xa0, 0x8f}, OP_DIV, valtype{0x83}); + CheckOp(valtype{0x98, 0xba}, valtype{0xa0, 0x0f}, OP_DIV, valtype{0x83}); + CheckOp(valtype{0x98, 0xba}, valtype{0xa0, 0x8f}, OP_DIV, valtype{0x03}); + // 15000000/4000 =3750 + // 15000000/-4000 =-3750 + //-15000000/4000 =-3750 + //-15000000/-4000 =3750 + CheckOp(valtype{0xc0, 0xe1, 0xe4, 0x00}, valtype{0xa0, 0x0f}, OP_DIV, + valtype{0xa6, 0x0e}); + CheckOp(valtype{0xc0, 0xe1, 0xe4, 0x00}, valtype{0xa0, 0x8f}, OP_DIV, + valtype{0xa6, 0x8e}); + CheckOp(valtype{0xc0, 0xe1, 0xe4, 0x80}, valtype{0xa0, 0x0f}, OP_DIV, + valtype{0xa6, 0x8e}); + CheckOp(valtype{0xc0, 0xe1, 0xe4, 0x80}, valtype{0xa0, 0x8f}, OP_DIV, + valtype{0xa6, 0x0e}); + // 15000000/4 =3750000 + // 15000000/-4 =-3750000 + //-15000000/4 =-3750000 + //-15000000/-4 =3750000 + CheckOp(valtype{0xc0, 0xe1, 0xe4, 0x00}, valtype{0x04}, OP_DIV, + valtype{0x70, 0x38, 0x39}); + CheckOp(valtype{0xc0, 0xe1, 0xe4, 0x00}, valtype{0x84}, OP_DIV, + valtype{0x70, 0x38, 0xb9}); + CheckOp(valtype{0xc0, 0xe1, 0xe4, 0x80}, valtype{0x04}, OP_DIV, + valtype{0x70, 0x38, 0xb9}); + CheckOp(valtype{0xc0, 0xe1, 0xe4, 0x80}, valtype{0x84}, OP_DIV, + valtype{0x70, 0x38, 0x39}); +} + +BOOST_AUTO_TEST_CASE(mod_opcode_tests) { + CheckOpError(stacktype{}, OP_MOD, SCRIPT_ERR_INVALID_STACK_OPERATION); + CheckOpError(stacktype{{}}, OP_MOD, SCRIPT_ERR_INVALID_STACK_OPERATION); + + // test not valid numbers + CheckOpError(stacktype{{0x01, 0x02, 0x03, 0x04, 0x05}, + {0x01, 0x02, 0x03, 0x04, 0x05}}, + OP_MOD, SCRIPT_ERR_UNKNOWN_ERROR); + CheckOpError(stacktype{{0x01, 0x02, 0x03, 0x04, 0x05}, {0x01}}, OP_MOD, + SCRIPT_ERR_UNKNOWN_ERROR); + CheckOpError(stacktype{{0x01, 0x05}, {0x01, 0x02, 0x03, 0x04, 0x05}}, + OP_MOD, SCRIPT_ERR_UNKNOWN_ERROR); + + // mod by 0 + CheckOpError(stacktype{{0x01, 0x05}, {}}, OP_MOD, SCRIPT_ERR_MOD_BY_ZERO); + + // 56488123%321 =148 + // 56488123%3 =1 + // 56488123%564881230 =56488123 + CheckOp(valtype{0xbb, 0xf0, 0x5d, 0x03}, valtype{0x41, 0x01}, OP_MOD, + valtype{0x94, 0x00}); + CheckOp(valtype{0xbb, 0xf0, 0x5d, 0x03}, valtype{0x03}, OP_MOD, + valtype{0x01}); + CheckOp(valtype{0xbb, 0xf0, 0x5d, 0x03}, valtype{0x4e, 0x67, 0xab, 0x21}, + OP_MOD, valtype{0xbb, 0xf0, 0x5d, 0x03}); + + //-56488123%321 = -148 + //-56488123%3 = -1 + //-56488123%564881230 = -56488123 + CheckOp(valtype{0xbb, 0xf0, 0x5d, 0x83}, valtype{0x41, 0x01}, OP_MOD, + valtype{0x94, 0x80}); + CheckOp(valtype{0xbb, 0xf0, 0x5d, 0x83}, valtype{0x03}, OP_MOD, + valtype{0x81}); + CheckOp(valtype{0xbb, 0xf0, 0x5d, 0x83}, valtype{0x4e, 0x67, 0xab, 0x21}, + OP_MOD, valtype{0xbb, 0xf0, 0x5d, 0x83}); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -92,6 +92,8 @@ {SCRIPT_ERR_NONCOMPRESSED_PUBKEY, "NONCOMPRESSED_PUBKEY"}, {SCRIPT_ERR_ILLEGAL_FORKID, "ILLEGAL_FORKID"}, {SCRIPT_ERR_MUST_USE_FORKID, "MISSING_FORKID"}, + {SCRIPT_ERR_DIV_BY_ZERO, "DIV_BY_ZERO"}, + {SCRIPT_ERR_MOD_BY_ZERO, "MOD_BY_ZERO"}, }; const char *FormatScriptError(ScriptError_t err) {