diff --git a/lib/evmone/advanced_analysis.hpp b/lib/evmone/advanced_analysis.hpp index 252a158981..6ebf48eefe 100644 --- a/lib/evmone/advanced_analysis.hpp +++ b/lib/evmone/advanced_analysis.hpp @@ -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()} {} diff --git a/lib/evmone/advanced_execution.cpp b/lib/evmone/advanced_execution.cpp index a72a6e4a5a..2176bfcbaa 100644 --- a/lib/evmone/advanced_execution.cpp +++ b/lib/evmone/advanced_execution.cpp @@ -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(*msg, rev, *host, ctx, container); + auto state = + std::make_unique(*msg, rev, *host, ctx, container, bytes_view{}); return execute(*state, analysis); } } // namespace evmone::advanced diff --git a/lib/evmone/baseline.cpp b/lib/evmone/baseline.cpp index 7a9caab651..2555f7ff2a 100644 --- a/lib/evmone/baseline.cpp +++ b/lib/evmone/baseline.cpp @@ -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 @@ -375,8 +377,8 @@ evmc_result execute(evmc_vm* c_vm, const evmc_host_interface* host, evmc_host_co { auto vm = static_cast(c_vm); const auto jumpdest_map = analyze(rev, {code, code_size}); - auto state = - std::make_unique(*msg, rev, *host, ctx, bytes_view{code, code_size}); + auto state = std::make_unique( + *msg, rev, *host, ctx, bytes_view{code, code_size}, jumpdest_map.data); return execute(*vm, *state, jumpdest_map); } } // namespace evmone::baseline diff --git a/lib/evmone/baseline.hpp b/lib/evmone/baseline.hpp index 1519534bc7..682c961a54 100644 --- a/lib/evmone/baseline.hpp +++ b/lib/evmone/baseline.hpp @@ -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. @@ -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); diff --git a/lib/evmone/execution_state.hpp b/lib/evmone/execution_state.hpp index 8aa54353ca..2ac60bf984 100644 --- a/lib/evmone/execution_state.hpp +++ b/lib/evmone/execution_state.hpp @@ -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; @@ -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. diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index 6a95e48662..6e40b3b4b2 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -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(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(data); + } + return EVMC_SUCCESS; +} + template inline evmc_status_code log(StackTop stack, ExecutionState& state) noexcept { diff --git a/lib/evmone/instructions_opcodes.hpp b/lib/evmone/instructions_opcodes.hpp index 9b430ce47a..7dfee579a4 100644 --- a/lib/evmone/instructions_opcodes.hpp +++ b/lib/evmone/instructions_opcodes.hpp @@ -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, diff --git a/lib/evmone/instructions_traits.hpp b/lib/evmone/instructions_traits.hpp index fc4bb85776..428b22d7eb 100644 --- a/lib/evmone/instructions_traits.hpp +++ b/lib/evmone/instructions_traits.hpp @@ -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]; @@ -375,6 +376,7 @@ constexpr inline std::array 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}; diff --git a/lib/evmone/instructions_xmacro.hpp b/lib/evmone/instructions_xmacro.hpp index 7c81d7f135..342aae0d12 100644 --- a/lib/evmone/instructions_xmacro.hpp +++ b/lib/evmone/instructions_xmacro.hpp @@ -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) \ diff --git a/test/unittests/execution_state_test.cpp b/test/unittests/execution_state_test.cpp index 2600481c14..b08efe5768 100644 --- a/test/unittests/execution_state_test.cpp +++ b/test/unittests/execution_state_test.cpp @@ -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); diff --git a/test/unittests/instructions_test.cpp b/test/unittests/instructions_test.cpp index 2e13a3799d..84c6062743 100644 --- a/test/unittests/instructions_test.cpp +++ b/test/unittests/instructions_test.cpp @@ -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;