Skip to content

Commit

Permalink
Implement DATALOAD instruction
Browse files Browse the repository at this point in the history
  • Loading branch information
gumb0 committed Mar 18, 2023
1 parent 4c03243 commit aefb67e
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 14 deletions.
6 changes: 3 additions & 3 deletions lib/evmone/advanced_analysis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ struct AdvancedExecutionState : ExecutionState
AdvancedExecutionState() noexcept : stack{stack_space.bottom()} {}

AdvancedExecutionState(const evmc_message& message, evmc_revision revision,
const evmc_host_interface& host_interface, evmc_host_context* host_ctx,
bytes_view _code) noexcept
: ExecutionState{message, revision, host_interface, host_ctx, _code},
const evmc_host_interface& host_interface, evmc_host_context* host_ctx, bytes_view _code,
bytes_view _data) noexcept
: ExecutionState{message, revision, host_interface, host_ctx, _code, _data},
stack{stack_space.bottom()}
{}

Expand Down
3 changes: 2 additions & 1 deletion lib/evmone/advanced_execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ evmc_result execute(evmc_vm* /*unused*/, const evmc_host_interface* host, evmc_h
}
else
analysis = analyze(rev, container);
auto state = std::make_unique<AdvancedExecutionState>(*msg, rev, *host, ctx, container);
auto state =
std::make_unique<AdvancedExecutionState>(*msg, rev, *host, ctx, container, bytes_view{});
return execute(*state, analysis);
}
} // namespace evmone::advanced
8 changes: 5 additions & 3 deletions lib/evmone/baseline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@ CodeAnalysis analyze_eof1(bytes_view container)
for (const auto offset : header.code_offsets)
relative_offsets.push_back(offset - code_sections_offset);

const auto data_section = container.substr(code_sections_end);

// FIXME: Better way of getting EOF version.
const auto eof_version = container[2];
return CodeAnalysis{executable_code, {}, eof_version, relative_offsets};
return CodeAnalysis{executable_code, {}, eof_version, relative_offsets, data_section};
}
} // namespace

Expand Down Expand Up @@ -375,8 +377,8 @@ evmc_result execute(evmc_vm* c_vm, const evmc_host_interface* host, evmc_host_co
{
auto vm = static_cast<VM*>(c_vm);
const auto jumpdest_map = analyze(rev, {code, code_size});
auto state =
std::make_unique<ExecutionState>(*msg, rev, *host, ctx, bytes_view{code, code_size});
auto state = std::make_unique<ExecutionState>(
*msg, rev, *host, ctx, bytes_view{code, code_size}, jumpdest_map.data);
return execute(*vm, *state, jumpdest_map);
}
} // namespace evmone::baseline
8 changes: 6 additions & 2 deletions lib/evmone/baseline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class CodeAnalysis
/// section. We flatten the sections for cheap execution.
CodeOffsets code_offsets;

bytes_view data; ///< Data section.

private:
/// Padded code for faster legacy code execution.
/// If not nullptr the executable_code must point to it.
Expand All @@ -43,11 +45,13 @@ class CodeAnalysis
m_padded_code{std::move(padded_code)}
{}

CodeAnalysis(bytes_view code, JumpdestMap map, uint8_t version, CodeOffsets offsets)
CodeAnalysis(bytes_view code, JumpdestMap map, uint8_t version, CodeOffsets offsets,
bytes_view data_section)
: executable_code{code},
jumpdest_map{std::move(map)},
eof_version{version},
code_offsets{std::move(offsets)}
code_offsets{std::move(offsets)},
data{data_section}
{}
};
static_assert(std::is_move_constructible_v<CodeAnalysis>);
Expand Down
9 changes: 6 additions & 3 deletions lib/evmone/execution_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ class ExecutionState
/// For EOF-formatted code this is a reference to entire container.
bytes_view original_code;

bytes_view data;

evmc_status_code status = EVMC_SUCCESS;
size_t output_offset = 0;
size_t output_size = 0;
Expand All @@ -164,13 +166,14 @@ class ExecutionState
ExecutionState() noexcept = default;

ExecutionState(const evmc_message& message, evmc_revision revision,
const evmc_host_interface& host_interface, evmc_host_context* host_ctx,
bytes_view _code) noexcept
const evmc_host_interface& host_interface, evmc_host_context* host_ctx, bytes_view _code,
bytes_view _data) noexcept
: gas_left{message.gas},
msg{&message},
host{host_interface, host_ctx},
rev{revision},
original_code{_code}
original_code{_code},
data{_data}
{}

