diff --git a/src/Makefile.test.include b/src/Makefile.test.include --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -58,6 +58,7 @@ test/mempool_tests.cpp \ test/merkle_tests.cpp \ test/miner_tests.cpp \ + test/monolith_opcodes.cpp \ test/multisig_tests.cpp \ test/net_tests.cpp \ test/netbase_tests.cpp \ diff --git a/src/script/interpreter.h b/src/script/interpreter.h --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -111,6 +111,10 @@ // Do we accept activate replay protection using a different fork id. // SCRIPT_ENABLE_REPLAY_PROTECTION = (1U << 17), + + // Enable new opcodes activated from 15 May 2018 HF + // + SCRIPT_ENABLE_OPCODES_MONOLITH = (1U << 18), }; bool CheckSignatureEncoding(const std::vector &vchSig, uint32_t flags, diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -312,6 +312,7 @@ } int nOpCount = 0; bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; + bool fEnabledOpCodesMonolith = (flags & SCRIPT_ENABLE_OPCODES_MONOLITH) != 0; try { while (pc < pend) { @@ -332,12 +333,8 @@ return set_error(serror, SCRIPT_ERR_OP_COUNT); } - if (opcode == OP_CAT || opcode == OP_SPLIT || - opcode == OP_NUM2BIN || opcode == OP_BIN2NUM || - opcode == OP_INVERT || opcode == OP_AND || opcode == OP_OR || - opcode == OP_XOR || opcode == OP_2MUL || opcode == OP_2DIV || - opcode == OP_MUL || opcode == OP_DIV || opcode == OP_MOD || - opcode == OP_LSHIFT || opcode == OP_RSHIFT) { + if (opcode == OP_INVERT || opcode == OP_2MUL || opcode == OP_2DIV || + opcode == OP_MUL || opcode == OP_LSHIFT || opcode == OP_RSHIFT) { // Disabled opcodes. return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); } @@ -778,6 +775,15 @@ // // Bitwise logic // + case OP_AND: + case OP_OR: + case OP_XOR: { + if (!fEnabledOpCodesMonolith) { + // Disabled opcodes. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); + } + } break; + case OP_EQUAL: case OP_EQUALVERIFY: // case OP_NOTEQUAL: // use OP_NUMNOTEQUAL @@ -856,6 +862,8 @@ case OP_ADD: case OP_SUB: + case OP_DIV: + case OP_MOD: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: @@ -884,6 +892,20 @@ bn = bn1 - bn2; break; + case OP_DIV: + if (!fEnabledOpCodesMonolith) { + // Disabled opcode. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); + } + break; + + case OP_MOD: + if (!fEnabledOpCodesMonolith) { + // Disabled opcode. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); + } + break; + case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; @@ -1177,6 +1199,40 @@ } } break; + // + // Byte string operations + // + case OP_CAT: { + if (!fEnabledOpCodesMonolith) { + // Disabled opcodes. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); + } + } break; + + case OP_SPLIT: { + if (!fEnabledOpCodesMonolith) { + // Disabled opcodes. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); + } + } break; + + // + // Conversion operations + // + case OP_BIN2NUM: { + if (!fEnabledOpCodesMonolith) { + // Disabled opcodes. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); + } + } break; + + case OP_NUM2BIN: { + if (!fEnabledOpCodesMonolith) { + // Disabled opcodes. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); + } + } break; + default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } 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 @@ -33,6 +33,12 @@ SCRIPT_ERR_INVALID_STACK_OPERATION, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, SCRIPT_ERR_UNBALANCED_CONDITIONAL, + SCRIPT_ERR_INVALID_BITWISE_LENGTH, + SCRIPT_ERR_DIV_BY_ZERO, + SCRIPT_ERR_MOD_BY_ZERO, + SCRIPT_ERR_INVALID_SPLIT_RANGE, + SCRIPT_ERR_INVALID_BIN2NUM_OPERATION, + SCRIPT_ERR_INVALID_NUM2BIN_OPERATION, /* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */ SCRIPT_ERR_NEGATIVE_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 @@ -46,6 +46,18 @@ return "OP_RETURN was encountered"; case SCRIPT_ERR_UNBALANCED_CONDITIONAL: return "Invalid OP_IF construction"; + case SCRIPT_ERR_INVALID_BITWISE_LENGTH: + return "Invalid bitwise operation (check length of inputs)"; + case SCRIPT_ERR_DIV_BY_ZERO: + return "Invalid division operation"; + case SCRIPT_ERR_MOD_BY_ZERO: + return "Invalid modulo operation"; + case SCRIPT_ERR_INVALID_SPLIT_RANGE: + return "Invalid OP_SPLIT range"; + case SCRIPT_ERR_INVALID_BIN2NUM_OPERATION: + return "Invalid OP_BIN2NUM operation (check operand values)"; + case SCRIPT_ERR_INVALID_NUM2BIN_OPERATION: + return "Invalid OP_NUM2BIN operation (check operand values)"; case SCRIPT_ERR_NEGATIVE_LOCKTIME: return "Negative locktime"; case SCRIPT_ERR_UNSATISFIED_LOCKTIME: diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -35,6 +35,7 @@ mempool_tests.cpp merkle_tests.cpp miner_tests.cpp + monolith_opcodes.cpp multisig_tests.cpp net_tests.cpp netbase_tests.cpp 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 @@ -818,26 +818,43 @@ ["1", "2 3 2SWAP 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], ["'a' 'b'", "CAT", "P2SH,STRICTENC", "DISABLED_OPCODE", "CAT disabled"], -["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "CAT disabled"], +["'a' 'b' 1", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "CAT disabled"], ["'abc' 1 1", "SPLIT", "P2SH,STRICTENC", "DISABLED_OPCODE", "SPLIT disabled"], -["'abc' 1 1 0", "IF SPLIT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "SPLIT disabled"], -["'abc' 2 0", "IF NUM2BIN ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "NUM2BIN disabled"], -["'abc' 2 0", "IF BIN2NUM ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "BIN2NUM disabled"], +["'abc' 1 1 1", "IF SPLIT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "SPLIT disabled"], +["'abc' 2 1", "IF NUM2BIN ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "NUM2BIN disabled"], +["'abc' 2 1", "IF BIN2NUM ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "BIN2NUM disabled"], ["NOP", "SIZE 1", "P2SH,STRICTENC", "INVALID_STACK_OPERATION"], ["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "DISABLED_OPCODE", "INVERT disabled"], -["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "AND disabled"], -["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "OR disabled"], -["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "XOR disabled"], +["1 2 1 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "AND disabled"], +["1 2 1 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "OR disabled"], +["1 2 1 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "XOR disabled"], ["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 1 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "MUL disabled"], +["2 2 1 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DISABLED_OPCODE", "DIV disabled"], +["2 2 1 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"], +["0x02 0x0011 0x02 0x0011 0x02 0x0011", "AND EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0x02 0x1111 0x02 0x1111 0x02 0x1111", "AND EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0x02 0x1111 0x02 0x1111 0x02 0x0101", "OR EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0x02 0x0011 0x02 0x0000 0x02 0x0011", "OR EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0x02 0x0000 0x02 0x1111 0x02 0x1111", "XOR EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0x02 0x0011 0x02 0x0000 0x02 0x0011", "XOR EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["100 200 2", "DIV EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0 0 100", "DIV EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["1 10 3", "MOD EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0 1 1", "MOD EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["'abcdef' 'abc' 'def'", "CAT EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0x02 0x4141 0x01 0x41 0x01 0x41", "CAT EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["'abc' 'def' 'abcdef' 3 1", "IF SPLIT EQUAL ENDIF IF EQUAL ENDIF", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["'abcd' 'ef' 'abcdef' 4 1", "IF SPLIT EQUAL ENDIF IF EQUAL ENDIF", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["100 0x02 0x0064", "BIN2NUM EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], +["0x04 0x00000064 100 4", "NUM2BIN EQUAL", "P2SH,STRICTENC,MONOLITH_OPCODES", "OK"], + ["", "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"], ["0 1","EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], diff --git a/src/test/monolith_opcodes.cpp b/src/test/monolith_opcodes.cpp new file mode 100644 --- /dev/null +++ b/src/test/monolith_opcodes.cpp @@ -0,0 +1,834 @@ +// Copyright (c) 2011-2018 The Bitcoin Cash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "policy/policy.h" +#include "script/interpreter.h" +#include "script/script.h" +#include +#include + +#ifdef VERBOSE +#undef VERBOSE +#endif + +//-------------------------- +// uncomment the following line to see debug output +//#define VERBOSE +//-------------------------- + +#ifdef VERBOSE +#include "core_io.h" +#include +#include +#endif + +namespace { +typedef std::vector item; +typedef std::vector stack_t; + +#ifdef VERBOSE +void print(const item &i) { + if (i.empty()) std::cout << "empty"; + for (auto &s : i) + std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)s << " "; + std::cout << std::endl; +} +void print(const stack_t &i) { + for (auto &s : i) + print(s); + std::cout << std::endl; +} +#endif + +/// Deepest sole function for testing expected errors +/// Invokes the interpreter. +void test(const CScript &script, stack_t stack, uint32_t flags, + const ScriptError se) { +#ifdef VERBOSE + std::cout << "--------------" << std::endl; + std::cout << "Checking script \"" << FormatScript(script) << "\" flags " << flags + << std::endl; + std::cout << "with input stack: " << std::endl; + print(stack); + std::cout << "expected error: " << se << std::endl; +#endif + ScriptError err; + BaseSignatureChecker sigchecker; + bool fEnabledOpCodesMonolith = (flags & SCRIPT_ENABLE_OPCODES_MONOLITH) != 0; + bool r; + // opcode is disabled + if (!fEnabledOpCodesMonolith) { + err = SCRIPT_ERR_DISABLED_OPCODE; + r = EvalScript(stack, script, flags, sigchecker, &err); + } + // opcode is not disabled + else { + err = SCRIPT_ERR_OK; + r = EvalScript(stack, script, flags, sigchecker, &err); + BOOST_CHECK_EQUAL(err == se, true); + } + BOOST_CHECK_EQUAL(r, false); + +#ifdef VERBOSE + std::cout << "got error: " << err << " vs " << se << std::endl; +#endif +} + +/// Deepest sole function for testing expected returning stacks +/// Invokes the interpreter. +void test(const CScript &script, stack_t stack, uint32_t flags, + stack_t expected) { +#ifdef VERBOSE + std::cout << "--------------" << std::endl; + std::cout << "Checking script \"" << FormatScript(script) << "\" flags " << flags + << std::endl; + std::cout << "with input stack: " << std::endl; + print(stack); + std::cout << "expected output stack: " << std::endl; + print(expected); +#endif + ScriptError err; + BaseSignatureChecker sigchecker; + bool r = EvalScript(stack, script, flags, sigchecker, &err); +#ifdef VERBOSE + std::cout << "got output stack: " << std::endl; + print(stack); +#endif + bool fEnabledOpCodesMonolith = (flags & SCRIPT_ENABLE_OPCODES_MONOLITH) != 0; + // opcode is disabled + if (!fEnabledOpCodesMonolith) { + BOOST_CHECK_EQUAL(r, false); + BOOST_CHECK_EQUAL(err, SCRIPT_ERR_DISABLED_OPCODE); + } + // opcode is not disabled + else { + BOOST_CHECK_EQUAL(r, true); + BOOST_CHECK_EQUAL(err, SCRIPT_ERR_OK); + BOOST_CHECK_EQUAL(stack == expected, true); + } +} + +/// OP_AND, OP_OR, and OP_XOR + +void test_bitwiseop(const CScript &script, uint32_t flags) { + // number of inputs + test(script, stack_t(), flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + test(script, stack_t(), flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + test(script, stack_t{{0x01}}, flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + + // where len(x1) == 0 == len(x2) the output will be an empty array. + test(script, stack_t{{}, {}}, flags, stack_t{{}}); + + // operation fails when length of operands not equal + test(script, stack_t{{0x01}, {}}, flags, + SCRIPT_ERR_INVALID_BITWISE_LENGTH); + test(script, stack_t{{0x01, 0x01}, {}}, flags, + SCRIPT_ERR_INVALID_BITWISE_LENGTH); + test(script, stack_t{{}, {0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_LENGTH); + test(script, stack_t{{}, {0x01, 0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_LENGTH); + test(script, stack_t{{0x01}, {0x01, 0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_LENGTH); + test(script, stack_t{{0x01, 0x01}, {0x01, 0x01, 0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_LENGTH); + test(script, stack_t{{0x01, 0x01}, {0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_LENGTH); + test(script, stack_t{{0x01, 0x01, 0x01}, {0x01, 0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_LENGTH); +} + +/// OP_AND + +void test_and(uint32_t flags) { + CScript script; + script << OP_AND; + test_bitwiseop(script, flags); + test(script, stack_t{{0x00}, {0x00}}, flags, stack_t{{0x00}}); + test(script, stack_t{{0x00}, {0x01}}, flags, stack_t{{0x00}}); + test(script, stack_t{{0x01}, {0x00}}, flags, stack_t{{0x00}}); + test(script, stack_t{{0x01}, {0x01}}, flags, stack_t{{0x01}}); + + test(script, stack_t{{0x00, 0x00}, {0x00, 0x00}}, flags, + stack_t{{0x00, 0x00}}); + test(script, stack_t{{0x00, 0x00}, {0x01, 0x00}}, flags, + stack_t{{0x00, 0x00}}); + test(script, stack_t{{0x01, 0x00}, {0x00, 0x00}}, flags, + stack_t{{0x00, 0x00}}); + test(script, stack_t{{0x01, 0x00}, {0x01, 0x00}}, flags, + stack_t{{0x01, 0x00}}); + + { + item maxlenbin1(MAX_SCRIPT_ELEMENT_SIZE, 0x01); + item maxlenbin2(MAX_SCRIPT_ELEMENT_SIZE, 0xF0); + item maxlenbin3(MAX_SCRIPT_ELEMENT_SIZE, 0x01 & 0xF0); + test(script, stack_t{maxlenbin1, maxlenbin2}, flags, + stack_t{maxlenbin3}); + } + + { + item maxlenbin1(MAX_SCRIPT_ELEMENT_SIZE, 0x3C); + item maxlenbin2(MAX_SCRIPT_ELEMENT_SIZE, 0xDB); + item maxlenbin3(MAX_SCRIPT_ELEMENT_SIZE, 0x3C & 0xDB); + test(script, stack_t{maxlenbin1, maxlenbin2}, flags, + stack_t{maxlenbin3}); + } +} + +/// OP_OR + +void test_or(uint32_t flags) { + CScript script; + script << OP_OR; + test_bitwiseop(script, flags); + + test(script, stack_t{{0x00}, {0x00}}, flags, stack_t{{0x00}}); + test(script, stack_t{{0x00}, {0x01}}, flags, stack_t{{0x01}}); + test(script, stack_t{{0x01}, {0x00}}, flags, stack_t{{0x01}}); + test(script, stack_t{{0x01}, {0x01}}, flags, stack_t{{0x01}}); + + test(script, stack_t{{0x00, 0x00}, {0x00, 0x00}}, flags, + stack_t{{0x00, 0x00}}); + test(script, stack_t{{0x00, 0x00}, {0x01, 0x00}}, flags, + stack_t{{0x01, 0x00}}); + test(script, stack_t{{0x01, 0x00}, {0x00, 0x00}}, flags, + stack_t{{0x01, 0x00}}); + test(script, stack_t{{0x01, 0x00}, {0x01, 0x00}}, flags, + stack_t{{0x01, 0x00}}); + + { + item maxlenbin1(MAX_SCRIPT_ELEMENT_SIZE, 0x01); + item maxlenbin2(MAX_SCRIPT_ELEMENT_SIZE, 0xF0); + item maxlenbin3(MAX_SCRIPT_ELEMENT_SIZE, 0x01 | 0xF0); + test(script, stack_t{maxlenbin1, maxlenbin2}, flags, + stack_t{maxlenbin3}); + } + + { + item maxlenbin1(MAX_SCRIPT_ELEMENT_SIZE, 0x3C); + item maxlenbin2(MAX_SCRIPT_ELEMENT_SIZE, 0xDB); + item maxlenbin3(MAX_SCRIPT_ELEMENT_SIZE, 0x3C | 0xDB); + test(script, stack_t{maxlenbin1, maxlenbin2}, flags, + stack_t{maxlenbin3}); + } +} + +/// OP_XOR tests + +void test_xor(uint32_t flags) { + CScript script; + script << OP_XOR; + test_bitwiseop(script, flags); + + test(script, stack_t{{0x00}, {0x00}}, flags, stack_t{{0x00}}); + test(script, stack_t{{0x00}, {0x01}}, flags, stack_t{{0x01}}); + test(script, stack_t{{0x01}, {0x00}}, flags, stack_t{{0x01}}); + test(script, stack_t{{0x01}, {0x01}}, flags, stack_t{{0x00}}); + + test(script, stack_t{{0x00, 0x00}, {0x00, 0x00}}, flags, + stack_t{{0x00, 0x00}}); + test(script, stack_t{{0x00, 0x00}, {0x01, 0x00}}, flags, + stack_t{{0x01, 0x00}}); + test(script, stack_t{{0x01, 0x00}, {0x00, 0x00}}, flags, + stack_t{{0x01, 0x00}}); + test(script, stack_t{{0x01, 0x00}, {0x01, 0x00}}, flags, + stack_t{{0x00, 0x00}}); + + { + item maxlenbin1(MAX_SCRIPT_ELEMENT_SIZE, 0x01); + item maxlenbin2(MAX_SCRIPT_ELEMENT_SIZE, 0xF0); + item maxlenbin3(MAX_SCRIPT_ELEMENT_SIZE, 0x01 ^ 0xF0); + test(script, stack_t{maxlenbin1, maxlenbin2}, flags, + stack_t{maxlenbin3}); + } + + { + item maxlenbin1(MAX_SCRIPT_ELEMENT_SIZE, 0x3C); + item maxlenbin2(MAX_SCRIPT_ELEMENT_SIZE, 0xDB); + item maxlenbin3(MAX_SCRIPT_ELEMENT_SIZE, 0x3C ^ 0xDB); + test(script, stack_t{maxlenbin1, maxlenbin2}, flags, + stack_t{maxlenbin3}); + } +} + +/// 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}}); +} + +/// OP_MOD tests + +void test_mod(uint32_t flags) { + CScript script; + script << OP_MOD; + + 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); + + // mod by 0 + test(script, stack_t{{0x01, 0x05}, {}}, flags, SCRIPT_ERR_MOD_BY_ZERO); + + // 56488123%321 =148 + // 56488123%3 =1 + // 56488123%564881230 =56488123 + test(script, stack_t{{0xbb, 0xf0, 0x5d, 0x03}, {0x41, 0x01}}, flags, + stack_t{{0x94, 0x00}}); + test(script, stack_t{{0xbb, 0xf0, 0x5d, 0x03}, {0x03}}, flags, + stack_t{{0x01}}); + test(script, stack_t{{0xbb, 0xf0, 0x5d, 0x03}, {0x4e, 0x67, 0xab, 0x21}}, + flags, stack_t{{0xbb, 0xf0, 0x5d, 0x03}}); + + //-56488123%321 = -148 + //-56488123%3 = -1 + //-56488123%564881230 = -56488123 + test(script, stack_t{{0xbb, 0xf0, 0x5d, 0x83}, {0x41, 0x01}}, flags, + stack_t{{0x94, 0x80}}); + test(script, stack_t{{0xbb, 0xf0, 0x5d, 0x83}, {0x03}}, flags, + stack_t{{0x81}}); + test(script, stack_t{{0xbb, 0xf0, 0x5d, 0x83}, {0x4e, 0x67, 0xab, 0x21}}, + flags, stack_t{{0xbb, 0xf0, 0x5d, 0x83}}); +} + +/// OP_CAT + +void test_cat(uint32_t flags) { + CScript script; + script << OP_CAT; + + // two inputs required + test(script, stack_t(), flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + test(script, stack_t{{0x00}}, flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + + // stack item with maximum length + item maxlength_item(MAX_SCRIPT_ELEMENT_SIZE, 0x00); + + // Concatenation producing illegal sized output + { + stack_t input_stack; + input_stack.push_back(maxlength_item); + item i; + i.push_back(0x00); + input_stack.push_back(i); + test(script, input_stack, flags, SCRIPT_ERR_PUSH_SIZE); + } + + // Concatenation of a max-sized item with empty is legal + { + stack_t input_stack; + input_stack.push_back(maxlength_item); + input_stack.push_back(item()); // empty item + test(script, input_stack, flags, stack_t{maxlength_item}); + } + { + stack_t input_stack; + input_stack.push_back(item()); // empty item + input_stack.push_back(maxlength_item); + test(script, input_stack, flags, stack_t{maxlength_item}); + } + + // Concatenation of a zero length operand + test(script, stack_t{{0x01}, {}}, flags, stack_t{{0x01}}); + test(script, stack_t{{}, {0x01}}, flags, stack_t{{0x01}}); + + // Concatenation of two empty operands results in empty item + test(script, stack_t{{}, {}}, flags, stack_t{{}}); + + // concatenating two operands generates the correct result + test(script, stack_t{{0x00}, {0x00}}, flags, stack_t{{0x00, 0x00}}); + test(script, stack_t{{0x01}, {0x02}}, flags, stack_t{{0x01, 0x02}}); + test(script, + stack_t{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, + {0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14}}, + flags, + stack_t{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14}}); +} + +/// OP_SPLIT + +void test_split(uint32_t flags) { + CScript script; + script << OP_SPLIT; // inputs: x n; outputs: x1 x2 + + // two inputs required + test(script, stack_t(), flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + test(script, stack_t{{0x01}}, flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + + // length of 2nd input greater than CScriptNum::nDefaultMaxNumSize + { + item maxlength_num_item(CScriptNum::nDefaultMaxNumSize, 0x01); + item illegal_item = maxlength_num_item; + illegal_item.push_back(0x00); + test(script, stack_t{{0x01}, illegal_item}, flags, + SCRIPT_ERR_UNKNOWN_ERROR); + } + + // if n == 0, then x1 is the empty array and x2 == x; + // execution of OP_SPLIT on empty array results in two empty arrays. + test(script, stack_t{{}, {}}, flags, stack_t{{}, {}}); + test(script, stack_t{{0x01}, {}}, flags, + stack_t{{}, {0x01}}); // x 0 OP_SPLIT -> OP_0 x + test(script, stack_t{{0x01, 0x02, 0x03, 0x04}, {}}, flags, + stack_t{{}, {0x01, 0x02, 0x03, 0x04}}); + + // if n == len(x) then x1 == x and x2 is the empty array + test(script, stack_t{{0x01}, {0x01}}, flags, stack_t{{0x01}, {}}); + test(script, stack_t{{0x01, 0x02, 0x03}, {0x03}}, flags, + stack_t{{0x01, 0x02, 0x03}, {}}); // x len(x) OP_SPLIT -> x OP_0 + + // if n > len(x), then the operator must fail; x (len(x) + 1) OP_SPLIT -> + // FAIL + test(script, stack_t{{}, {0x01}}, flags, SCRIPT_ERR_INVALID_SPLIT_RANGE); + test(script, stack_t{{0x01}, {0x02}}, flags, + SCRIPT_ERR_INVALID_SPLIT_RANGE); + test(script, stack_t{{0x01, 0x02, 0x03}, {0x04}}, flags, + SCRIPT_ERR_INVALID_SPLIT_RANGE); + test(script, stack_t{{0x01, 0x02, 0x03, 0x04}, {0x05}}, flags, + SCRIPT_ERR_INVALID_SPLIT_RANGE); + + // if n < 0 the operator must fail. + test(script, stack_t{{0x01, 0x02, 0x03, 0x04}, {0x81}}, flags, + SCRIPT_ERR_INVALID_SPLIT_RANGE); + + test(script, stack_t{{0x01, 0x02, 0x03, 0x04}, {0x01}}, flags, + stack_t{{0x01}, {0x02, 0x03, 0x04}}); + test(script, stack_t{{0x01, 0x02, 0x03, 0x04}, {0x02}}, flags, + stack_t{{0x01, 0x02}, {0x03, 0x04}}); + test(script, stack_t{{0x01, 0x02, 0x03, 0x04}, {0x03}}, flags, + stack_t{{0x01, 0x02, 0x03}, {0x04}}); + test(script, stack_t{{0x01, 0x02, 0x03, 0x04}, {0x04}}, flags, + stack_t{{0x01, 0x02, 0x03, 0x04}, {}}); + + // split of a max-len item + { + item maxlength_item(MAX_SCRIPT_ELEMENT_SIZE, 0x00); + test(script, stack_t{maxlength_item, {}}, flags, + stack_t{{}, maxlength_item}); + } +} + +/// OP_CAT + OP_SPLIT + +void test_cat_split(const item &x, uint32_t flags) { + CScript script; + script << OP_SPLIT << OP_CAT; + // x n OP_SPLIT OP_CAT -> x - for all x and for all 0 <= n <= len(x) + test(script, stack_t{x, {}}, flags, stack_t{x}); + for (uint8_t i = 1; i <= x.size(); ++i) { + test(script, stack_t{x, {i}}, flags, stack_t{x}); + } +} + +void test_cat_split(uint32_t flags) { + test_cat_split({}, flags); + test_cat_split({0x01}, flags); + test_cat_split({0x01, 0x02}, flags); + test_cat_split({0x01, 0x02, 0x03}, flags); +} + +/// OP_BIN2NUM tests + +/// make bin - helper function +/// input: a number +/// output: BIN representation Big Endian (BE) +/// removes the sign, constructs a BE array of bytes with the positive +/// number, +/// the adds the sign. +item mk_bin(int64_t numBinary) { + if (numBinary == 0) return item{0x00}; + bool neg = numBinary < 0; + uint64_t v = htobe64(neg ? -numBinary : numBinary); + item result; + result.reserve(sizeof(uint64_t)); + uint8_t *p = reinterpret_cast(&v); + for (size_t i = 0; i < sizeof(uint64_t); ++i, ++p) { + if (result.empty()) { + if (!*p) continue; + if (*p & 0x80) + result.push_back(0x00); // first bit looks like a sign but it is + // not, add a leading 0 + } + result.push_back(*p); + } + if (neg) *result.begin() |= 0x80; // add the sign + return move(result); +} + +void test_bin2num(uint32_t flags) { + CScript script; + script << OP_BIN2NUM; + { + item i{0x00, 0x80, 0x00, 0x05}; + BOOST_CHECK_EQUAL(mk_bin(0x800005) == i, true); + } + { + item i{0x05}; + BOOST_CHECK_EQUAL(mk_bin(0x000005) == i, true); + } + { + item i{0x01, 0x05}; + BOOST_CHECK_EQUAL(mk_bin(0x000105) == i, true); + } + { + item i{0x81, 0x05}; + BOOST_CHECK_EQUAL(mk_bin(-0x000105) == i, true); + } + test(script, stack_t(), flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + test(script, stack_t{mk_bin(0)}, flags, stack_t{{}}); + test(script, stack_t{mk_bin((int64_t)INT_MAX >> 1)}, flags, + stack_t{CScriptNum(INT_MAX >> 1).getvch()}); + test(script, stack_t{mk_bin((int64_t)INT_MIN >> 1)}, flags, + stack_t{CScriptNum(INT_MIN >> 1).getvch()}); + test(script, stack_t{mk_bin((int64_t)(INT_MAX >> 1) + 1)}, flags, + SCRIPT_ERR_INVALID_BIN2NUM_OPERATION); + test(script, stack_t{mk_bin((int64_t)(INT_MIN >> 1) - 1)}, flags, + SCRIPT_ERR_INVALID_BIN2NUM_OPERATION); + test(script, stack_t{mk_bin(106894)}, flags, + stack_t{CScriptNum(106894).getvch()}); + test(script, stack_t{mk_bin(-106894)}, flags, + stack_t{CScriptNum(-106894).getvch()}); + test(script, stack_t{mk_bin(0)}, flags, stack_t{CScriptNum(0).getvch()}); +} + +/// OP_NUM2BIN tests + +/// make expected value - helper function +/// input: number in LE byte order, desired output byte length +/// output: BIN representation as expected to be generated by the +/// interpreter. +/// removes the sign, constructs a BE array of bytes with the positive +/// number, +/// the adds the sign. +/// +std::vector make_ev(std::vector vchInput, size_t size) { + if (vchInput.empty()) return std::vector(size, 0); + std::vector result; + assert(size >= vchInput.size()); + result.reserve(size); + bool neg = *vchInput.rbegin() & 0x80; + *vchInput.rbegin() &= ~0x80; + size_t pad = size - vchInput.size(); + for (uint8_t i = 0; i < pad; ++i) { + result.push_back(0); + } + for (auto i = vchInput.rbegin(); i != vchInput.rend(); ++i) { + result.push_back(*i); + } + if (neg) *result.begin() |= 0x80; + return result; +} + +void test_num2bin(const CScript &script, std::vector vchInput, + uint32_t flags) { + if (vchInput.empty()) return; + for (uint8_t i = 0; i < vchInput.size(); ++i) { + if (i == 0) + test(script, stack_t{vchInput, {}}, flags, + SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); + else + test(script, stack_t{vchInput, {i}}, flags, + SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); + } + for (uint8_t i = vchInput.size(); i <= CScriptNum::nDefaultMaxNumSize; + ++i) { + if (i == 0) + test(script, stack_t{vchInput, {}}, flags, + stack_t{make_ev(vchInput, i)}); + else + test(script, stack_t{vchInput, {i}}, flags, + stack_t{make_ev(vchInput, i)}); + } +} + +void test_num2bin(uint32_t flags) { + CScript script; + script << OP_NUM2BIN; + test(script, stack_t(), flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + test(script, stack_t{{4}}, flags, SCRIPT_ERR_INVALID_STACK_OPERATION); + test(script, stack_t{{0x02}, {CScriptNum::nDefaultMaxNumSize + 1}}, flags, + SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); + test(script, stack_t{{0x85}, {CScriptNum::nDefaultMaxNumSize + 1}}, flags, + SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); + test(script, stack_t{{0x02}, {}}, flags, + SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); + test(script, stack_t{{0x85}, {0x85}}, flags, + SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); + test(script, stack_t{{0x85}, {}}, flags, + SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); + test_num2bin(script, {}, flags); + test_num2bin(script, {0x7f}, flags); + test_num2bin(script, {0xff, 0x7f}, flags); // LE for 0x7FFF + test_num2bin(script, {0x02, 0x71}, flags); + test_num2bin(script, {0xff, 0xff, 0x7f}, flags); + test_num2bin(script, {0x03, 0x02, 0x71}, flags); + test_num2bin(script, {0xff, 0xff, 0xff, 0x7f}, flags); + test_num2bin(script, {0x04, 0x03, 0x02, 0x71}, flags); + test_num2bin(script, {0x81}, flags); + test_num2bin(script, {0xff, 0x80}, flags); + test_num2bin(script, {0xaf, 0x81}, flags); + test_num2bin(script, {0xed, 0x60, 0x83}, flags); + test_num2bin(script, {0xb6, 0xe3, 0x81}, flags); + test_num2bin(script, {0x81, 0x9a, 0x6e, 0x84}, flags); + test_num2bin(script, {0xe4, 0xc3, 0x92, 0x91}, flags); +} + +/// OP_BIN2NUM + OP_NUM2BIN tests + +void test_bin2num_num2bin(const CScript &script, size_t size, int64_t numBinary, + uint32_t flags) { + auto x = mk_bin(numBinary); + test(script, stack_t{x}, flags, + stack_t{make_ev(CScriptNum(numBinary).getvch(), size)}); +} + +void test_num2bin_bin2num(const CScript &script, int64_t numBinary, + uint32_t flags) { + test(script, stack_t{CScriptNum(numBinary).getvch()}, flags, + stack_t{CScriptNum(numBinary).getvch()}); +} + +void test_bin2num_num2bin(int size, uint32_t flags) { + CScript script; + script << OP_BIN2NUM << size << OP_NUM2BIN; + test_bin2num_num2bin(script, size, 0, flags); + test_bin2num_num2bin(script, size, 1, flags); + test_bin2num_num2bin(script, size, -1, flags); + if (size >= 2) { + test_bin2num_num2bin(script, size, 321, flags); + test_bin2num_num2bin(script, size, -321, flags); + if (size >= 3) { + test_bin2num_num2bin(script, size, 106894, flags); + test_bin2num_num2bin(script, size, -106894, flags); + if (size >= 4) { + test_bin2num_num2bin(script, size, INT_MAX >> 1, flags); + test_bin2num_num2bin(script, size, INT_MIN >> 1, flags); + } + } + } +} + +void test_num2bin_bin2num(int size, uint32_t flags) { + CScript script; + script << size << OP_NUM2BIN << OP_BIN2NUM; + test_num2bin_bin2num(script, 0, flags); + test_num2bin_bin2num(script, 1, flags); + test_num2bin_bin2num(script, -1, flags); + if (size >= 2) { + test_num2bin_bin2num(script, 321, flags); + test_num2bin_bin2num(script, -321, flags); + if (size >= 3) { + test_num2bin_bin2num(script, 106894, flags); + test_num2bin_bin2num(script, -106894, flags); + if (size >= 4) { + test_num2bin_bin2num(script, INT_MAX >> 1, flags); + test_num2bin_bin2num(script, INT_MIN >> 1, flags); + } + } + } +} + +void test_bin2num_num2bin(uint32_t flags) { + test_bin2num_num2bin(4, flags); // expect 4 byte output + test_bin2num_num2bin(3, flags); // expect 3 byte output + test_bin2num_num2bin(2, flags); // expect 2 byte output + test_bin2num_num2bin(1, flags); // expect 1 byte output +} + +void test_num2bin_bin2num(uint32_t flags) { + test_num2bin_bin2num(4, flags); // 4 byte num2bin output + test_num2bin_bin2num(3, flags); // 3 byte num2bin output + test_num2bin_bin2num(2, flags); // 2 byte num2bin output + test_num2bin_bin2num(1, flags); // 1 byte num2bin output +} +} + +/// Entry points + +BOOST_AUTO_TEST_SUITE(opcodes) + +BOOST_AUTO_TEST_CASE(op_and) { + test_and(0); + test_and(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_and(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_and(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_and(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(op_or) { + test_or(0); + test_or(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_or(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_or(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_or(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(op_xor) { + test_xor(0); + test_xor(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_xor(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_xor(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_xor(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(op_div) { + test_div(0); + test_div(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_div(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_div(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_div(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(op_mod) { + test_mod(0); + test_mod(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_mod(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_mod(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_mod(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(op_cat) { + test_cat(0); + test_cat(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_cat(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_cat(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_cat(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(op_split) { + test_split(0); + test_split(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_split(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_split(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_split(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(cat_split) { + test_cat_split(0); + test_cat_split(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_cat_split(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_cat_split(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_cat_split(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(op_bin2num) { + test_bin2num(0); + test_bin2num(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_bin2num(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_bin2num(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_bin2num(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(op_num2bin) { + test_bin2num(0); + test_num2bin(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_num2bin(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_num2bin(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_num2bin(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(bin2num_num2bin) { + test_bin2num_num2bin(0); + test_bin2num_num2bin(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_bin2num_num2bin(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_bin2num_num2bin(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_bin2num_num2bin(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} + +BOOST_AUTO_TEST_CASE(num2bin_bin2num) { + test_num2bin_bin2num(0); + test_num2bin_bin2num(SCRIPT_ENABLE_OPCODES_MONOLITH); + test_num2bin_bin2num(STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_num2bin_bin2num(STANDARD_NOT_MANDATORY_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); + test_num2bin_bin2num(STANDARD_LOCKTIME_VERIFY_FLAGS | SCRIPT_ENABLE_OPCODES_MONOLITH); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/scriptflags.cpp b/src/test/scriptflags.cpp --- a/src/test/scriptflags.cpp +++ b/src/test/scriptflags.cpp @@ -33,6 +33,7 @@ {"COMPRESSED_PUBKEYTYPE", SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE}, {"SIGHASH_FORKID", SCRIPT_ENABLE_SIGHASH_FORKID}, {"REPLAY_PROTECTION", SCRIPT_ENABLE_REPLAY_PROTECTION}, + {"MONOLITH_OPCODES", SCRIPT_ENABLE_OPCODES_MONOLITH}, }; uint32_t ParseScriptFlags(std::string strFlags) {