Skip to content

Commit

Permalink
DUPN and SWAPN in EOF only + EOF stack validation
Browse files Browse the repository at this point in the history
  • Loading branch information
pdobacz committed Jan 10, 2024
1 parent 3d0242b commit 896a029
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 55 deletions.
8 changes: 8 additions & 0 deletions lib/evmone/advanced_instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ inline code_iterator impl(AdvancedExecutionState& state, code_iterator pos) noex
state.stack.top_item += instr::traits[Op].stack_height_change;
return new_pos;
}

template <Opcode Op, code_iterator CoreFn(StackTop, code_iterator) noexcept = core::impl<Op>>
inline code_iterator impl(AdvancedExecutionState& state, code_iterator pos) noexcept
{
const auto new_pos = CoreFn(state.stack.top_item, pos);
state.stack.top_item += instr::traits[Op].stack_height_change;
return new_pos;
}
/// @}
} // namespace instr

Expand Down
7 changes: 7 additions & 0 deletions lib/evmone/baseline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ struct Position
return instr_fn(pos.stack_top, state, pos.code_it);
}

[[release_inline]] inline code_iterator invoke(
code_iterator (*instr_fn)(StackTop, code_iterator) noexcept, Position pos, int64_t& /*gas*/,
ExecutionState& /*state*/) noexcept
{
return instr_fn(pos.stack_top, pos.code_it);
}

[[release_inline]] inline code_iterator invoke(
TermResult (*instr_fn)(StackTop, int64_t, ExecutionState&) noexcept, Position pos, int64_t& gas,
ExecutionState& state) noexcept
Expand Down
2 changes: 2 additions & 0 deletions lib/evmone/baseline_instruction_table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ constexpr auto legacy_cost_tables = []() noexcept {
tables[EVMC_PRAGUE][OP_DATALOADN] = instr::undefined;
tables[EVMC_PRAGUE][OP_DATASIZE] = instr::undefined;
tables[EVMC_PRAGUE][OP_DATACOPY] = instr::undefined;
tables[EVMC_PRAGUE][OP_DUPN] = instr::undefined;
tables[EVMC_PRAGUE][OP_SWAPN] = instr::undefined;
return tables;
}();

Expand Down
10 changes: 10 additions & 0 deletions lib/evmone/eof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,16 @@ std::variant<EOFValidationError, int32_t> validate_max_stack_height(
if (stack_height > code_types[func_index].outputs)
return EOFValidationError::stack_higher_than_outputs_required;
}
else if (opcode == OP_DUPN)
{
const auto n = static_cast<int8_t>(code[i + 1]);
stack_height_required = n + 1;
}
else if (opcode == OP_SWAPN)
{
const auto n = static_cast<int8_t>(code[i + 1]);
stack_height_required = n + 2;
}

if (stack_height < stack_height_required)
return EOFValidationError::stack_underflow;
Expand Down
22 changes: 2 additions & 20 deletions lib/evmone/instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -902,35 +902,17 @@ inline void swap(StackTop stack) noexcept
a[3] = t3;
}

inline code_iterator dupn(StackTop stack, ExecutionState& state, code_iterator pos) noexcept
inline code_iterator dupn(StackTop stack, code_iterator pos) noexcept
{
const auto n = pos[1] + 1;

const auto stack_size = &stack.top() - state.stack_space.bottom();

if (stack_size < n)
{
state.status = EVMC_STACK_UNDERFLOW;
return nullptr;
}

stack.push(stack[n - 1]);

return pos + 2;
}

inline code_iterator swapn(StackTop stack, ExecutionState& state, code_iterator pos) noexcept
inline code_iterator swapn(StackTop stack, code_iterator pos) noexcept
{
const auto n = pos[1] + 1;

const auto stack_size = &stack.top() - state.stack_space.bottom();

if (stack_size <= n)
{
state.status = EVMC_STACK_UNDERFLOW;
return nullptr;
}

// TODO: This may not be optimal, see instr::core::swap().
std::swap(stack.top(), stack[n]);

Expand Down
18 changes: 18 additions & 0 deletions test/unittests/eof_validation_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,24 @@ TEST(eof_validation, retf_stack_validation)
EXPECT_EQ(validate_eof(code), EOFValidationError::stack_higher_than_outputs_required);
}

