Index: src/script/interpreter.cpp =================================================================== --- src/script/interpreter.cpp +++ src/script/interpreter.cpp @@ -88,7 +88,7 @@ if (fEnabledOpCodesMagnetic) { switch (opcode) { case OP_INVERT: - return true; + return false; case OP_2MUL: return true; @@ -1188,6 +1188,19 @@ } } break; + case OP_INVERT: { + // (x -- out) + if (stack.size() < 1) { + return set_error( + serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + + valtype &x = stacktop(-1); + for (size_t i = 0; i < x.size(); i++) { + x[i] = ~x[i]; + } + } break; + default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } Index: src/test/data/script_tests.json =================================================================== --- src/test/data/script_tests.json +++ src/test/data/script_tests.json @@ -928,8 +928,8 @@ ["NOP", "SIZE 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], ["Disabled opcodes"], -["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "INVERT disabled"], -["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC,MAGNETIC_OPCODES", "DISABLED_OPCODE", "INVERT disabled"], +["'abc' 0", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "INVERT disabled"], +["'abc' 0", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT enabled"], ["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2MUL disabled"], ["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC,MAGNETIC_OPCODES", "DISABLED_OPCODE", "2MUL disabled"], ["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "2DIV disabled"], @@ -952,6 +952,7 @@ ["", "AND 0 EQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "AND, empty stack"], ["0 1", "AND 1 EQUAL", "P2SH,STRICTENC", "OPERAND_SIZE", "AND, different operand size"], ["0x01 0xab 0x01 0xcd", "AND 0x01 0x89 EQUAL", "P2SH,STRICTENC", "OK", "AND, more complex operands"], + ["OR"], ["0 0", "OR 0 EQUAL", "P2SH,STRICTENC", "OK", "OR, empty parameters"], ["0x01 0x00 0x01 0x00", "OR 0x01 0x00 EQUAL", "P2SH,STRICTENC", "OK", "OR, simple and"], @@ -962,6 +963,7 @@ ["", "OR 0 EQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "OR, empty stack"], ["0 1", "OR 1 EQUAL", "P2SH,STRICTENC", "OPERAND_SIZE", "OR, different operand size"], ["0x01 0xab 0x01 0xcd", "OR 0x01 0xef EQUAL", "P2SH,STRICTENC", "OK", "XOR, more complex operands"], + ["XOR"], ["0 0", "XOR 0 EQUAL", "P2SH,STRICTENC", "OK", "XOR, empty parameters"], ["0x01 0x00 0x01 0x00", "XOR 0x01 0x00 EQUAL", "P2SH,STRICTENC", "OK", "XOR, simple and"], @@ -973,6 +975,19 @@ ["0 1", "XOR 1 EQUAL", "P2SH,STRICTENC", "OPERAND_SIZE", "XOR, different operand size"], ["0x01 0xab 0x01 0xcd", "XOR 0x01 0x66 EQUAL", "P2SH,STRICTENC", "OK", "XOR, more complex operands"], +["INVERT"], +["", "INVERT", "P2SH,STRICTENC,MAGNETIC_OPCODES", "INVALID_STACK_OPERATION", "INVERT, invalid parameter count"], +["0x0100", "INVERT 0x01FF EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT, simple"], +["0x01FF", "INVERT 0x0100 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT, simple"], +["0x00", "INVERT 0x00 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT, empty"], +["0x020F0F", "INVERT 0x02F0F0 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT, 2 bytes"], +["0x03FF0000", "INVERT 0x0300FFFF EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT, 3 bytes"], +["0x0300FFFF", "INVERT 0x03FF0000 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT, 3 bytes"], +["0x03FFFFFF", "INVERT 0x03000000 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT, 3 bytes"], +["0x03801234", "INVERT 0x037FEDCB EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT, 3 bytes"], +["0x088012348012341234", "INVERT 0x087FEDCB7FEDCBEDCB EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "OK", "INVERT, 8 bytes"], + +["Arithmetic opcodes"], ["DIV"], ["1 1", "DIV 1 EQUAL", "P2SH,STRICTENC", "OK"], ["1 -1", "DIV -1 EQUAL", "P2SH,STRICTENC", "OK"], Index: src/test/opcode_tests.cpp =================================================================== --- src/test/opcode_tests.cpp +++ src/test/opcode_tests.cpp @@ -30,7 +30,9 @@ for (uint32_t flags : flagset) { ScriptError err = SCRIPT_ERR_OK; stacktype stack{original_stack}; - bool r = EvalScript(stack, script, flags, sigchecker, &err); + bool r = + EvalScript(stack, script, flags | SCRIPT_ENABLE_MAGNETIC_OPCODES, + sigchecker, &err); BOOST_CHECK(r); BOOST_CHECK(stack == expected); } @@ -41,7 +43,8 @@ BaseSignatureChecker sigchecker; ScriptError err = SCRIPT_ERR_OK; stacktype stack{original_stack}; - bool r = EvalScript(stack, script, flags, sigchecker, &err); + bool r = EvalScript(stack, script, flags | SCRIPT_ENABLE_MAGNETIC_OPCODES, + sigchecker, &err); BOOST_CHECK(!r); BOOST_CHECK_EQUAL(err, expected_error); } @@ -71,6 +74,11 @@ CheckTestResultForAllFlags({a, b}, CScript() << op, {expected}); } +static void CheckUnaryOp(const valtype &a, opcodetype op, + const valtype &expected) { + CheckTestResultForAllFlags({a}, CScript() << op, {expected}); +} + static valtype NegativeValtype(const valtype &v) { valtype r(v); if (r.size() > 0) { @@ -392,6 +400,14 @@ CheckAllBitwiseOpErrors({b, {}}, SCRIPT_ERR_INVALID_OPERAND_SIZE); } +BOOST_AUTO_TEST_CASE(invert_test) { + CheckUnaryOp({}, OP_INVERT, {}); + CheckUnaryOp({0x00}, OP_INVERT, {0xFF}); + CheckUnaryOp({0xFF}, OP_INVERT, {0x00}); + CheckUnaryOp({0xFF, 0xA0, 0xCE, 0xA0, 0x96, 0x12}, OP_INVERT, + {0x00, 0x5F, 0x31, 0x5F, 0x69, 0xED}); +} + /** * String opcodes. */