diff --git a/src/Makefile.test.include b/src/Makefile.test.include --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -61,6 +61,7 @@ test/multisig_tests.cpp \ test/net_tests.cpp \ test/netbase_tests.cpp \ + test/op_codes.cpp \ test/pmt_tests.cpp \ test/policyestimator_tests.cpp \ test/pow_tests.cpp \ diff --git a/src/script/interpreter.h b/src/script/interpreter.h --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -107,6 +107,10 @@ // Do we accept signature using SIGHASH_FORKID // SCRIPT_ENABLE_SIGHASH_FORKID = (1U << 16), + + // Enable new opcodes activated from 15 May 2018 HF + // + SCRIPT_ENABLE_OPCODES_MONOLITH = (1U << 17), }; 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,8 @@ } int nOpCount = 0; bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; + bool fEnabledOpCodesMonolith = + (flags & SCRIPT_ENABLE_OPCODES_MONOLITH) != 0; try { while (pc < pend) { @@ -334,14 +336,20 @@ 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_INVERT || opcode == OP_2MUL || opcode == OP_2DIV || opcode == OP_MUL || opcode == OP_DIV || opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) { // Disabled opcodes. return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); } + // if not monolith protocol upgrade (May 2018) then still disabled + if (!fEnabledOpCodesMonolith && + (opcode == OP_AND || opcode == OP_XOR || opcode == OP_OR)) { + // Disabled opcodes. + return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); + } + if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { @@ -778,6 +786,44 @@ // // Bitwise logic // + case OP_AND: + case OP_OR: + case OP_XOR: { + // (x1 x2 - out) + if (stack.size() < 2) { + return set_error( + serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + valtype &vch1 = stacktop(-2); + valtype &vch2 = stacktop(-1); + // throw error if inputs are not the same size + if (vch1.size() != vch2.size()) { + return set_error( + serror, SCRIPT_ERR_INVALID_BITWISE_OPERATION); + } + + switch (opcode) { + case OP_AND: + for (size_t i=0; i +#include + +using namespace std; + +#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 vector item; +typedef vector stack_t; + +#ifdef VERBOSE +void print(const item &i) { + if (i.empty()) cout << "empty"; + for (auto &s : i) + cout << hex << setw(2) << setfill('0') << (int)s << " "; + cout << endl; +} +void print(const stack_t &i) { + for (auto &s : i) + print(s); + cout << 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 + cout << "--------------" << endl; + cout << "Checking script \"" << FormatScript(script) << "\" flags " << flags + << endl; + cout << "with input stack: " << endl; + print(stack); + cout << "expected error: " << se << endl; +#endif + ScriptError err = SCRIPT_ERR_OK; + BaseSignatureChecker sigchecker; + bool r = EvalScript(stack, script, flags, sigchecker, &err); + BOOST_CHECK_EQUAL(r, false); +#ifdef VERBOSE + cout << "got error: " << err << " vs " << se << endl; +#endif + BOOST_CHECK_EQUAL(err == se, true); +} + +/// 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 + cout << "--------------" << endl; + cout << "Checking script \"" << FormatScript(script) << "\" flags " << flags + << endl; + cout << "with input stack: " << endl; + print(stack); + cout << "expected output stack: " << endl; + print(expected); +#endif + ScriptError err; + BaseSignatureChecker sigchecker; + bool r = EvalScript(stack, script, flags, sigchecker, &err); +#ifdef VERBOSE + cout << "got output stack: " << endl; + print(stack); +#endif + 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_OPERATION); + test(script, stack_t{{0x01, 0x01}, {}}, flags, + SCRIPT_ERR_INVALID_BITWISE_OPERATION); + test(script, stack_t{{}, {0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_OPERATION); + test(script, stack_t{{}, {0x01, 0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_OPERATION); + test(script, stack_t{{0x01}, {0x01, 0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_OPERATION); + test(script, stack_t{{0x01, 0x01}, {0x01, 0x01, 0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_OPERATION); + test(script, stack_t{{0x01, 0x01}, {0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_OPERATION); + test(script, stack_t{{0x01, 0x01, 0x01}, {0x01, 0x01}}, flags, + SCRIPT_ERR_INVALID_BITWISE_OPERATION); +} + +/// 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}); + } +} +} + +/// Entry points + +BOOST_AUTO_TEST_SUITE(op_code) + +BOOST_AUTO_TEST_CASE(op_and) { + 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(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(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_SUITE_END() \ No newline at end of file