diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index 2d0f9c5f65..aa9f3fa3d6 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -822,17 +822,17 @@ inline void swap(StackTop stack) noexcept inline code_iterator dupn(StackTop stack, ExecutionState& state, code_iterator pos) noexcept { - const auto n = pos[1]; + const auto n = pos[1] + 1; const auto stack_size = &stack.top() - state.stack_space.bottom(); - if (stack_size <= n) + if (stack_size < n) { state.status = EVMC_STACK_UNDERFLOW; return nullptr; } - stack.push(stack[n]); + stack.push(stack[n - 1]); return pos + 2; } diff --git a/lib/evmone/instructions_opcodes.hpp b/lib/evmone/instructions_opcodes.hpp index ab28e73f59..8385c7120d 100644 --- a/lib/evmone/instructions_opcodes.hpp +++ b/lib/evmone/instructions_opcodes.hpp @@ -152,8 +152,8 @@ enum Opcode OP_LOG3 = 0xa3, OP_LOG4 = 0xa4, - OP_DUPN = 0xb3, - OP_SWAPN = 0xb4, + OP_DUPN = 0xb5, + OP_SWAPN = 0xb6, OP_CREATE = 0xf0, OP_CALL = 0xf1, diff --git a/lib/evmone/instructions_xmacro.hpp b/lib/evmone/instructions_xmacro.hpp index 7c830db6a9..d69b5c13f5 100644 --- a/lib/evmone/instructions_xmacro.hpp +++ b/lib/evmone/instructions_xmacro.hpp @@ -222,10 +222,10 @@ ON_OPCODE_UNDEFINED(0xb0) \ ON_OPCODE_UNDEFINED(0xb1) \ ON_OPCODE_UNDEFINED(0xb2) \ + ON_OPCODE_UNDEFINED(0xb3) \ + ON_OPCODE_UNDEFINED(0xb4) \ ON_OPCODE_IDENTIFIER(OP_DUPN, dupn) \ ON_OPCODE_IDENTIFIER(OP_SWAPN, swapn) \ - ON_OPCODE_UNDEFINED(0xb5) \ - ON_OPCODE_UNDEFINED(0xb6) \ ON_OPCODE_UNDEFINED(0xb7) \ ON_OPCODE_UNDEFINED(0xb8) \ ON_OPCODE_UNDEFINED(0xb9) \ diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 1c87956ce9..1124eaba8b 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -219,7 +219,8 @@ TEST(eof_validation, EOF1_terminating_instructions) { const auto& op_traits = traits[opcode]; // Skip undefined opcodes. - if (op_traits.name == nullptr) + // TODO iterate for all EOF revisions + if (op_traits.name == nullptr || op_traits.since == EVMC_CANCUN) continue; bytes code{static_cast(opcode) + bytes(op_traits.immediate_size, 0)}; @@ -230,6 +231,6 @@ TEST(eof_validation, EOF1_terminating_instructions) opcode == OP_INVALID || opcode == OP_SELFDESTRUCT) ? EOFValidationError::success : EOFValidationError::missing_terminating_instruction); - EXPECT_EQ(validate_eof(container, EVMC_CANCUN), expected) << hex(code); + EXPECT_EQ(validate_eof(container), expected) << hex(code); } } diff --git a/test/unittests/evm_test.cpp b/test/unittests/evm_test.cpp index f351c552cc..14a585ea02 100644 --- a/test/unittests/evm_test.cpp +++ b/test/unittests/evm_test.cpp @@ -197,14 +197,26 @@ TEST_P(evm, swapn) EXPECT_STATUS(EVMC_SUCCESS); EXPECT_OUTPUT_INT(19); + execute(pushes + OP_SWAPN + "00" + OP_DUPN + "01" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(20); + execute(pushes + OP_SWAPN + "01" + ret_top()); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_OUTPUT_INT(18); + execute(pushes + OP_SWAPN + "01" + OP_DUPN + "02" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(20); + execute(pushes + OP_SWAPN + "12" + ret_top()); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_OUTPUT_INT(1); + execute(pushes + OP_SWAPN + "12" + OP_DUPN + "13" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(20); + execute(pushes + OP_SWAPN + "13" + ret_top()); EXPECT_STATUS(EVMC_STACK_UNDERFLOW); } diff --git a/test/unittests/instructions_test.cpp b/test/unittests/instructions_test.cpp index 2d44f940e6..e86550724b 100644 --- a/test/unittests/instructions_test.cpp +++ b/test/unittests/instructions_test.cpp @@ -136,9 +136,9 @@ TEST(instructions, compare_undefined_instructions) for (size_t i = 0; i < instr_tbl.size(); ++i) { - // Skip DUPN and SWAPN for Cancun. They are not defined in evmc + // Skip DUPN and SWAPN. They are not defined in evmc // TODO: Define DUPN and SWAPN in evmc - if (r == EVMC_CANCUN && (Opcode(i) == OP_DUPN || Opcode(i) == OP_SWAPN)) + if (Opcode(i) == OP_DUPN || Opcode(i) == OP_SWAPN) continue; EXPECT_EQ(instr_tbl[i] == instr::undefined, evmc_names_tbl[i] == nullptr) << i; } @@ -150,10 +150,9 @@ TEST(instructions, compare_with_evmc_instruction_names) const auto* evmc_tbl = evmc_get_instruction_names_table(EVMC_MAX_REVISION); for (size_t i = 0; i < instr::traits.size(); ++i) { - // Skip DUPN and SWAPN for Cancun. They are not defined in evmc + // Skip DUPN and SWAPN. They are not defined in evmc // TODO: Define DUPN and SWAPN in evmc - if (instr::traits[i].since == EVMC_CANCUN && - (Opcode(i) == OP_DUPN || Opcode(i) == OP_SWAPN)) + if (Opcode(i) == OP_DUPN || Opcode(i) == OP_SWAPN) continue; EXPECT_STREQ(instr::traits[i].name, evmc_tbl[i]); }