diff --git a/test/unittests/bytecode_test.cpp b/test/unittests/bytecode_test.cpp index deb55776a5..0c41a3754d 100644 --- a/test/unittests/bytecode_test.cpp +++ b/test/unittests/bytecode_test.cpp @@ -26,6 +26,26 @@ TEST(bytecode, push_int) EXPECT_EQ(push(0xffffffffffffffff), "67ffffffffffffffff"); } +TEST(bytecode, push_explicit_opcode) +{ + EXPECT_THROW(push(OP_JUMPDEST, {}), std::invalid_argument); + EXPECT_THROW(push(OP_DUP1, {}), std::invalid_argument); + + EXPECT_THROW(push(OP_PUSH1, "0000"), std::invalid_argument); + + EXPECT_EQ(push(OP_PUSH1, {}), "6000"); + EXPECT_EQ(push(OP_PUSH1, "ff"), "60ff"); + EXPECT_EQ(push(OP_PUSH2, ""), "610000"); + EXPECT_EQ(push(OP_PUSH2, "01"), "610001"); + EXPECT_EQ(push(OP_PUSH2, "8001"), "618001"); + EXPECT_EQ( + push(OP_PUSH32, ""), "7f0000000000000000000000000000000000000000000000000000000000000000"); + EXPECT_EQ(push(OP_PUSH32, "ab"), + "7f00000000000000000000000000000000000000000000000000000000000000ab"); + EXPECT_EQ(push(OP_PUSH32, "fe000000000000000000000000000000000000000000000000000000000000ef"), + "7ffe000000000000000000000000000000000000000000000000000000000000ef"); +} + TEST(bytecode, add) { auto e = "6007600d0160005260206000f3"; diff --git a/test/unittests/evm_test.cpp b/test/unittests/evm_test.cpp index 0939b9aaf1..6bd0946dfc 100644 --- a/test/unittests/evm_test.cpp +++ b/test/unittests/evm_test.cpp @@ -140,7 +140,7 @@ TEST_P(evm, swapsn_push) // EIP-663 variants B and C. // When SWAPSN is implemented execution will succeed, considering PUSH an argument of SWAPSN. const auto swapsn = "b3"; - const auto code = push(5) + OP_JUMP + swapsn + push(OP_JUMPDEST) + push(0) + ret_top(); + const auto code = push(5) + OP_JUMP + swapsn + push(uint8_t{OP_JUMPDEST}) + push(0) + ret_top(); rev = EVMC_PETERSBURG; execute(code); diff --git a/test/utils/bytecode.hpp b/test/utils/bytecode.hpp index 4765d7c1af..ed3c2fb315 100644 --- a/test/utils/bytecode.hpp +++ b/test/utils/bytecode.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include struct bytecode; @@ -76,6 +77,20 @@ inline bytecode push(std::string_view hex_data) return push(from_hex(hex_data)); } +bytecode push(evmc_opcode opcode) = delete; + +inline bytecode push(evmc_opcode opcode, const bytecode& data) +{ + if (opcode < OP_PUSH1 || opcode > OP_PUSH32) + throw std::invalid_argument{"invalid push opcode " + std::to_string(opcode)}; + + const auto num_instr_bytes = static_cast(opcode) - OP_PUSH1 + 1; + if (data.size() > num_instr_bytes) + throw std::invalid_argument{"push data too long"}; + + const auto instr_bytes = bytes(num_instr_bytes - data.size(), 0) + bytes{data}; + return opcode + instr_bytes; +} inline bytecode push(uint64_t n) {