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_MUL: return true; @@ -1234,6 +1234,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 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"], @@ -982,6 +982,16 @@ ["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC,MAGNETIC_OPCODES", "DISABLED_OPCODE", "disabled"], ["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"], Index: src/test/opcode_tests.cpp =================================================================== --- src/test/opcode_tests.cpp +++ src/test/opcode_tests.cpp @@ -74,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) { @@ -395,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. */