Index: src/script/interpreter.cpp =================================================================== --- src/script/interpreter.cpp +++ src/script/interpreter.cpp @@ -337,8 +337,8 @@ if (opcode == OP_CAT || opcode == OP_SUBSTR || opcode == OP_LEFT || opcode == OP_RIGHT || opcode == OP_INVERT || opcode == OP_2MUL || - opcode == OP_2DIV || opcode == OP_MUL || opcode == OP_DIV || - opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) { + opcode == OP_2DIV || opcode == OP_MUL || opcode == OP_MOD || + opcode == OP_LSHIFT || opcode == OP_RSHIFT) { // Disabled opcodes. return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); } @@ -893,6 +893,7 @@ case OP_ADD: case OP_SUB: + case OP_DIV: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: @@ -909,6 +910,7 @@ return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } + // first two inputs must be minimally encoded numbers CScriptNum bn1(stacktop(-2), fRequireMinimal); CScriptNum bn2(stacktop(-1), fRequireMinimal); CScriptNum bn(0); @@ -921,6 +923,15 @@ bn = bn1 - bn2; break; + case OP_DIV: + // 2nd operand must not be 0 + if (bn2 == 0) { + return set_error( + serror, SCRIPT_ERR_DIV_BY_ZERO); + } + bn = bn1 / bn2; + break; + case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; Index: src/script/script.h =================================================================== --- src/script/script.h +++ src/script/script.h @@ -273,6 +273,13 @@ 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); } Index: src/script/script_error.h =================================================================== --- src/script/script_error.h +++ src/script/script_error.h @@ -34,6 +34,7 @@ SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, SCRIPT_ERR_UNBALANCED_CONDITIONAL, SCRIPT_ERR_INVALID_BITWISE_OPERATION, + SCRIPT_ERR_DIV_BY_ZERO, /* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */ SCRIPT_ERR_NEGATIVE_LOCKTIME, Index: src/script/script_error.cpp =================================================================== --- src/script/script_error.cpp +++ src/script/script_error.cpp @@ -48,6 +48,8 @@ return "Invalid OP_IF construction"; case SCRIPT_ERR_INVALID_BITWISE_OPERATION: return "Invalid bitwise operation (check length of inputs)"; + case SCRIPT_ERR_DIV_BY_ZERO: + return "Invalid division operation"; case SCRIPT_ERR_NEGATIVE_LOCKTIME: return "Negative locktime"; case SCRIPT_ERR_UNSATISFIED_LOCKTIME: Index: src/test/data/script_tests.json =================================================================== --- src/test/data/script_tests.json +++ src/test/data/script_tests.json @@ -826,7 +826,6 @@ ["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2MUL disabled"], ["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2DIV disabled"], ["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MUL disabled"], -["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "DIV disabled"], ["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MOD disabled"], ["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "LSHIFT disabled"], ["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "RSHIFT disabled"], @@ -843,7 +842,6 @@ ["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "UNKNOWN_ERROR", "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"], ["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], Index: src/test/op_code.cpp =================================================================== --- src/test/op_code.cpp +++ src/test/op_code.cpp @@ -202,6 +202,76 @@ } } + /// OP_DIV tests + + void test_div(uint32_t flags) { + CScript script; + script << OP_DIV; + + test(script,stack_t(),flags,SCRIPT_ERR_INVALID_STACK_OPERATION); + test(script,stack_t{{}},flags,SCRIPT_ERR_INVALID_STACK_OPERATION); + + //test not valid numbers + test(script,stack_t{{0x01,0x02,0x03,0x04,0x05},{0x01,0x02,0x03,0x04,0x05}},flags,SCRIPT_ERR_UNKNOWN_ERROR); + test(script,stack_t{{0x01,0x02,0x03,0x04,0x05},{0x01}},flags,SCRIPT_ERR_UNKNOWN_ERROR); + test(script,stack_t{{0x01,0x05},{0x01,0x02,0x03,0x04,0x05}},flags,SCRIPT_ERR_UNKNOWN_ERROR); + //b == 0 ; b is equal to any type of zero + test(script,stack_t{{0x01,0x05},{}},flags,SCRIPT_ERR_DIV_BY_ZERO); + test(script,stack_t{{},{}},flags,SCRIPT_ERR_DIV_BY_ZERO); + if (flags&SCRIPT_VERIFY_MINIMALDATA) { + test(script,stack_t{{},{0x00}},flags,SCRIPT_ERR_UNKNOWN_ERROR); //not minimal encoding + test(script,stack_t{{},{0x00,0x00}},flags,SCRIPT_ERR_UNKNOWN_ERROR); + } + else { + test(script,stack_t{{},{0x00}},flags,SCRIPT_ERR_DIV_BY_ZERO); + test(script,stack_t{{},{0x00,0x00}},flags,SCRIPT_ERR_DIV_BY_ZERO); + } + //185377af/85f41b01 =-4 + //185377af/00001b01 =E69D + test(script,stack_t{{0xaf,0x77,0x53,0x18},{0x01,0x1b,0xf4,0x85}},flags,stack_t{{0x84}}); + test(script,stack_t{{0xaf,0x77,0x53,0x18},{0x01,0x1b}},flags,stack_t{{0x9D,0xE6,0x00}}); + //15/4 =3 + //15/-4 =-3 + //-15/4 =-3 + //-15/-4 =3 + test(script,stack_t{{0x0f},{0x04}},flags,stack_t{{0x03}}); + test(script,stack_t{{0x0f},{0x84}},flags,stack_t{{0x83}}); + test(script,stack_t{{0x8f},{0x04}},flags,stack_t{{0x83}}); + test(script,stack_t{{0x8f},{0x84}},flags,stack_t{{0x03}}); + //15000/4 =3750 + //15000/-4 =-3750 + //-15000/4 =-3750 + //-15000/-4 =3750 + test(script,stack_t{{0x98,0x3a},{0x04}},flags,stack_t{{0xa6,0x0e}}); + test(script,stack_t{{0x98,0x3a},{0x84}},flags,stack_t{{0xa6,0x8e}}); + test(script,stack_t{{0x98,0xba},{0x04}},flags,stack_t{{0xa6,0x8e}}); + test(script,stack_t{{0x98,0xba},{0x84}},flags,stack_t{{0xa6,0x0e}}); + //15000/4000 =3 + //15000/-4000 =-3 + //-15000/4000 =-3 + //-15000/-4000 =3 + test(script,stack_t{{0x98,0x3a},{0xa0,0x0f}},flags,stack_t{{0x03}}); + test(script,stack_t{{0x98,0x3a},{0xa0,0x8f}},flags,stack_t{{0x83}}); + test(script,stack_t{{0x98,0xba},{0xa0,0x0f}},flags,stack_t{{0x83}}); + test(script,stack_t{{0x98,0xba},{0xa0,0x8f}},flags,stack_t{{0x03}}); + //15000000/4000 =3750 + //15000000/-4000 =-3750 + //-15000000/4000 =-3750 + //-15000000/-4000 =3750 + test(script,stack_t{{0xc0,0xe1,0xe4,0x00},{0xa0,0x0f}},flags,stack_t{{0xa6,0x0e}}); + test(script,stack_t{{0xc0,0xe1,0xe4,0x00},{0xa0,0x8f}},flags,stack_t{{0xa6,0x8e}}); + test(script,stack_t{{0xc0,0xe1,0xe4,0x80},{0xa0,0x0f}},flags,stack_t{{0xa6,0x8e}}); + test(script,stack_t{{0xc0,0xe1,0xe4,0x80},{0xa0,0x8f}},flags,stack_t{{0xa6,0x0e}}); + //15000000/4 =3750000 + //15000000/-4 =-3750000 + //-15000000/4 =-3750000 + //-15000000/-4 =3750000 + test(script,stack_t{{0xc0,0xe1,0xe4,0x00},{0x04}},flags,stack_t{{0x70,0x38,0x39}}); + test(script,stack_t{{0xc0,0xe1,0xe4,0x00},{0x84}},flags,stack_t{{0x70,0x38,0xb9}}); + test(script,stack_t{{0xc0,0xe1,0xe4,0x80},{0x04}},flags,stack_t{{0x70,0x38,0xb9}}); + test(script,stack_t{{0xc0,0xe1,0xe4,0x80},{0x84}},flags,stack_t{{0x70,0x38,0x39}}); + } + } /// Entry points @@ -229,5 +299,12 @@ test_xor(STANDARD_LOCKTIME_VERIFY_FLAGS); } +BOOST_AUTO_TEST_CASE(op_div) { + test_div(0); + test_div(STANDARD_SCRIPT_VERIFY_FLAGS); + test_div(STANDARD_NOT_MANDATORY_VERIFY_FLAGS); + test_div(STANDARD_LOCKTIME_VERIFY_FLAGS); +} + BOOST_AUTO_TEST_SUITE_END()