TEST(eof_validation, dupn_stack_validation)
{
auto pushes = bytecode{};
for (uint64_t i = 1; i <= 20; ++i)
pushes += push(i);
auto code = eof_bytecode(pushes + OP_DUPN + "14" + OP_STOP, 21);
EXPECT_EQ(validate_eof(code), EOFValidationError::stack_underflow);
}

TEST(eof_validation, swapn_stack_validation)
{
auto pushes = bytecode{};
for (uint64_t i = 1; i <= 20; ++i)
pushes += push(i);
auto code = eof_bytecode(pushes + OP_SWAPN + "13" + OP_STOP, 20);
EXPECT_EQ(validate_eof(code), EOFValidationError::stack_underflow);
}

TEST(eof_validation, non_returning_status)
{
// Non-returning with no JUMPF and no RETF
Expand Down
61 changes: 26 additions & 35 deletions test/unittests/evm_eip663_dupn_swapn_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,17 @@ TEST_P(evm, dupn)
for (uint64_t i = 1; i <= 20; ++i)
pushes += push(i);

execute(pushes + OP_DUPN + "00" + ret_top());
execute(eof_bytecode(pushes + OP_DUPN + "00" + ret_top(), 22));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(20);

execute(pushes + OP_DUPN + "02" + ret_top());
execute(eof_bytecode(pushes + OP_DUPN + "02" + ret_top(), 22));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(18);

execute(pushes + OP_DUPN + "13" + ret_top());
execute(eof_bytecode(pushes + OP_DUPN + "13" + ret_top(), 22));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(1);

execute(pushes + OP_DUPN + "14" + ret_top());
EXPECT_STATUS(EVMC_STACK_UNDERFLOW);
}

TEST_P(evm, swapn)
Expand All @@ -50,32 +47,29 @@ TEST_P(evm, swapn)
for (uint64_t i = 1; i <= 20; ++i)
pushes += push(i);

execute(pushes + OP_SWAPN + "00" + ret_top());
execute(eof_bytecode(pushes + OP_SWAPN + "00" + ret_top(), 21));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(19);

execute(pushes + OP_SWAPN + "00" + OP_DUPN + "01" + ret_top());
execute(eof_bytecode(pushes + OP_SWAPN + "00" + OP_DUPN + "01" + ret_top(), 22));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(20);

execute(pushes + OP_SWAPN + "01" + ret_top());
execute(eof_bytecode(pushes + OP_SWAPN + "01" + ret_top(), 21));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(18);

execute(pushes + OP_SWAPN + "01" + OP_DUPN + "02" + ret_top());
execute(eof_bytecode(pushes + OP_SWAPN + "01" + OP_DUPN + "02" + ret_top(), 22));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(20);

execute(pushes + OP_SWAPN + "12" + ret_top());
execute(eof_bytecode(pushes + OP_SWAPN + "12" + ret_top(), 21));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(1);

execute(pushes + OP_SWAPN + "12" + OP_DUPN + "13" + ret_top());
execute(eof_bytecode(pushes + OP_SWAPN + "12" + OP_DUPN + "13" + ret_top(), 22));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(20);

execute(pushes + OP_SWAPN + "13" + ret_top());
EXPECT_STATUS(EVMC_STACK_UNDERFLOW);
}

TEST_P(evm, dupn_full_stack)
Expand All @@ -86,23 +80,20 @@ TEST_P(evm, dupn_full_stack)

rev = EVMC_PRAGUE;
auto full_stack_code = bytecode{};
for (uint64_t i = 1023; i >= 1; --i)
for (uint64_t i = 1022; i >= 1; --i)
full_stack_code += push(i);