/// Resets the contents of the ExecutionState so that it could be reused.
Expand Down
25 changes: 25 additions & 0 deletions lib/evmone/instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,31 @@ inline code_iterator swapn(StackTop stack, ExecutionState& state, code_iterator
return pos + 2;
}

inline evmc_status_code dataload(StackTop stack, ExecutionState& state) noexcept
{
auto& index = stack.top();

if (state.msg->input_size < index)
index = 0;
else
{
if (state.data.size() < index)
return EVMC_INVALID_MEMORY_ACCESS; // TODO better error
const auto begin = static_cast<size_t>(index);

const auto end = begin + 32;
if (end > state.data.size())
return EVMC_INVALID_MEMORY_ACCESS; // TODO better error

uint8_t data[32] = {};
for (size_t i = 0; i < 32; ++i)
data[i] = state.data[begin + i];

index = intx::be::load<uint256>(data);
}
return EVMC_SUCCESS;
}

template <size_t NumTopics>
inline evmc_status_code log(StackTop stack, ExecutionState& state) noexcept
{
Expand Down
2 changes: 2 additions & 0 deletions lib/evmone/instructions_opcodes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ enum Opcode : uint8_t
OP_DUPN = 0xb5,
OP_SWAPN = 0xb6,

OP_DATALOAD = 0xb7,

OP_CREATE = 0xf0,
OP_CALL = 0xf1,
OP_CALLCODE = 0xf2,
Expand Down
2 changes: 2 additions & 0 deletions lib/evmone/instructions_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ constexpr inline GasCostTable gas_costs = []() noexcept {
table[EVMC_CANCUN][OP_RJUMPV] = 4;
table[EVMC_CANCUN][OP_CALLF] = 5;
table[EVMC_CANCUN][OP_RETF] = 3;
table[EVMC_CANCUN][OP_DATALOAD] = 3;

table[EVMC_PRAGUE] = table[EVMC_CANCUN];

Expand Down Expand Up @@ -375,6 +376,7 @@ constexpr inline std::array<Traits, 256> traits = []() noexcept {

table[OP_DUPN] = {"DUPN", 1, false, 0, 1, EVMC_CANCUN};
table[OP_SWAPN] = {"SWAPN", 1, false, 0, 0, EVMC_CANCUN};
table[OP_DATALOAD] = {"DATALOAD", 0, false, 1, 0, EVMC_CANCUN};

table[OP_CREATE] = {"CREATE", 0, false, 3, -2, EVMC_FRONTIER};
table[OP_CALL] = {"CALL", 0, false, 7, -6, EVMC_FRONTIER};
Expand Down
2 changes: 1 addition & 1 deletion lib/evmone/instructions_xmacro.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@
ON_OPCODE_UNDEFINED(0xb4) \
ON_OPCODE_IDENTIFIER(OP_DUPN, dupn) \
ON_OPCODE_IDENTIFIER(OP_SWAPN, swapn) \
ON_OPCODE_UNDEFINED(0xb7) \
ON_OPCODE_IDENTIFIER(OP_DATALOAD, dataload) \
ON_OPCODE_UNDEFINED(0xb8) \
ON_OPCODE_UNDEFINED(0xb9) \
ON_OPCODE_UNDEFINED(0xba) \
Expand Down
2 changes: 1 addition & 1 deletion test/unittests/execution_state_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ TEST(execution_state, construct)
const evmc_host_interface host_interface{};
const uint8_t code[]{0x0f};
const evmone::ExecutionState st{
msg, EVMC_MAX_REVISION, host_interface, nullptr, {code, std::size(code)}};
msg, EVMC_MAX_REVISION, host_interface, nullptr, {code, std::size(code)}, {}};

EXPECT_EQ(st.gas_left, -1);
EXPECT_EQ(st.memory.size(), 0);
Expand Down
1 change: 1 addition & 0 deletions test/unittests/instructions_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ constexpr bool instruction_only_in_evmone(evmc_revision rev, Opcode op) noexcept
case OP_RETF:
case OP_DUPN:
case OP_SWAPN:
case OP_DATALOAD:
return true;
default:
return false;
Expand Down

0 comments on commit aefb67e

Please sign in to comment.