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_type.cpp \ test/multisig_tests.cpp \ test/net_tests.cpp \ test/netbase_tests.cpp \ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -304,10 +304,10 @@ return true; case OP_BIN2NUM: - return true; + return false; case OP_NUM2BIN: - return true; + return false; case OP_AND: return true; @@ -945,6 +945,22 @@ 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; @@ -1238,6 +1254,73 @@ } } break; + // + // Conversion operations + // + case OP_BIN2NUM: { + // (in -- out) + if (stack.size() < 1) { + return set_error( + serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + valtype bin = stacktop(-1); + // big endian to little endian conversion + std::reverse(bin.begin(), bin.end()); + CScriptNum num(bin, false); + if (num > (INT_MAX >> 1) || num < (INT_MIN >> 1)) { + return set_error( + serror, SCRIPT_ERR_INVALID_BIN2NUM_OPERATION); + } + stack.pop_back(); + stack.push_back(num.getvch()); + } break; + + case OP_NUM2BIN: { + // (in size -- out) + if (stack.size() < 2) { + return set_error( + serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + CScriptNum num(stacktop(-2), fRequireMinimal); + int64_t size = + CScriptNum(stacktop(-1), fRequireMinimal).getint(); + if (size < 1 || + static_cast(size) > + CScriptNum::nDefaultMaxNumSize) { + return set_error( + serror, SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); + } + // Produces a byte vector of num and check if input size + // is valid + valtype vchNum = num.getvch(); + if (size < vchNum.size()) { + return set_error( + serror, SCRIPT_ERR_INVALID_NUM2BIN_OPERATION); + } + // Initialize byte vector for result + valtype result; + result.reserve(size); + bool neg{false}; + // Avoid negative zero + if (!vchNum.empty()) { + neg = *vchNum.rbegin() & 0x80; + *vchNum.rbegin() &= ~0x80; + } + // Pad result to declared input size + size_t pad = size - vchNum.size(); + for (uint8_t i = 0; i < pad; ++i) { + result.push_back(0); + } + for (auto i = vchNum.rbegin(); i != vchNum.rend(); + ++i) { + result.push_back(*i); + } + if (neg) *result.begin() |= 0x80; + stack.pop_back(); + stack.pop_back(); + stack.push_back(result); + } 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 @@ -20,6 +20,10 @@ SCRIPT_ERR_SIG_COUNT, SCRIPT_ERR_PUBKEY_COUNT, + /* Operands checks */ + SCRIPT_ERR_INVALID_BIN2NUM_OPERATION, + SCRIPT_ERR_INVALID_NUM2BIN_OPERATION, + /* Failed verify operations */ SCRIPT_ERR_VERIFY, SCRIPT_ERR_EQUALVERIFY, 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 @@ -34,6 +34,10 @@ return "Signature count negative or greater than pubkey count"; case SCRIPT_ERR_PUBKEY_COUNT: return "Pubkey count negative or limit exceeded"; + 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_BAD_OPCODE: return "Opcode missing or not understood"; case SCRIPT_ERR_DISABLED_OPCODE: 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_type.cpp multisig_tests.cpp net_tests.cpp netbase_tests.cpp diff --git a/src/test/monolith_opcodes_type.cpp b/src/test/monolith_opcodes_type.cpp new file mode 100644