execute(full_stack_code + OP_POP + OP_DUPN + "00" + ret_top());
execute(eof_bytecode(full_stack_code + OP_POP + OP_DUPN + "00" + ret_top(), 1023));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(2);

execute(full_stack_code + OP_POP + OP_DUPN + "ff" + ret_top());
execute(eof_bytecode(full_stack_code + OP_POP + OP_DUPN + "ff" + ret_top(), 1023));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(257);

execute(full_stack_code + OP_POP + OP_DUPN + "fe" + ret_top());
execute(eof_bytecode(full_stack_code + OP_POP + OP_DUPN + "fe" + ret_top(), 1023));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(256);

execute(full_stack_code + OP_DUPN + "fe" + OP_DUPN + "ff");
EXPECT_STATUS(EVMC_STACK_OVERFLOW);
}

TEST_P(evm, swapn_full_stack)
Expand All @@ -113,22 +104,22 @@ TEST_P(evm, swapn_full_stack)

rev = EVMC_PRAGUE;
auto full_stack_code = bytecode{};
for (uint64_t i = 1024; i >= 1; --i)
for (uint64_t i = 1023; i >= 1; --i)
full_stack_code += push(i);

execute(full_stack_code + OP_POP + OP_SWAPN + "00" + ret_top());
execute(eof_bytecode(full_stack_code + OP_POP + OP_SWAPN + "00" + ret_top(), 1023));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(3);

execute(full_stack_code + OP_POP + OP_SWAPN + "ff" + ret_top());
execute(eof_bytecode(full_stack_code + OP_POP + OP_SWAPN + "ff" + ret_top(), 1023));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(255 + 3);

execute(full_stack_code + OP_POP + OP_SWAPN + "fe" + ret_top());
execute(eof_bytecode(full_stack_code + OP_POP + OP_SWAPN + "fe" + ret_top(), 1023));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(254 + 3);

execute(full_stack_code + OP_SWAPN + "ff" + OP_SWAPN + "00" + OP_RETURN);
execute(eof_bytecode(full_stack_code + OP_SWAPN + "ff" + OP_SWAPN + "00" + OP_RETURN, 1023));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_EQ(result.output_size, 255 + 2);
}
Expand All @@ -144,19 +135,19 @@ TEST_P(evm, dupn_dup_consistency)
for (uint64_t i = 32; i >= 1; --i)
pushes += push(i);

execute(pushes + OP_DUP1 + ret_top());
execute(eof_bytecode(pushes + OP_DUP1 + ret_top(), 34));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(1);

execute(pushes + OP_DUPN + "00" + ret_top());
execute(eof_bytecode(pushes + OP_DUPN + "00" + ret_top(), 34));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(1);

execute(pushes + OP_DUP16 + ret_top());
execute(eof_bytecode(pushes + OP_DUP16 + ret_top(), 34));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(16);

execute(pushes + OP_DUPN + "0f" + ret_top());
execute(eof_bytecode(pushes + OP_DUPN + "0f" + ret_top(), 34));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(16);
}
Expand All @@ -172,19 +163,19 @@ TEST_P(evm, swapn_swap_consistency)
for (uint64_t i = 32; i >= 1; --i)
pushes += push(i);

execute(pushes + OP_SWAP1 + ret_top());
execute(eof_bytecode(pushes + OP_SWAP1 + ret_top(), 33));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(2);

execute(pushes + OP_SWAPN + "00" + ret_top());
execute(eof_bytecode(pushes + OP_SWAPN + "00" + ret_top(), 33));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(2);

execute(pushes + OP_SWAP16 + ret_top());
execute(eof_bytecode(pushes + OP_SWAP16 + ret_top(), 33));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(17);

execute(pushes + OP_SWAPN + "0f" + ret_top());
execute(eof_bytecode(pushes + OP_SWAPN + "0f" + ret_top(), 33));
EXPECT_STATUS(EVMC_SUCCESS);
EXPECT_OUTPUT_INT(17);
}

0 comments on commit 896a029

Please sign in to comment.