From 581ce39da14bd7020176f1fd166831cb36d17077 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Thu, 10 Mar 2022 14:08:15 +0100 Subject: [PATCH 01/72] test: Helper to check if current VM is Advanced --- test/unittests/evm_fixture.cpp | 5 +++++ test/unittests/evm_fixture.hpp | 3 +++ 2 files changed, 8 insertions(+) diff --git a/test/unittests/evm_fixture.cpp b/test/unittests/evm_fixture.cpp index 173dccfd85..22342e9602 100644 --- a/test/unittests/evm_fixture.cpp +++ b/test/unittests/evm_fixture.cpp @@ -27,4 +27,9 @@ const char* print_vm_name(const testing::TestParamInfo& info) noexcep INSTANTIATE_TEST_SUITE_P( evmone, evm, testing::Values(&advanced_vm, &baseline_vm, &bnocgoto_vm), print_vm_name); + +bool evm::is_advanced() noexcept +{ + return GetParam() == &advanced_vm; +} } // namespace evmone::test diff --git a/test/unittests/evm_fixture.hpp b/test/unittests/evm_fixture.hpp index 1309f85999..7452c245d8 100644 --- a/test/unittests/evm_fixture.hpp +++ b/test/unittests/evm_fixture.hpp @@ -32,6 +32,9 @@ namespace evmone::test class evm : public testing::TestWithParam { protected: + /// Reports if execution is done by evmone/Advanced. + static bool is_advanced() noexcept; + /// The VM handle. evmc::VM& vm; From 4b1dad498247275264061362736a20657da5bc9a Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 30 Nov 2022 18:56:37 +0100 Subject: [PATCH 02/72] baseline: Implement EIP-663 DUPN SWAPN --- lib/evmone/advanced_instructions.cpp | 3 +++ lib/evmone/instructions.hpp | 35 ++++++++++++++++++++++++++++ lib/evmone/instructions_opcodes.hpp | 3 +++ lib/evmone/instructions_traits.hpp | 5 ++++ lib/evmone/instructions_xmacro.hpp | 4 ++-- 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/evmone/advanced_instructions.cpp b/lib/evmone/advanced_instructions.cpp index 2a6469d02c..b484912f2d 100644 --- a/lib/evmone/advanced_instructions.cpp +++ b/lib/evmone/advanced_instructions.cpp @@ -245,6 +245,9 @@ constexpr std::array instruction_implementations = []( table[OP_CREATE2] = op_create; table[OP_STATICCALL] = op_call; + table[OP_DUPN] = op_undefined; + table[OP_SWAPN] = op_undefined; + return table; }(); } // namespace diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index 982ae4a1e8..e525387d83 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -820,6 +820,41 @@ inline void swap(StackTop stack) noexcept a[3] = t3; } +inline code_iterator dupn(StackTop stack, ExecutionState& state, 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 +{ + 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]); + + return pos + 2; +} + 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 0846b1e097..8385c7120d 100644 --- a/lib/evmone/instructions_opcodes.hpp +++ b/lib/evmone/instructions_opcodes.hpp @@ -152,6 +152,9 @@ enum Opcode OP_LOG3 = 0xa3, OP_LOG4 = 0xa4, + OP_DUPN = 0xb5, + OP_SWAPN = 0xb6, + OP_CREATE = 0xf0, OP_CALL = 0xf1, OP_CALLCODE = 0xf2, diff --git a/lib/evmone/instructions_traits.hpp b/lib/evmone/instructions_traits.hpp index d5e486e8b6..ccea01b2fb 100644 --- a/lib/evmone/instructions_traits.hpp +++ b/lib/evmone/instructions_traits.hpp @@ -164,6 +164,8 @@ constexpr inline GasCostTable gas_costs = []() noexcept { table[EVMC_SHANGHAI][OP_PUSH0] = 2; table[EVMC_CANCUN] = table[EVMC_SHANGHAI]; + table[EVMC_CANCUN][OP_DUPN] = 3; + table[EVMC_CANCUN][OP_SWAPN] = 3; return table; }(); @@ -360,6 +362,9 @@ constexpr inline std::array traits = []() noexcept { table[OP_LOG3] = {"LOG3", 0, false, 5, -5, EVMC_FRONTIER}; table[OP_LOG4] = {"LOG4", 0, false, 6, -6, EVMC_FRONTIER}; + table[OP_DUPN] = {"DUPN", 1, false, 0, 1, EVMC_CANCUN}; + table[OP_SWAPN] = {"SWAPN", 1, false, 0, 0, EVMC_CANCUN}; + table[OP_CREATE] = {"CREATE", 0, false, 3, -2, EVMC_FRONTIER}; table[OP_CALL] = {"CALL", 0, false, 7, -6, EVMC_FRONTIER}; table[OP_CALLCODE] = {"CALLCODE", 0, false, 7, -6, EVMC_FRONTIER}; diff --git a/lib/evmone/instructions_xmacro.hpp b/lib/evmone/instructions_xmacro.hpp index 1f7b135caf..d69b5c13f5 100644 --- a/lib/evmone/instructions_xmacro.hpp +++ b/lib/evmone/instructions_xmacro.hpp @@ -224,8 +224,8 @@ ON_OPCODE_UNDEFINED(0xb2) \ ON_OPCODE_UNDEFINED(0xb3) \ ON_OPCODE_UNDEFINED(0xb4) \ - ON_OPCODE_UNDEFINED(0xb5) \ - ON_OPCODE_UNDEFINED(0xb6) \ + ON_OPCODE_IDENTIFIER(OP_DUPN, dupn) \ + ON_OPCODE_IDENTIFIER(OP_SWAPN, swapn) \ ON_OPCODE_UNDEFINED(0xb7) \ ON_OPCODE_UNDEFINED(0xb8) \ ON_OPCODE_UNDEFINED(0xb9) \ From 3e0ab0ec741c99354c46a9b4fd2c8d720c70c901 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Mon, 28 Nov 2022 12:22:23 +0100 Subject: [PATCH 03/72] test: Add EIP-663 DUPN SWAPN unit tests --- test/unittests/CMakeLists.txt | 1 + test/unittests/eof_validation_test.cpp | 3 +- test/unittests/evm_eip663_dupn_swapn_test.cpp | 190 ++++++++++++++++++ test/unittests/instructions_test.cpp | 16 ++ 4 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 test/unittests/evm_eip663_dupn_swapn_test.cpp diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index e58cd1d33f..33f6e44b84 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(evmone-unittests evm_test.cpp evm_calls_test.cpp evm_control_flow_test.cpp + evm_eip663_dupn_swapn_test.cpp evm_eip2929_test.cpp evm_eip3198_basefee_test.cpp evm_eip3855_push0_test.cpp diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index e55ee49a0a..54925bef1e 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 over 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)}; diff --git a/test/unittests/evm_eip663_dupn_swapn_test.cpp b/test/unittests/evm_eip663_dupn_swapn_test.cpp new file mode 100644 index 0000000000..acc77911f4 --- /dev/null +++ b/test/unittests/evm_eip663_dupn_swapn_test.cpp @@ -0,0 +1,190 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2022 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "evm_fixture.hpp" +#include + +using namespace evmc::literals; +using namespace evmone; +using namespace intx; +using evmone::test::evm; + +TEST_P(evm, dupn) +{ + // DUPN is not implemented in Advanced. + if (evm::is_advanced()) + return; + + rev = EVMC_CANCUN; + + auto pushes = bytecode{}; + for (uint64_t i = 1; i <= 20; ++i) + pushes += push(i); + + execute(pushes + OP_DUPN + "00" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(20); + + execute(pushes + OP_DUPN + "02" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(18); + + execute(pushes + OP_DUPN + "13" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(1); + + execute(pushes + OP_DUPN + "14" + ret_top()); + EXPECT_STATUS(EVMC_STACK_UNDERFLOW); +} + +TEST_P(evm, swapn) +{ + // SWAPN is not implemented in Advanced. + if (evm::is_advanced()) + return; + + rev = EVMC_CANCUN; + + auto pushes = bytecode{}; + for (uint64_t i = 1; i <= 20; ++i) + pushes += push(i); + + execute(pushes + OP_SWAPN + "00" + ret_top()); + 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); +} + +TEST_P(evm, dupn_full_stack) +{ + // DUPN is not implemented in Advanced. + if (evm::is_advanced()) + return; + + rev = EVMC_CANCUN; + auto full_stack_code = bytecode{}; + for (uint64_t i = 1023; i >= 1; --i) + full_stack_code += push(i); + + execute(full_stack_code + OP_POP + OP_DUPN + "00" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(2); + + execute(full_stack_code + OP_POP + OP_DUPN + "ff" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(257); + + execute(full_stack_code + OP_POP + OP_DUPN + "fe" + ret_top()); + 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) +{ + // SWAPN is not implemented in Advanced. + if (evm::is_advanced()) + return; + + rev = EVMC_CANCUN; + auto full_stack_code = bytecode{}; + for (uint64_t i = 1024; i >= 1; --i) + full_stack_code += push(i); + + execute(full_stack_code + OP_POP + OP_SWAPN + "00" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(3); + + execute(full_stack_code + OP_POP + OP_SWAPN + "ff" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(255 + 3); + + execute(full_stack_code + OP_POP + OP_SWAPN + "fe" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(254 + 3); + + execute(full_stack_code + OP_SWAPN + "ff" + OP_SWAPN + "00" + OP_RETURN); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_EQ(result.output_size, 255 + 2); +} + +TEST_P(evm, dupn_dup_consistency) +{ + // DUPN is not implemented in Advanced. + if (evm::is_advanced()) + return; + + rev = EVMC_CANCUN; + auto pushes = bytecode{}; + for (uint64_t i = 32; i >= 1; --i) + pushes += push(i); + + execute(pushes + OP_DUP1 + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(1); + + execute(pushes + OP_DUPN + "00" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(1); + + execute(pushes + OP_DUP16 + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(16); + + execute(pushes + OP_DUPN + "0f" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(16); +} + +TEST_P(evm, swapn_swap_consistency) +{ + // DUPN is not implemented in Advanced. + if (evm::is_advanced()) + return; + + rev = EVMC_CANCUN; + auto pushes = bytecode{}; + for (uint64_t i = 32; i >= 1; --i) + pushes += push(i); + + execute(pushes + OP_SWAP1 + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(2); + + execute(pushes + OP_SWAPN + "00" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(2); + + execute(pushes + OP_SWAP16 + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(17); + + execute(pushes + OP_SWAPN + "0f" + ret_top()); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(17); +} diff --git a/test/unittests/instructions_test.cpp b/test/unittests/instructions_test.cpp index 1a36632287..e86550724b 100644 --- a/test/unittests/instructions_test.cpp +++ b/test/unittests/instructions_test.cpp @@ -55,6 +55,8 @@ constexpr void validate_traits_of() noexcept // immediate_size if constexpr (Op >= OP_PUSH1 && Op <= OP_PUSH32) static_assert(tr.immediate_size == Op - OP_PUSH1 + 1); + else if constexpr (Op == OP_DUPN || Op == OP_SWAPN) + static_assert(tr.immediate_size == 1); else static_assert(tr.immediate_size == 0); @@ -101,6 +103,10 @@ TEST(instructions, compare_with_evmc_instruction_tables) for (size_t i = 0; i < evmone_tbl.size(); ++i) { + // Skip DUPN and SWAPN for Cancun. 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)) + continue; const auto gas_cost = (instr_tbl[i] != instr::undefined) ? instr_tbl[i] : 0; const auto& metrics = evmone_tbl[i]; const auto& ref_metrics = evmc_tbl[i]; @@ -129,7 +135,13 @@ TEST(instructions, compare_undefined_instructions) const auto* evmc_names_tbl = evmc_get_instruction_names_table(rev); for (size_t i = 0; i < instr_tbl.size(); ++i) + { + // Skip DUPN and SWAPN. They are not defined in evmc + // TODO: Define DUPN and SWAPN in evmc + if (Opcode(i) == OP_DUPN || Opcode(i) == OP_SWAPN) + continue; EXPECT_EQ(instr_tbl[i] == instr::undefined, evmc_names_tbl[i] == nullptr) << i; + } } } @@ -138,6 +150,10 @@ 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. They are not defined in evmc + // TODO: Define DUPN and SWAPN in evmc + if (Opcode(i) == OP_DUPN || Opcode(i) == OP_SWAPN) + continue; EXPECT_STREQ(instr::traits[i].name, evmc_tbl[i]); } } From b14fad9bfc87bd66219fe322ecbadd856faad17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 13 Dec 2022 13:48:53 +0100 Subject: [PATCH 04/72] Set Opcode underlaying storage to uint8_t (#537) --- lib/evmone/instructions_opcodes.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/evmone/instructions_opcodes.hpp b/lib/evmone/instructions_opcodes.hpp index 8385c7120d..fdeb97e843 100644 --- a/lib/evmone/instructions_opcodes.hpp +++ b/lib/evmone/instructions_opcodes.hpp @@ -4,12 +4,14 @@ #pragma once -/// The list of EVM opcodes from every EVM revision. -/// -/// TODO: Change to `enum class Opcode: uint8_t`. namespace evmone { -enum Opcode + +/// The list of EVM opcodes from every EVM revision. +/// +/// This is not enum class because we want implicit conversion to integers, +/// e.g. for usage as an array index. +enum Opcode : uint8_t { OP_STOP = 0x00, OP_ADD = 0x01, From 94b8a92c3a614755021c3d4ea633403ac69d2a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Jun 2022 22:05:04 +0200 Subject: [PATCH 05/72] precompiles: Implement gas cost analysis --- test/state/precompiles.cpp | 196 ++++++++++++++++++++++++++++++++++++- test/state/precompiles.hpp | 25 ++++- 2 files changed, 217 insertions(+), 4 deletions(-) diff --git a/test/state/precompiles.cpp b/test/state/precompiles.cpp index 9ca58f199d..5b894e8df9 100644 --- a/test/state/precompiles.cpp +++ b/test/state/precompiles.cpp @@ -3,14 +3,187 @@ // SPDX-License-Identifier: Apache-2.0 #include "precompiles.hpp" +#include +#include +#include +#include +#include +#include namespace evmone::state { +using evmc::bytes; +using evmc::bytes_view; using namespace evmc::literals; +namespace +{ +constexpr auto GasCostMax = std::numeric_limits::max(); + +struct PrecompileAnalysis +{ + int64_t gas_cost; + size_t max_output_size; +}; + +inline constexpr int64_t num_words(size_t size_in_bytes) noexcept +{ + return static_cast((size_in_bytes + 31) / 32); +} + +template +inline constexpr int64_t cost_per_input_word(size_t input_size) noexcept +{ + return BaseCost + WordCost * num_words(input_size); +} + +PrecompileAnalysis ecrecover_analyze(bytes_view /*input*/, evmc_revision /*rev*/) noexcept +{ + return {3000, 32}; +} + +PrecompileAnalysis sha256_analyze(bytes_view input, evmc_revision /*rev*/) noexcept +{ + return {cost_per_input_word<60, 12>(input.size()), 32}; +} + +PrecompileAnalysis ripemd160_analyze(bytes_view input, evmc_revision /*rev*/) noexcept +{ + return {cost_per_input_word<600, 120>(input.size()), 32}; +} + +PrecompileAnalysis identity_analyze(bytes_view input, evmc_revision /*rev*/) noexcept +{ + return {cost_per_input_word<15, 3>(input.size()), input.size()}; +} + +PrecompileAnalysis ecadd_analyze(bytes_view /*input*/, evmc_revision rev) noexcept +{ + return {rev >= EVMC_ISTANBUL ? 150 : 500, 64}; +} + +PrecompileAnalysis ecmul_analyze(bytes_view /*input*/, evmc_revision rev) noexcept +{ + return {rev >= EVMC_ISTANBUL ? 6000 : 40000, 64}; +} + +PrecompileAnalysis ecpairing_analyze(bytes_view input, evmc_revision rev) noexcept +{ + const auto base_cost = (rev >= EVMC_ISTANBUL) ? 45000 : 100000; + const auto element_cost = (rev >= EVMC_ISTANBUL) ? 34000 : 80000; + const auto num_elements = static_cast(input.size() / 192); + return {base_cost + num_elements * element_cost, 32}; +} + +PrecompileAnalysis blake2bf_analyze(bytes_view input, evmc_revision) noexcept +{ + return {input.size() == 213 ? intx::be::unsafe::load(input.data()) : GasCostMax, 64}; +} + +PrecompileAnalysis expmod_analyze(bytes_view input, evmc_revision rev) noexcept +{ + using namespace intx; + + static constexpr size_t input_header_required_size = 3 * sizeof(uint256); + const int64_t min_gas = (rev >= EVMC_BERLIN) ? 200 : 0; + + uint8_t input_header[input_header_required_size]{}; + std::copy_n(input.data(), std::min(input.size(), input_header_required_size), input_header); + + const auto base_len = be::unsafe::load(&input_header[0]); + const auto exp_len = be::unsafe::load(&input_header[32]); + const auto mod_len = be::unsafe::load(&input_header[64]); + + if (base_len == 0 && mod_len == 0) + return {min_gas, 0}; + + static constexpr auto len_limit = std::numeric_limits::max(); + if (base_len > len_limit || exp_len > len_limit || mod_len > len_limit) + return {GasCostMax, 0}; + + auto adjusted_len = [input](size_t offset, size_t len) { + const auto head_len = std::min(len, size_t{32}); + const auto head_explicit_len = + std::max(std::min(offset + head_len, input.size()), offset) - offset; + const bytes_view head_explicit_bytes(&input[offset], head_explicit_len); + const auto top_byte_index = head_explicit_bytes.find_first_not_of(uint8_t{0}); + const size_t exp_bit_width = + (top_byte_index != bytes_view::npos) ? + (head_len - top_byte_index - 1) * 8 + + static_cast(std::bit_width(head_explicit_bytes[top_byte_index])) : + 0; + + return std::max( + 8 * (std::max(len, size_t{32}) - 32) + (std::max(exp_bit_width, size_t{1}) - 1), + size_t{1}); + }; + + static constexpr auto mult_complexity_eip2565 = [](const uint256& x) noexcept { + const auto w = (x + 7) >> 3; + return w * w; + }; + static constexpr auto mult_complexity_eip198 = [](const uint256& x) noexcept { + const auto x2 = x * x; + return (x <= 64) ? x2 : + (x <= 1024) ? (x2 >> 2) + 96 * x - 3072 : + (x2 >> 4) + 480 * x - 199680; + }; + + const auto max_len = std::max(mod_len, base_len); + const auto adjusted_exp_len = adjusted_len( + sizeof(input_header) + static_cast(base_len), static_cast(exp_len)); + const auto gas = (rev >= EVMC_BERLIN) ? + mult_complexity_eip2565(max_len) * adjusted_exp_len / 3 : + mult_complexity_eip198(max_len) * adjusted_exp_len / 20; + return {std::max(min_gas, static_cast(std::min(gas, intx::uint256{GasCostMax}))), + static_cast(mod_len)}; +} + +ExecutionResult identity_execute(const uint8_t* input, size_t input_size, uint8_t* output, + [[maybe_unused]] size_t output_size) noexcept +{ + assert(output_size == input_size); + std::copy_n(input, input_size, output); + return {EVMC_SUCCESS, input_size}; +} + +struct PrecompileTraits +{ + decltype(identity_analyze)* analyze = nullptr; + decltype(identity_execute)* execute = nullptr; +}; + +template +ExecutionResult dummy_execute(const uint8_t*, size_t, uint8_t*, size_t) noexcept +{ + std::cerr << "Precompile " << static_cast(Id) << " not implemented!\n"; + return ExecutionResult{EVMC_INTERNAL_ERROR, 0}; +} + +inline constexpr auto traits = []() noexcept { + std::array tbl{{ + {}, // undefined for 0 + {ecrecover_analyze, dummy_execute}, + {sha256_analyze, dummy_execute}, + {ripemd160_analyze, dummy_execute}, + {identity_analyze, identity_execute}, + {expmod_analyze, dummy_execute}, + {ecadd_analyze, dummy_execute}, + {ecmul_analyze, dummy_execute}, + {ecpairing_analyze, dummy_execute}, + {blake2bf_analyze, dummy_execute}, + }}; + return tbl; +}(); +} // namespace + std::optional call_precompile(evmc_revision rev, const evmc_message& msg) noexcept { - if (evmc::is_zero(msg.code_address) || msg.code_address > 0x09_address) + // Define compile-time constant, + // TODO: workaround for Clang Analyzer bug https://github.com/llvm/llvm-project/issues/59493. + static constexpr evmc::address address_boundary{NumPrecompiles}; + + if (evmc::is_zero(msg.code_address) || msg.code_address >= address_boundary) return {}; const auto id = msg.code_address.bytes[19]; @@ -20,6 +193,25 @@ std::optional call_precompile(evmc_revision rev, const evmc_messag if (rev < EVMC_ISTANBUL && id > 8) return {}; - return evmc::Result{EVMC_INTERNAL_ERROR}; // Not implemented. + assert(id > 0); + assert(msg.gas >= 0); + + const auto [analyze, execute] = traits[id]; + + const bytes_view input{msg.input_data, msg.input_size}; + const auto [gas_cost, max_output_size] = analyze(input, rev); + const auto gas_left = msg.gas - gas_cost; + if (gas_left < 0) + return evmc::Result{EVMC_OUT_OF_GAS}; + + uint8_t output_buf[256]; // Big enough to handle all "expmod" tests. + assert(std::size(output_buf) >= max_output_size); + + const auto [status_code, output_size] = + execute(msg.input_data, msg.input_size, output_buf, max_output_size); + + evmc::Result result{ + status_code, status_code == EVMC_SUCCESS ? gas_left : 0, 0, output_buf, output_size}; + return result; } } // namespace evmone::state diff --git a/test/state/precompiles.hpp b/test/state/precompiles.hpp index f6bc963213..4169f6cbec 100644 --- a/test/state/precompiles.hpp +++ b/test/state/precompiles.hpp @@ -1,7 +1,6 @@ // evmone: Fast Ethereum Virtual Machine implementation // Copyright 2022 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 - #pragma once #include @@ -9,5 +8,27 @@ namespace evmone::state { +/// The total number of known precompiles ids, including 0. +inline constexpr std::size_t NumPrecompiles = 10; + +enum class PrecompileId : uint8_t +{ + ecrecover = 0x01, + sha256 = 0x02, + ripemd160 = 0x03, + identity = 0x04, + expmod = 0x05, + ecadd = 0x06, + ecmul = 0x07, + ecpairing = 0x08, + blake2bf = 0x09, +}; + +struct ExecutionResult +{ + evmc_status_code status_code; + size_t output_size; +}; + std::optional call_precompile(evmc_revision rev, const evmc_message& msg) noexcept; -} +} // namespace evmone::state From c776b4283769c2418ba27e256335c3ae957384e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 16 Jul 2022 14:11:37 +0200 Subject: [PATCH 06/72] precompiles: Cache precompiles' execution results --- test/state/CMakeLists.txt | 2 ++ test/state/precompiles.cpp | 10 +++++++-- test/state/precompiles.hpp | 10 +++++++++ test/state/precompiles_cache.cpp | 35 +++++++++++++++++++++++++++++++ test/state/precompiles_cache.hpp | 36 ++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 test/state/precompiles_cache.cpp create mode 100644 test/state/precompiles_cache.hpp diff --git a/test/state/CMakeLists.txt b/test/state/CMakeLists.txt index 7fc1f82608..3f6858da34 100644 --- a/test/state/CMakeLists.txt +++ b/test/state/CMakeLists.txt @@ -18,6 +18,8 @@ target_sources( mpt_hash.cpp precompiles.hpp precompiles.cpp + precompiles_cache.hpp + precompiles_cache.cpp rlp.hpp state.hpp state.cpp diff --git a/test/state/precompiles.cpp b/test/state/precompiles.cpp index 5b894e8df9..47c9b81b16 100644 --- a/test/state/precompiles.cpp +++ b/test/state/precompiles.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "precompiles.hpp" +#include "precompiles_cache.hpp" #include #include #include @@ -12,8 +13,6 @@ namespace evmone::state { -using evmc::bytes; -using evmc::bytes_view; using namespace evmc::literals; namespace @@ -204,6 +203,10 @@ std::optional call_precompile(evmc_revision rev, const evmc_messag if (gas_left < 0) return evmc::Result{EVMC_OUT_OF_GAS}; + static Cache cache; + if (auto r = cache.find(static_cast(id), input, gas_left); r.has_value()) + return r; + uint8_t output_buf[256]; // Big enough to handle all "expmod" tests. assert(std::size(output_buf) >= max_output_size); @@ -212,6 +215,9 @@ std::optional call_precompile(evmc_revision rev, const evmc_messag evmc::Result result{ status_code, status_code == EVMC_SUCCESS ? gas_left : 0, 0, output_buf, output_size}; + + cache.insert(static_cast(id), input, result); + return result; } } // namespace evmone::state diff --git a/test/state/precompiles.hpp b/test/state/precompiles.hpp index 4169f6cbec..f0911c8381 100644 --- a/test/state/precompiles.hpp +++ b/test/state/precompiles.hpp @@ -5,6 +5,16 @@ #include #include +#include + +namespace stdx +{ +template +inline constexpr auto to_underlying(EnumT e) noexcept +{ + return static_cast>(e); +} +} // namespace stdx namespace evmone::state { diff --git a/test/state/precompiles_cache.cpp b/test/state/precompiles_cache.cpp new file mode 100644 index 0000000000..683e915186 --- /dev/null +++ b/test/state/precompiles_cache.cpp @@ -0,0 +1,35 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2022 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "precompiles_cache.hpp" + +namespace evmone::state +{ +std::optional Cache::find(PrecompileId id, bytes_view input, int64_t gas_left) const +{ + if (const auto& cache = m_cache.at(stdx::to_underlying(id)); !cache.empty()) + { + const auto input_hash = keccak256(input); + if (const auto it = cache.find(input_hash); it != cache.end()) + { + if (const auto& o = it->second; !o.has_value()) + return evmc::Result{EVMC_PRECOMPILE_FAILURE}; + else + return evmc::Result{EVMC_SUCCESS, gas_left, 0, o->data(), o->size()}; + } + } + return {}; +} + +void Cache::insert(PrecompileId id, bytes_view input, const evmc::Result& result) +{ + if (id == PrecompileId::identity) // Do not cache "identity". + return; + const auto input_hash = keccak256(input); + std::optional cached_output; + if (result.status_code == EVMC_SUCCESS) + cached_output = bytes{result.output_data, result.output_size}; + m_cache.at(stdx::to_underlying(id)).insert({input_hash, std::move(cached_output)}); +} +} // namespace evmone::state diff --git a/test/state/precompiles_cache.hpp b/test/state/precompiles_cache.hpp new file mode 100644 index 0000000000..316f62e65b --- /dev/null +++ b/test/state/precompiles_cache.hpp @@ -0,0 +1,36 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2022 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "hash_utils.hpp" +#include "precompiles.hpp" +#include +#include +#include +#include +#include + +namespace evmone::state +{ +using evmc::bytes; +using evmc::bytes_view; + +class Cache +{ + std::array>, NumPrecompiles> m_cache; + +public: + /// Lookups the precompiles cache. + /// + /// @param id The precompile ID. + /// @param input The input for precompile execution. + /// @param gas_left The amount of gas left _after_ execution, + /// used for constructing the result for successful execution. + /// @return The cached execution result + /// or std::nullopt if the matching cache entry is not found. + std::optional find(PrecompileId id, bytes_view input, int64_t gas_left) const; + + /// Inserts new precompiles cache entry. + void insert(PrecompileId id, bytes_view input, const evmc::Result& result); +}; +} // namespace evmone::state From 15fe385d1322d560dc0c5e66d274459249eb5fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 1 Aug 2022 12:21:04 +0200 Subject: [PATCH 07/72] precompiles: Dump and load precompiles' cache --- test/state/precompiles_cache.cpp | 61 ++++++++++++++++++++++++++++++++ test/state/precompiles_cache.hpp | 3 ++ 2 files changed, 64 insertions(+) diff --git a/test/state/precompiles_cache.cpp b/test/state/precompiles_cache.cpp index 683e915186..3d5edd1fba 100644 --- a/test/state/precompiles_cache.cpp +++ b/test/state/precompiles_cache.cpp @@ -2,7 +2,15 @@ // Copyright 2022 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 +#ifdef _MSC_VER +// Disable warning C4996: 'getenv': This function or variable may be unsafe. +#define _CRT_SECURE_NO_WARNINGS +#endif + #include "precompiles_cache.hpp" +#include +#include +#include namespace evmone::state { @@ -32,4 +40,57 @@ void Cache::insert(PrecompileId id, bytes_view input, const evmc::Result& result cached_output = bytes{result.output_data, result.output_size}; m_cache.at(stdx::to_underlying(id)).insert({input_hash, std::move(cached_output)}); } + +Cache::Cache() noexcept +{ + const auto stub_file = std::getenv("EVMONE_PRECOMPILES_STUB"); + if (stub_file == nullptr) + return; + + try + { + const auto j = nlohmann::json::parse(std::ifstream{stub_file}); + for (size_t id = 0; id < j.size(); ++id) + { + auto& cache = m_cache.at(id); + for (const auto& [h_str, j_input] : j[id].items()) + { + auto& e = cache[evmc::from_hex(h_str).value()]; + if (!j_input.is_null()) + e = evmc::from_hex(j_input.get()); + } + } + } + catch (...) + { + std::cerr << "evmone: Loading precompiles stub from '" << stub_file << "' has failed!\n"; + } +} + +Cache::~Cache() noexcept +{ + const auto dump_file = std::getenv("EVMONE_PRECOMPILES_DUMP"); + if (dump_file == nullptr) + return; + + try + { + nlohmann::json j; + for (size_t id = 0; id < std::size(m_cache); ++id) + { + auto& q = j[id]; + for (const auto& [h, o] : m_cache[id]) + { + auto& v = q[evmc::hex(h)]; + if (o) + v = evmc::hex(*o); + } + } + std::ofstream{dump_file} << std::setw(2) << j << '\n'; + } + catch (...) + { + std::cerr << "evmone: Dumping precompiles to '" << dump_file << "' has failed!\n"; + } +} } // namespace evmone::state diff --git a/test/state/precompiles_cache.hpp b/test/state/precompiles_cache.hpp index 316f62e65b..333976aa3b 100644 --- a/test/state/precompiles_cache.hpp +++ b/test/state/precompiles_cache.hpp @@ -20,6 +20,9 @@ class Cache std::array>, NumPrecompiles> m_cache; public: + Cache() noexcept; + ~Cache() noexcept; + /// Lookups the precompiles cache. /// /// @param id The precompile ID. From 5cae37a8aad7b297cd03e5c260ac884953f12096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 1 Aug 2022 13:28:48 +0200 Subject: [PATCH 08/72] precompiles: Add JSON stub of precompiles --- test/state/precompiles_stub.json | 696 +++++++++++++++++++++++++++++++ 1 file changed, 696 insertions(+) create mode 100644 test/state/precompiles_stub.json diff --git a/test/state/precompiles_stub.json b/test/state/precompiles_stub.json new file mode 100644 index 0000000000..2d15618a7d --- /dev/null +++ b/test/state/precompiles_stub.json @@ -0,0 +1,696 @@ +[ + null, + { + "009d9ee6ae2a8d2d33a6152cbd20b53e8e846228d6f5c3ba6df1c81f16d3f127": "", + "011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce": "", + "012893657d8eb2efad4de0a91bcd0e39ad9837745dec3ea923737ea803fc8e3d": "", + "044c8039b0e70b0a95fd48ef3fee93f60176902cedd5e692a3a73f69405300af": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "068218ef30064c84e88ce57ca518f25f82f1d14ae170f243051ba7d42d13f2be": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "0f81fd306d0c0cddd0728a76e6bfb0dfa12891c89994d877f0445483563b380a": "", + "121147ddfb9d189965dfcd9fc6a29d3a1e305fca28524a93dcc02dc1d01caa8d": "0000000000000000000000004c78739de03a70dbcf9b94bc21daf2bf46d44375", + "12ad18e8525e960f8c93c071d7e907981d6a1badf935b80c16e6ad790baf7fc5": "0000000000000000000000000f00d6a30e65104b909aa43d947ef2010e09446a", + "155ebbd01c7ab8c9e897a5907b01160b4b5fba72d9fd8fa7bbbd040ad8e10de3": "", + "15fed0451499512d95f3ec5a41c878b9de55f21878b5b4e190d4667ec709b4cf": "", + "16098be41cfab56cfc4e3d4ecf69407d06a3be90af6ded11696f19fddf23d474": "", + "16d64d4187a874fb2ecabfe23d426940d85ad700c2dbffa2a924a3bb27dbb769": "", + "184125b2e3d1ded2ad3f82a383d9b09bd5bac4ccea4d41092f49523399598aca": "", + "18e0a11d3c25dfdd8c3ebf5a3c431bc88349da31fdab52724d114b321edf959a": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "19617bb47c97a16b82eefd111c3ef2c88f1cb7ad4bbefdd5c52c3cdd910c6651": "", + "1bb6cba805b67c1733b643a25c6f9fee23e62eb39b943c736a781df8a7525680": "", + "1c56a607154e4c8de8c67f33a3106afba5b84fbc7c8c8735b2cb9908a3fc74f5": "", + "1cd9efb2ba7ed02bf88d37210f589f8440ce3365b081b37c07d350cf0fae4371": "", + "1d8453ab2f7716504a4457ebe9831dbf996267e350ad0b2029f654d0dce1e055": "", + "1d9ce567b95236f552a05b29064a31e5bfc7f859e38a2722acc2db99b3d8c8a2": "", + "1da37edc3bb58391e0d9d65acfc452feda09ea79af15ef9d629e927055ad9661": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "1fd6d417f8358520da705dcf9664a19a58dc8c5bc060459f0b30a0de9318a0e5": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "20047d6c3a7cdb146351139ec6ee0f79e7df10a29bf27b9d9764efe10be3d51b": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "20b9a18492383c417bca756db64e24237b56f819771ceea5320f9e862c0b8503": "", + "21694f3ea9a52e859108e909331f609b3ccad56c4c975974094e55316ca124ed": "000000000000000000000000fc4539330fee551b296f9396d01ab7643521d5df", + "23b5d657f8f6a213c0dd0847b57a61477bdebad32c94cfa191a6ed4622f6cdc6": "000000000000000000000000389a57ba1c546578b67167c6571d92e047bd4029", + "248f21a78a10df8e98ae4bc941cac92a8e6e07244b11f43fa70537f81513bf52": "", + "24d0f21724fc3b3bef5d93f5e0d7fc9aab70fe0f1cdc79ccbe81025d1daedc94": "000000000000000000000000ad5a9fc193dcf16041d4e96433ef3a6d82d36b16", + "255ba666481586d8a19c818613b8902832669667049a80f876276e0e8b1b7faf": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "26758654639a74eafce1decd301a0c76f7a57162bad0b763be2765578416f1bf": "", + "276d032750f286c508d060efcddd1b7a9becbfdb64efb5dfcbee057f86722fef": "", + "283ed216d65f248c2522811579b2652e949520ca3f4c0c86af2beb6692dd9c83": "", + "28489601bd9ae32c886d8ae05c9249311ad3d440b6384dd707c4cbda2441c40f": "000000000000000000000000364a9dae48110760306b009bf2297819176be559", + "290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": "", + "2af357fc2ab2964b76482ec0fcac3b86f5aca1a8292676023c8b9ec392d821a0": "", + "2ddc60dbbc6777935bc0a435d3a77b75909e18e42a80016f33fb2b8585aac3b3": "", + "2e795758918d9c804da815b3be88b798e63d21d668c624228fbd697bff25ea3b": "", + "2e8aa99ac952c926b1c0bb0a5e3c329c5034064c62ef4110d7e23edea7ee94d6": "000000000000000000000000b4950a7fad428434b11c357fa6d4b4bcd3096a5d", + "2ece9425df06ce26f47bfeb62cd58816af93cbd581da47cf24d392854d101e12": "", + "307e519a0d583c4346c5bbc14c5e5bd3d56cb6096dbfe2c033bed9bd3df24e23": "00000000000000000000000001c954021193a220878900cf5f7db5b3ea4c2b24", + "307f9f77474286909ec7d1de723ce0d1803f25184e288f7f4010c8cab8a9a964": "", + "30e224dbf56e9075c98996690ef5716a82c652d363c75e2895632196016b14b7": "00000000000000000000000019e7e376e7c213b7e7e7e46cc70a5dd086daff2a", + "30e2bfdaad2f3c218a1a8cc54fa1c4e6182b6b7f3bca273390cf587b50b47311": "", + "3184fc86524b0495db56f434fba34e478911db355cbb44815e987625ab42e557": "", + "322ebff356b39a0fdca6dc8a23b37746ce13e6bb5fb284eedc03ab65c7f36d42": "", + "3372afbaf0a4eee019450dba6aa152840875c80c83e433d4b9abda54f414bf7e": "", + "34c2175d62f5203de28e4ad262af278307bab5159024d49ff03b0b5716cf6bde": "", + "3565fe444d17a1d3e7e2c6fcf26239a579b98ec7d6a15a82056159e3c85e066c": "", + "38d1e68159186ade831fbe4872dfa94955c86cced3fd6c4555f5350908efbbac": "", + "3abb6f45dcab55efca9712461264d554ab6facb4c0c0afeb668bf5aa43c41dc8": "", + "3dc5064867fdde3ea414107c203aaf64fa40d079b507f03fb05d5d651bedf6ca": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "3e0cd3adba79d8cdfe018df6b11eeea126842d7c648f55f759a13cc0d8cca632": "0000000000000000000000008324683aaae32ccebdeb758e2777ab2b1ce3d3f1", + "3f0b47fc77754afe57e9f10470ce33d56fb6ef8755868188c43674e45911cc5f": "000000000000000000000000e8e2d3e49d1bb0ddf5beeff311456f251dae9ea9", + "3f14010fd6ad2d379bc84717dcfde1adbd49ab0effd164d6f48687e3b64eec7a": "", + "3f9ae92b3cf5cb96dc4e9dc10e2d2c668577014e6e8a3978cb021a2c9457db1a": "", + "402ca0e8663865c03b0fcae18b2d13b8a1a07b4db2aa174fd4449a666ecd043d": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "40d1059b882052f28a776dffb83ae2000f4975ea9cd103d13c8ebe16bafc8ce4": "", + "41414fecbcd48d24288f4cd69cdc4f11560667f16291c4c642082019a2c613a6": "", + "421f83b9cb3c1673e660435b3392b0ad5cc7d97852d16ea20410bf4bf44c755f": "000000000000000000000000d1d3bc125318dd71176248d9c86f41a842d4bec9", + "43087d053f72c42d4ff586b734a684f275adbda4bff302f6aabbc7f908cbf56e": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "438f6c5a8ed820e3a148e6b3bfaf27a8eb67a5bac583cd51e3f74fa35d2adb36": "", + "44a25c9533b4c9e05472848068a6b5bcb693ce9e222f3f4ac82d2927a82a34ce": "", + "44fc8b2192a7abb4907a620aa0760b455b3aff99736d1a8817d504ea1ec91cbd": "000000000000000000000000295ad34cb312eaf9574511208848caf57b7429e0", + "452ee175b6d3ed54e5d16d3a3218fd899ba99aed67e974d13a75b7442e24efd7": "", + "459c0d89c260a919fbdf013d6707f1794bd332260626b08df4d053c5eedd2aaf": "", + "462c247a22c49aa7de40d030c1d242dfe2fb47003ab3f0b9924677dbff038ddd": "", + "471ccdcb79bddea38175f8cc115b52365f2c864200fbce48e994511bb9c6006f": "", + "48107462b0f7d0d5cc3106b4ddbed581fd1a7182c10fde2e83830c6f13896a1c": "", + "48a6d470f69a7958d16348af5c419d4f155cde98e4fe7e25f0e1e4de2a176d48": "", + "4d8a735acc38ab7f01310ca8e6026ed9f86de88141cd83996db741df5291fc0d": "", + "4f01ca2b90db2ac03064f2958683e809503a6270c67d4219b13b257c5018c178": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "4fef400b93123b210519abd8c81e39e17e4a691a8bdf200e08c3beaa04877033": "", + "5037e1a5e02e081b1b850b130eca7ac17335fdf4c61cc5ff6ae765196fb0d5b3": "", + "50a8aca900c34e14fe43aa0d7f132065c799ac1d8307abec60e78abf3d41472c": "", + "5127452b278723071f64915211d191a7a59f729ab3c9617de94070d86a86c22c": "000000000000000000000000db658a31f5a174be0e3fc0d0ce05dd6a76084910", + "5178143227fe4c2d9ab33dfce3eb6bcc5fc73e407a3fccc4c03be2fdb46cdfe5": "", + "525603e86451df346317e6ccf0c38a1d1a79728e7389c228d69d7a6c136ea083": "000000000000000000000000294091b609877b020b4f5a01357936fc0a877a3f", + "52e07c5ac4c91ad28aec87754a1cd4f14c256516e453b562fff2a8ab56e90e1c": "0000000000000000000000008d682238981c4940830fa6971d25e036d1fb3d27", + "5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a": "", + "5429fdc28e48579bde709c0ca18c55d58f14c9438d5cd1829556be99fd68b97b": "", + "54a8c0ab653c15bfb48b47fd011ba2b9617af01cb45cab344acd57c924d56798": "", + "5562d44b8038c7ec81ac64c10e44ed3b5638aebd3a8cb9d4231533aa9cb3890e": "", + "55cb0ca323c8496a60242fbec05d1a55aa53b3fefbfefa93115fd7f6fe209b4f": "000000000000000000000000e4319f4b631c6d0fcfc84045dbcb676865fe5e13", + "56dd7445e8246202dd28c795ebcb656c70ba9075063cbc3aae6749690fc13afb": "", + "5753138212d78ca85a6b17affd10cca7cffce1fbe25c66b53efc4fadcc45bb91": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "57a8be445205924e80a60daf8a9ac2b83b55eb01eff01bcb1825be87c44dae93": "", + "584f46c60af19681376031579adb04a2416e54ee5505351c2a8435e3766026ea": "", + "59642f809245ca2950deda7acf1d460ac419ef7a8d003ac6bb42f69b01891e5d": "", + "5a1cf9bc06adcfe7397b3edc00612d7ec7dfa0d44afec417e27d3665389cae6b": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "5a22989ecb853baf2104fce8bd10d880da4887a5ec058c170e31a832db4f2a56": "", + "5a657105c493a1213c976c653e929218bb4a516bca307dce5861ec23fffa4e58": "", + "5b6513d4747d845f5045a8daad79201c65d806755f4ffba68b1dcb0c78f5644c": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "5b7d7eba22589dfe1bd7a5417faa2a79838f19c58fe7408d6f66be2327cc996d": "", + "5bf1ea6f086a8edde772752dfa3b9102e6e90497d752287cbaee235d48d1f69e": "", + "5d855fe977abaa48cd5f626a97eb798ae0ffde421de3692c0684845a6c908f47": "", + "5d8af3eccd090407b914616ecb273b9d6c3321c26358e846ccb87a888d338b27": "", + "5efd0f3a104ddc539f268599d2486848f6ca5c071d92023886dbec25407df538": "000000000000000000000000b957b0da344f6a17f0081d63be7345a860e5b7a2", + "660b057b36925d4a0da5bf6588b4c64cff7f27ee34e9c90b052829bf8e2a3168": "", + "6637c8865151f4ac40e4faf213f7d2977eaaa48db59e39f3165abb87e89af8ce": "", + "66506b929ebb30dc155fef68827caf7ae6824e9b0bd7739084032e0289b333af": "", + "67695e93912019e851979ca0f51d809fc95d5c56231031a0a8e56cc735c10f2e": "0000000000000000000000000669457ce81442f235ffc4123662ba14a72b3d68", + "684a72a8364370adc3d8d142106fd330108bc92b6442f7cddda4e80d32d1b83b": "000000000000000000000000628f176bc4c64973abaf9acb6bd8bb8d9b1ae97c", + "6979bb29b5523d4b8ca0ddfd55cff3859487cbf2895662e9ec76e4df9d8aff52": "", + "6a26b4975755a21ffa22fa06d2eaa4c1e6d5ca8834c8719696bc8710f64eee3a": "", + "6bd2dd6bd408cbee33429358bf24fdc64612fbf8b1b4db604518f40ffd34b607": "", + "6e9182355718eec6f927067ac2afc5ecb3263628cf2f2921325fd04d7e3a8c84": "", + "6f9c0300d90788e3eaa2560d9c84298b436854bda9b9a4a9e9e04faa2e5e88c4": "", + "6f9f7d0ce1cd35fb86afc3632aac96fd0b294d1bf711d580a0a32f6437d4a503": "", + "7095093e306a452d41ba776c418b6dd1ffc7c68597b398a913372aa156d31aed": "", + "71db10bdc258e5d3dde75d0d15c5894acd8a0769f0b6935c65357770b1664eaf": "00000000000000000000000099cd51158e59da36ba48b457c02db77c17a6b91a", + "723738cd5b48e795bdb00ebbca91cb4b498909292a6b85555c6eeb7190692f2b": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "73671bbc396a6200adb90f1c8a061271dcf14f76976270cc64d6c97ba3bad94c": "", + "74723bc3efaf59d897623890ae3912b9be3c4c67ccee3ffcf10b36406c722c1b": "", + "74f5c4fd14a98241a85e9423e3fface2601c9dc66f7312cb2c120aba0a3db2aa": "", + "767bfb6ead6760f170718f8074950b9439f9d58e73b64f2554c474039f0e3eb4": "", + "784453c1eb01e806f21450010bb46832f5151aff4f41054783581cc36d411771": "", + "7a679a18af6a41aa0d5b7762b4a3e0401de8d78e66d0bc95b1b0cd144e8d5375": "0000000000000000000000009ca540e3f00347324bd94a94ce8e3a34b97c8244", + "7ac9bd10a3348ddeefe5fd2eea3686e33d5ee977cb0eba91ea90eb208b46a9c1": "00000000000000000000000016fe7fa0cb8a861f855039c2eda9251ca7cc79d0", + "7b4f30428fe6d4352f5dc0eb4f1ce59738fbb1ccf3468278bcd80b641ffdeaed": "0000000000000000000000001b85ac3c9b09de43659c5d04a2d9c75457d9abf4", + "7cdb9d7f02ea58dfeb797ed6b4f7ea68846e4f2b0e30ed1535fc98b60c4ec809": "", + "7e3e86118a8190c9742950d3d561bbfd43a8656d93456b328827efd6ce1589c9": "000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "7f2b59c8ac5698b4999e23adaf72c6ed4500fbd0d7734f881c5eb19e7b9ebd75": "", + "827b659bbda2a0bdecce2c91b8b68462545758f3eba2dbefef18e0daf84f5ccd": "", + "8425bc38f66e7882cfe1f974d4ee7f60e5476f4022b013b359ce5b353daf3057": "", + "861aeab295b8278ea72b1865b19d1517c018ff03d9b0a204efbecf7e0dae0804": "", + "86bca244dcf7c90a21f3e6a344ff75070b1182f2ed2d7bdd9b1db823ebffb616": "", + "87d456d16f0132e129b8ce55d8a63de8f9db49e36fc3d4c254860953494b2b77": "", + "8862cb036babe7f70eab2baeb040a97aafc095920878bc170d51c2df8e4d3df4": "0000000000000000000000001387af122c1e31a2dd1dac303b3f20ad83f0ed1b", + "89bb58666f09724bc750b264709704f4c47eaf3c227ed3e7c46e7f141960ae97": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "8c3a47de78197a12495b1b381467f70d10231a44907e73dacc7c548569326dc4": "", + "8ef70542b3dab086ca818bf61eb2c89a31dd266a0f89825cedfff865db68fb2c": "000000000000000000000000dcc53a4a0719101437e8791abf273af5893cb174", + "913b834257c793da6424db222da1ff2f6fd6170ac3094be0405cdcc5552e1a78": "", + "9166c8d72e513a9e3b8389c11481ec071da93e37370fc62bf99c51a7b869a7dd": "", + "91cad3515fc13b619cce04e1638c1cb4c7ad83e080adc65c7d3f00f0164d7e34": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "94374ea151ea3e73d7dd2fb895cb7f0c645bb54bd2d9a388e6209a57af17a19f": "", + "951b260673d281ef5873abcc5c7cca42ce9e4e4a27050f670a4873532efa3b71": "", + "96e2012ae1835f1b97d8521c4558a877b98f5dbd5fbe082f6a7747eaa649fe09": "", + "970267c3e058dd3893130643eb8b30d2a91e553210b887b8f70d5522d22bfeb9": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "998426673b3a3276a06d34611d862b55d977d67df6d1a9869391b775f5128c3b": "", + "99ff0d9125e1fc9531a11262e15aeb2c60509a078c4cc4c64cefdfb06ff68647": "", + "9b09bcaad3f649578d7ef2b6acf584aec1bd37c9dcc3642a9df5202f3f7c80fd": "0000000000000000000000008e5817968f74ffb0255ae41eefa6f89dd0183fa1", + "9dc625ddb208b1c059f12493751a97855ec303a68b114f2756b842b513192ca4": "000000000000000000000000a1889691e30136d95c0543f516bf2357b282d835", + "a15de862eeaf0bf4bbe7d487b3c73e0062611ff0c2a1c8efb7ee70a07947600d": "", + "a3053687a9f160a16cdb363f9088bc719c812e3777e2124134cc79604d2dce5a": "0000000000000000000000005c4725e00d8f9415e2b77630543fe41dcdaaa304", + "a345ce13ce768748744c207a4c9224691722d4697fc14702db48648e10d69740": "", + "a47177933c8f355f8088754dc8ab101c196f76512e19f784741ed2f96f2c8f31": "", + "a533db48442c1c18882149f8a3b768b48288edf57aecf5122aa8b9170d52dcb2": "", + "a81e2ba117de5a113588647e5864dd9d67d2b04ec1abc35fe3923c24b17ebf39": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "a860d0fcf0b95e3ad7f130c3dcce8fff0d3e98b0d63e6ff2a78d4dc82f6e81a8": "", + "a86d54e9aab41ae5e520ff0062ff1b4cbd0b2192bb01080a058bb170d84e6457": "", + "ab699ccf43a5742809e63fb47016309315b3a496a6ab2938485661d986e0a7eb": "", + "ace33d109b3796ad0870d2cdd24f5ba60631ed1c61bf23082a27000636f0d756": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "ad315e209dd62516ab8c7d1c2d8c3c206525501ebef91d12c34431f9ea255371": "", + "adaf372fcd93e6510620653a95d8b22c5e3c1ac0536d7b2362a5bbb3c7b49df1": "", + "ae394eace5cda18bf10286f929a2ce510e8545db3efe236f48f3df4dd51b21c6": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "aef160683b3dc2aefe89736560824cec0a4d9b028f2fa47cf969747d9dfb3d41": "0000000000000000000000000a74178ec0a865b84eed705e85ddf9b5002389ab", + "b05641b5cfede170815a9efb5af9bc0e545503dba1e869a2a03a952ac316b471": "", + "b17a251204f3edd07092143ea255bd43e0e46bfd2c5d2299d4fcdc87ec0135b3": "000000000000000000000000d8765900c0f467df6bc4f514ed39c568497a8ead", + "b4509c0c8084cd0ab241aeab9996adcf19de6980eef05ea888f88ce18f33339e": "", + "b696031ea0505df7c7b5cc290e50cea0402d2a396b0db1c5d08155bd219cc52e": "", + "b8b5dd07b6aa51acac77dc23bff5aedaa33ec78caabb77a2ba2e4e07cd69c2b2": "", + "b8eb56735b6e0948cdb2059ebe727b7fb20fc4affddf2b590253f6b30884c600": "", + "b9a919f9df630de181473a346f22e332f99b1b51a30a4e3b790d57d37c09f0a6": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "bbe03e3a8ba322502f4ad5d333d0fabcf2ce72904dff3bf9ae471d6ef2e31508": "", + "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a": "", + "be48a95e08d0841125714329c6cbf30767e04765c56c0e532ef4c41a8eed9d98": "000000000000000000000000f6defd0f92f2a018ba20bf6051698a8dde7cc949", + "bf1039e9d8f458cb0631edfab4902ce135879eb69e38484e881a6574a68ba9c0": "", + "bf53adb76067fdab0d008aef3ad8b28bbb63c2ce4c2b63394ede73f01a70c865": "", + "bf6d9351d12dad52142cb4f941f972be10a491ad4e76c886f82039f7b45a8605": "", + "bfdc1d6c53b5979b35506e0ea4387c3d4b7a6a4187d5d3a3bf6482efba1224bd": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "c0d41db1b6c5cd39e7205798b17f08eb6fc41ffc96eeaace0bef52fdf71aa9ab": "", + "c2398b32244735b68576beb4f02d12ab087c00b24d1afad52818bd40237341e4": "", + "c2ec347ed6bcf952be26799e2423c44f0c0bc057d9bfca220a74223d57974c60": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "c35d14d63fd65983b84417bc725647d5b2616b0f149f3835bbe92cc6dab2fa39": "00000000000000000000000079e727f2f0f816efd56fc2af37d98af6798551df", + "c41589e7559804ea4a2080dad19d876a024ccb05117835447d72ce08c1d020ec": "", + "c46dc67b9717bb28c2a5a6279dcb4bf78042c5098b9784c77e7627ce6433a8e1": "", + "c4f277de8baf6a2718a91d9fd0100c6def50d6193a3900e3c87409599639a83d": "", + "c51a5e32f59750afeabd8dc7c86d2b17b5bc5aa197b43f065638f2263c56b848": "", + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470": "", + "c655dcc56a8b68fa1c7fffcc6ccec3f6a20e1d55b5a129d89488038c2a85e71f": "0000000000000000000000002182da748249a933bf737586b80212df19b8f829", + "c86655cceaaaf6b16ade4d1054d4e0515cdc2f5225b66d4a8a7386f4ea9c3356": "000000000000000000000000f571eb5abd7da99c6b32b3f3ed0740f6fac7d14b", + "c8b09b6f3384f2ffe0882b9e9717f3637dcae61628a910a73bfe2afd37b15b79": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "c980e59163ce244bb4bb6211f48c7b46f88a4f40943e84eb99bdc41e129bd293": "", + "ca1c89237bece40382b71cc333f0cf90b8d896352d5f336ce534d6875b926e2b": "", + "ca882a554480910ec59c6c0225ca5c4953ea5a3f0958dfdd7ebb428b41eca843": "", + "cbfc9f3ace1802ac45478ea2849968b5f2a6895f1c4beea8e29085ec84a2fe43": "", + "cd2548c4fa14cb15667cd5e5667dafbd0970d09185c619eb3348f5d7dbf131ba": "", + "cf9795aec23e1cac71a092c1659e21eba469f6c64f46e053ac73e6d73bb10787": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "d027c30f3f44c6104c075a1ead1a2e43e9f39198cabec1621f156d4979f19ae3": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "d212513106d90721dbbe3233b6ada0ba201f6c550bd2bcf953720edd84fb842a": "000000000000000000000000b7529ed60a10291754a635ed9fd67c1723f4d83b", + "d4ce672c13a9ee8002ea944e1ebbb620394139c1375bcdb869dcd1271b7c1f03": "", + "d7db60dff9ea1561a36e5abb52e777b0cbb91dee34d46b8a195d9127dbd0dc9f": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "da6b6ac6392a85bbf59fd1c3fb553087a1a3622a8d82a6b22979e0758dc2d0a9": "", + "da974c7fd18b8e48fcd0649bcaa1c3e338128570a18d3b84d5863ee513ebfc2a": "000000000000000000000000b957b0da344f6a17f0081d63be7345a860e5b7a2", + "da9978f0bc086d41a18d2b99f16c51583c2a38ee4c9346aa834dc50e66b4964d": "", + "daa77426c30c02a43d9fba4e841a6556c524d47030762eb14dc4af897e605d9b": "", + "dafb08ad2e8051263f565108f38cabb76abdca652cbe1b7f859cc22e76f2f85c": "", + "dc7ff32cae6cc2adfe49a8722c521a91d3671fad9169d792473e1560c50bf490": "", + "deb3b6b0bf693bec455d94b929bbce222afe810fe4acebe51ce7948ff4e8f8fd": "000000000000000000000000b957b0da344f6a17f0081d63be7345a860e5b7a2", + "dfcbe054725ea501056a95ff91530c2a83371e15ec9d05619f12c76baa92ee2f": "", + "e07be6bce4cd44b8bf547c4a0f9314e707f42b648525bf6c1cbb5f5689028f1e": "", + "e168b55b543959bfc9a1ba0d6f846406e9c5078c9f20fb49488e72c3781df761": "", + "e2b9f9f9430b05bfa9a3abd3bac9a181434d23a707ef1cde8bd25d30203538d8": "", + "e540257305ba7ed8f0852280a8bb5fa439642e2bbe5efb8396023190d1d4efac": "", + "e85a51ec6b78682038ace16f068a11f783fa49d1434b99ac9ac1ac5f80135227": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "e8e77626586f73b955364c7b4bbf0bb7f7685ebd40e852b164633a4acbd3244c": "", + "e8fb33650faf37535ebd07826e66bdb5c39fb2091055617df310736132d8743c": "", + "e91e6d5af38224d907e455df2217132cc0b9d492350d7c1fcaa48a7d37b4fa2b": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "ec70b555acbe1190ac243b838cadede0f852ce5a7275f8a056ce770e747a2e9c": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "ee5234bbc6b441348cec1b04f7a5aa6034da1dd290fcaf64ecec5733c7f83229": "000000000000000000000000d0277c8a3eccd462a313fc60161bac36b16e8699", + "ee5788e290a48125a7e6875b6150282e64895373632a4d53ae7a8fd1927d7364": "000000000000000000000000a0b29af6a56d6cfef6415cb195ccbe540e006d0a", + "f0d3d1ec19e32ff5b08e71a77244ecfe9b4a82eb41d6f83363322f02a40558d3": "", + "f39a869f62e75cf5f0bf914688a6b289caf2049435d8e68c5c5e6d05e44913f3": "", + "f3db34a47b8751945e9998223fcc0aae730454486da96a78626f4d750dd09502": "", + "f490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4": "", + "f548e71c32522ed78c2588df2cfdc3acd5c04cf930953ecabcc86ee3532f317c": "", + "f88b68a845e59b23d30cfebfb1f42f620d558b80c4f8fe260324b4ff4c364f4c": "", + "f98f8b01ec299350719315489babcb45e99398c8fbaf5c182da442ac83133f1a": "", + "f9df4273f77270a754f076a5d7a72b00bee4b9b9f012b4513637f0dfdda4ebf1": "", + "fd2420d8c819123439502172c23f6b5053814ccb95a80b4494c85a349192c735": "00000000000000000000000006642c4fd062a12b980d2bf28334e48ffe609248", + "fdda011f65897f249410dc9e51464058a1a5f1b48fced4325dd1d5b551a52890": "0000000000000000000000003f9ecb7b25fa567afb2a4c7b633749bda578b593", + "ff0435150397611e919e58bfcec8652d0856528bb4781903439ca1afa83f5293": "" + }, + { + "012893657d8eb2efad4de0a91bcd0e39ad9837745dec3ea923737ea803fc8e3d": "38723a2e5e8a17aa7950dc008209944e898f69a7bd10a23c839d341e935fd5ca", + "17bc5666b1ec85903b4657b6adaa1e0d32cce50dfa483c1c5948ebb3d8787268": "73f5062fb68ed2a1ec82ff8c73f9251bb9cf53a623bc93527e16bc5ae29dad74", + "405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": "9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2", + "43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d": "3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d111", + "4df2effad59eb919c30cf175fb15c66618dd52e6865b846c930752d44faf859d": "eceef81a484fea2cd17f305981f7b46d1eb583da375d9c499d90cdd63b650fbc", + "9ea7a819a0914e18e935cf832504011ef2ea4e0d3ee72af3c69d40e2066289af": "cb39b3bde22925b2f931111130c774761d8895e0e08437c9b396c1e97d10f34d", + "a9c584056064687e149968cbab758a3376d22aedc6a55823d1b3ecbee81b8fb9": "af9613760f72635fbdb44a5a0a63c39f12af30f950a6ee5c971be188e89c4051", + "ad4ac87fa8b6f7014b17f40a9d8c5ee373cf34535661d6375156c5ba3a04e3af": "7392925565d67be8e9620aacbcfaecd8cb6ec58d709d25da9eccf1d08a41ce35", + "b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5", + "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a": "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "da9978f0bc086d41a18d2b99f16c51583c2a38ee4c9346aa834dc50e66b4964d": "611ab7d0b1e0f74d9d8e9dad7daae35404c3c0c5d9e94839338562d708d8e9d0", + "fd6d486de5910c769ade60684c4e74e68a93a919b286607d7995398daf42204d": "3b745a1c00d035c334f358d007a430e4cf0ae63aa0556fb05529706de546464d" + }, + { + "012893657d8eb2efad4de0a91bcd0e39ad9837745dec3ea923737ea803fc8e3d": "0000000000000000000000004300a157335cb7c9fc9423e011d7dd51090d093f", + "17bc5666b1ec85903b4657b6adaa1e0d32cce50dfa483c1c5948ebb3d8787268": "00000000000000000000000014ef238cfa4075e9ede92f18b1566c1dd0b99aaa", + "43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d": "000000000000000000000000cd566972b5e50104011a92b59fa8e0b1234851ae", + "9ea7a819a0914e18e935cf832504011ef2ea4e0d3ee72af3c69d40e2066289af": "000000000000000000000000dbc100f916bfbc53535573d98cf0cbb3a5b36124", + "a1468185ed02fbc3b21223ec1c8c49605873fc9604653fa6ee049d60edc5ceb0": "000000000000000000000000c4053784867ac0165cbc1f7677386cae8489eae6", + "a9c584056064687e149968cbab758a3376d22aedc6a55823d1b3ecbee81b8fb9": "0000000000000000000000001cf4e77f5966e13e109703cd8a0df7ceda7f3dc3", + "ad4ac87fa8b6f7014b17f40a9d8c5ee373cf34535661d6375156c5ba3a04e3af": "000000000000000000000000316750573f9be26bc17727b47cacedbd0ab3e6ca", + "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a": "000000000000000000000000c81b94933420221a7ac004a90242d8b1d3e5070d", + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470": "0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31", + "da9978f0bc086d41a18d2b99f16c51583c2a38ee4c9346aa834dc50e66b4964d": "000000000000000000000000a2aa04ec13cbcdddd14a43575f1363ecb1cd90b7", + "fd6d486de5910c769ade60684c4e74e68a93a919b286607d7995398daf42204d": "0000000000000000000000007730b4642169b0f16752696da8da830a4b429c9d" + }, + null, + { + "010d1c26efabac677596f64e2e4f8894606e3636370a8665756ebc184e745aba": "000000000001", + "012893657d8eb2efad4de0a91bcd0e39ad9837745dec3ea923737ea803fc8e3d": "", + "033274602281965ae0382e28ea7584792e3d846b4ead2f1529e0d61a63afa9b9": "0000000000000000000000000000000000000000000000000000000000000000", + "034d54cdad5956fb28f9060287fad9073c1e87fb7c6d1709e00f362c9052aff7": "0000000000000000000000000000000000000000000000000000000000000001", + "03c85b4c0caf8657ff29b05743c33f9ffbb8df604c46cc86caa2f051e6a065a8": "0000000000000000000000000000000000000000000000000000000000000000", + "067b3e4d57e1fe2d23c71a95cdd86c8019a649e466d5fcf8e22cce66ceea36fc": "0000000000000000000000000000000000000000000000000000000000000001", + "08774b45b9263bbdd4f040b01c444d167f20686daf1d9dc0be2703ac5b79898f": "0000000000000000000000000000000000000000000000000000000000000001", + "0ea4f1fe8ab439ed65bf736c2d1e75244a52fec0e96cefadf09ea5d170956d52": "0e7de84a5bcf0e16fa56b80cbf55f39877229030e5a8af78a0a78e003cdb657b", + "0ff064739dbad34456d55c4dafd7d33b7e0e7c63b18a1252ef9fd8bc88867234": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009", + "10eab4762daae8abab287dd86a83326a78f5bbb8641f38a6792819576c94e35a": "0000000000000000000000000000000000000000000000000000000000000001", + "12292042f822da16c3db8dc1fc978be48218e0fb997cfff35857e16abba41300": "0000000000000000000000000000000000000000000000000000000000000001", + "12fc00c16a89e602782828a84667390d4a14bf74c1fd16dab784c7ebae45de06": "0000000000000000000000000000000000000000000000000000000000000000", + "130508100dd1f8b1c72b7eb16f82ee3b8a6f3bcbc8461c9f02c06f14ead89d75": "0000000000000000000000000000000000000000000000000000000000000000", + "1403e9d046887460408ff2c1956a064def64c4bb221b7bdff146b097b3a282c5": "0000000000000000000000000000000000000000000000000000000000000001", + "1669beee2b904266bc5a6eef210d6869ccea5c9a25e173d940428ccfbd6310c4": "0000", + "180fd71813c81062f2cdf852bc03fb8e8b8b98d21436001e255dc7141cb299d7": "0000000000000000000000000000000000000000000000000000000000000000", + "18c5b4c6cf9fccb97b1cf7f966b2ca8e951365e13eaf63ec93d3fd4ad87fadb5": "0000000000000000000000000000000000000000000000000000000000000000", + "18ca0a599a7bcdfd7e487cafca8ab1dfb6ef18074841fc3da95b73479eee3270": "0000000000000000000000000000000000000000000000000000000000000000", + "19a1b3731620b60c6decd10c1019cd9d6fca4fe6025d6b7307827ea994dc81f8": "", + "1a949941ca6b99c817a4e16cefe478308222535d19f1437ae2fdd892cb8ac789": "0000000000000000000000000000000000000000000000000000000000000001", + "1d885466c9ed74249248ad01d298eb4f509d9102a849d767f893da1e78799a9d": "0002", + "1e2d85db0c7c63bcc2054bf2d3caaf5d61920c77bb16f10572e6115458b0c352": "00", + "1e6d8ff8f706b4b423086b9c725a43e4aa6ce504b790612fb0e6f738cafa5b00": "0000000000000000000000000000000000000000000000000000000000000000", + "1ea137b55c9c2a68d4dd701fc31c5a11a2fcb3f9cc4c2fe6b2bf968d250ece35": "0000000000000000000000000000000000000000000000000000000000000000", + "1fe8359bcf1145edd7e23e4c32df953ea82d5db7a0d840ebe1d436f73bf93c5d": "0000000000000000000000000000000000000000000000000000000000000000", + "216ff577ab4b6adc22902060367bba5d514a67cb53b6171bc62569e58ce1a8ce": "0000000000000000000000000000000000000000000000000000000000000001", + "21915510d6f6b58738bc790d97df3881396743ef975eb2a4d7dd0cd4bc10bc4b": "0000000000000000000000000000000000000000000000000000000000000001", + "24137ff708807fbf454fa0f7c3b603cdcf414890396424962389c3f887be5c00": "", + "244fa8474b97c1fc5589e3372062373bc939e2c2c8d51733cb62dd1af06d93ae": "0000000000000000000000000000000000000000000000000000000000000000", + "251828ea0fa55eeff4920c784f29d02b3d462893b0a53b35da407951f670d4c3": "0000000000000000000000000000000000000000000000000000000000000000", + "251f23d45faa62fd4edee6c7ca9d0e522dd618b21ca79c0ececcf6b4ab1d418e": "0000000000000000000000000000000000000000000000000000000000000000", + "2559c03f8499faccfb5d86c5a9c6857b9882045939b54fcab26046debc586400": "0000000000000000000000000000000000000000000000000000000000000000", + "25612858eb4e5086b12e02d2fbb70b8b64bb55022fdd629ec789f2c84607688f": "0000000000000000000000000000000000000000000000000000000000000000", + "26d4791888c6a5a6dad93c613727e1025a5e629993ace97b6f60a168ba5b643b": "3e", + "274f35379f9c71d56060a980068aa27bbb6b0163485b566c98f23208d9afebe8": "0000000000000000000000000000000000000000000000000000000000000001", + "27611fee3bcae57830f4acede0e4ddc28d6b80307e4e3c24518ff8427870b1a2": "0000000000000000000000000000000000000000000000000000000000000000", + "2815ce44f31ea08706a5b434ba9241be790bb99a9a14f2abc58f44e4c7ed5258": "0000000000000000000000000000000000000000000000000000000000000001", + "2bbbf3147d86f35e028afe730dbe8a309c343a5af574d686b4de6f0299f44b62": "00", + "2e2b0152d440cb2300acb1a66f126dc6a55d48429cd4d1c65a6b08b1d70faa1a": "00", + "2e7668b70ebbbf0427b7206105b43be56ed44866084aef806b455c4302bb09ed": "0000000000000000000000000000000000000000000000000000000000000000", + "2ebcffbe9bfd10639c61895d63dc4adbea44b1ef949f81ec56b684a553ac3325": "0000000000000000000000000000000000000000000000000000000000000000", + "2fa614a47cc9c85b69679204e1ef9ac927b19471ded492b8ece1e8e67262fb51": "0000000000000000000000000000000000000000000000000000000000000000", + "31d7d7f3d30e2f6915813b0eae348106f9c36033685f734d666df55950721e09": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009", + "35de80ebb4a020482ef20b08e76ccf3047a069603f0f298ca69d20d652e8d84b": "00000000000000000000000001", + "39d0581989c293b89482bfa1e116cec4009a18aa00b89c5242b7fe5c3766ed7e": "0000000000000000000000000000000000000000000000000000000000000001", + "39e4706fe515d7364d5d89bca544e81f9ef187062620ac4e97b4c64e9dba668a": "0000000000000000000000000000000000000000000000000000000000000000", + "3b41faafc90d54978545a2f7f0a0fbc5710b148872dd6e1d6c2ec4c94fee3617": "0000000000000000000000000000000000000000000000000000000000000001", + "3b73107bd69d6198ed057833aac40d0dcdc99e568c5e4f2ff154688bbab5fb26": "000000000000000000000000000000000000000000000000000000000000000001", + "3bf09109c39d56015c8905aa26907c8f8c509e4a54ff4efee2f896a8b1176042": "0000000000000000000000000000000000000000000000000000000000000000", + "3cc1cc331ba2e9897c734d97dfb178fecedbc4cc90c706eee0c6059c94b36297": "0000", + "3d8f5d715374acba3f92a425b8bad30eae5f2f534a63c4cea5ad4401fe46ad75": "0000000000000000000000000000000000000000000000000000000000000000", + "4084709b90b82b198ec95c387a53f65e5492611a56a9bf34a46d7c5fa02907dd": "0000000000000000000000000000000000000000000000000000000000000001", + "418b0655db32fa5820ed237053dfe34869c9a1c39460ed8d58e6e87e5164f8ec": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "4262e4bfbfbc25391172acaa697e2b36c9aa60be165a81de92f9a6be0ed447ca": "0000000000000000000000000000000000000000000000000000000000000000", + "42c4e39cf1e2224199b3895508025d4cf89fc21154dd0ba0c9f86ebbe81667a1": "0000000000000000000000000000000000000000000000000000000000000000", + "42d09d5551133d4982c7c496aa710fdeb46c2974fa2ee405bd0cf2d8687f5eb4": "0000", + "46700b4d40ac5c35af2c22dda2787a91eb567b06c924a8fb8ae9a05b20c08c21": "", + "469eae86b1701336b3d583df4527d639b1cccca716608b728563a0eeeeeb55ba": "0000000000000000000000000000000000000000000000000000000000000001", + "4798efaf9795653086f314b2a745a3c677befc3a143f8e71f6961410234d4aa7": "0000000000000000000000000000000000000000000000000000000000000000", + "48cbcce9cddcfc87a9dfb28f8c07a498c6cae91c3577410009e009de8ae15426": "0000000000000000000000000000000000000000000000000000000000000001", + "48d102df204080cb58f6131e8de27892647da0958ab111e3b7604279fe7638d9": "0000000000000000000000000000000000000000000000000000000000000001", + "49daba1e38b9fdb769584f02a5cf0d5ccc52e1dcc5f1683c384e308cbda1aefb": "0000000000000000000000000000000000000000000000000000000000000000", + "4a4e7e22f228bbfeef1e2e652aeb39630a3fea4545ce98694e34b3a13cbf4d9c": "162ead82cadefaeaf6e9283248fdf2f2845f6396f6f17c4d5a39f820b6f6b5f9", + "4b1c0353029df7c0e24c97c1caa608b2447a736abd6ec92c6a6ad19c74af6764": "0000000000000000000000000000000000000000000000000000000000001c3b", + "4c1451f2f475e314e13ab026083f0e75042da3757331579bcc2acf982eb93e47": "0000000000000000000000000000000000000000000000000000000000000001", + "4d26511722a244d920d5b388b5008248c71b7232df5e2dad0c68731ecea7baca": "0000000000000000000000000000000000000000000000000000000000000000", + "4e895772ea04e2bebc4494c0f61d649af0ec15eb35e3d6fb23ccd43cec8fc477": "0000000000000000000000000000000000000000000000000000000000000001", + "4e9bc8aacd818468cd54729198300a542eaa7ed24d172b0fa62eaca18c80320f": "0000", + "50f0b7d9f0b0195307199ecc68ea12ec8b2855ebd3938241acea7eab945706a3": "", + "5627aa867eedac80321e8a99321c11d624a974907a00338d183e495737ad224b": "", + "56cd39d56e15e186eb742169736637742fe0129e3816caa42199e1d11444a087": "0000000000000000000000000000000000000000000000000000000000000001", + "57f24ba6197dd6bca4b92b2b069547c4d9715cb715b118fd06b6c506f3fe9a6f": "0000000000000000000000000000000000000000000000000000000000000001", + "58dca178acf545c5f569bf230c25f4b299df65d50427e5599c062de84ae8e117": "0000000000000000000000000000000000000000000000000000000000000000", + "59083a31c083633493c1f0fff98188fc553195939b97664ddf4f1f7372fdb9ed": "00", + "5913b435dbacbaf8a060c4901cb61a7aeea4f64e04bed5194a9cda0e3f7407b9": "0000000000000000000000000000000000000000000000000000000000000000", + "5ad3326c83fc81b119a19e072abec9b015d3230407d61fddeac53d8d622665d2": "0000000000000000000000000000000000000000000000000000000000000000", + "5daa348868b1c7f027498f63593dc226890161a6e9fc6a458299fb2d954354d2": "0000000000000000000000000000000000000000000000000000000000003e80", + "5ec71d7c8e69482d0e0118734635e881ff05f5a87604da2302f19e3ade457b42": "0000000000000000000000000000000000000000000000000000000000000000", + "5ef61126f34e679f7b6d859b4f20cb716481fe3e7003d0bcfb017694f6d28649": "0000000000000000000000000000000000000000000000000000000000000000", + "66b7f8ac5bd4017cc1ae82dc7a1a5334bcb127a1f64ebe4f1a7595196da10a58": "0000", + "67f7c6a923a7558c8cb23e8475dda653460be6ee507466645d79d5fa6dd5c63f": "01", + "68ad0981c9f951bdbcad78d21e35e5ec7918595b341c8b3dd81d5f50eca06b78": "0000000000000000000000000000000000000000000000000000000000000000", + "6b1061285efade3c0b2593286bb08db69ae28df9e1d6714041b063e362ba1988": "0000000000000000000000000000000000000000000000000000000000000000", + "6beafa77883efd2c221ea4cb29831d1fe10a2190379312217dbe57909ac356b0": "0000000000000000000000000000000000000000000000000000000000000001", + "6d835e80050760971242c410fa7ddaf8b268d3669e2db343fd61343cd87d80f4": "0000000000000000000000000000000000000000000000000000000000000000", + "6de36875921c76ab5434e64791cc62395d65f49eb21f9ddaa82aa8756b44ed3d": "000000000000000000000000000000000000000000000000000000000000866a", + "6edab1ef76af731a34f9a306bfdeeaefe48aa8f4826c329e1fdd702652e17927": "0000000000000000000000000000000000000000000000000000000000000000", + "6f64f08deaeee1f2aa90289b4aaafc4d76bf5d79a6f0aee01cce6f914d6523af": "0000000000000000000000000000000000000000000000000000000000009c00", + "7030a0dcea1e544f2f20cab453564c3f7343ea3c7949e30b35c9b562d2a6f532": "0000000000000000000000000000000000000000000000000000000000000001", + "72937ea411f48b90764786c97d4229d192cc6b1426fabdc86b59298816af97bc": "0000000000000000000000000000000000000000000000000000000000000000", + "73291d37d5bdc108723a04c171d113d6c323c46000569d0eaa319e295497a911": "0000000000000000000000000000000000000000000000000000000000000000", + "75137d2ac452fa56c54f3a84b6a5032cf7e9979578b76da3d8893684ffc3c0c7": "0000000000000000000000000000000000000000000000000000000000000000", + "75e5c2f08ba7f4f5196eeee2fa5d4585c1a7d13d94c8dd01d8db7c6664bf5dc0": "0000", + "7687fd0273528d2f1aa49723afefa95a867eaa5a6a898a75d8d1c1774f244cdb": "0000000000000000000000000000000000000000000000000000000000000000", + "77d6ede055e1bf3669db1b8e965fcced0a76864f364f6135e6cabe1037fe4809": "0000000000000000000000000000000000000000000000000000000000000000", + "7870eaca19c10f38ad151dabd337cbc8e2df484ac4801b07b0d80348b645931e": "0000000000000000000000000000000000000000000000000000000000000001", + "7bf0fbb8f1754a19c5efdf2dbdc4288c2d8728852734b30dc057d53beb59e5de": "0000000000000000000000000000000000000000000000000000000000000001", + "7d24c042d652db2f2d9e2e5d1eae97d19b44109420f11b6eadb6b90cb1ba50ea": "0000000000000000000000000000000000000000000000000000000000000001", + "7f2686134db3a520c34fdf758eba9a0d4f9c8945a3f06d1f4d7eb68b433be142": "0000000000000000000000000000000000000000000000000000000000000001", + "80de6c463032565ad835285aac5101f9748b93dde6ad45bb1136190bb8f5c253": "0000000000000000000000000000000000000000000000000000000000000000", + "8187355fc5e82694be920349dee28c7d4ec2a7bc15a85db4db530b13f34b4050": "0000000000000000000000000000000000000000000000000000000000000000", + "8191431cab44389a73030b5819d7af3bcdb3cb49e618810032cb1fd4e746bb41": "0000", + "8257bcfd8eb8eb906d8f3a0f3cb71577e6267f1a4af7f3fc611dc19dd96192bc": "0000000000000000000000000000000000000000000000000000000000000001", + "8507835cf8ffeccb9e5a2ef45b957ae5f463861884bcd279214fa36b2965619b": "0000000000000000000000000000000000000000000000000000000000001c3b", + "86d444d512bd04db648bc23e024132fbc2186aa73cda0bf0741114132324124b": "0000000000000000000000000000000000000000000000000000000000000000", + "87b97726f9d1d6e04d170320fc2d8b16a971ecaa1048ac38dabab51369bd4543": "0000000000000000000000000000000000000000000000000000000000000000", + "880480a0dbe4cddcdb5cea5a9d483524b2f6c4e7b492bfe236b8d15649d0673d": "00", + "88451def3af9b5d137d0082f973d90facb971643f4eabf3c201a634861facef4": "000000000000000000000000000000000000000000000000000000000000001b", + "8a068cd204782a5859890b4201f784e3ade964c45f373bc4e20f2f0c60c927f6": "0000000000000000000000000000000000000000000000000000000000000000", + "8ad16be55060aff4f690974f6b8c74de388599e798c8ff48261897a95729fb9f": "0000000000000000000000000000000000000000000000000000000000000000", + "8b4d99f7357e3cf1c7ad74cfce0c1bab1ab69920595b7bb2c20ed919aa03f77c": "0000000000000000000000000000000000000000000000000000000000000001", + "8bf994b1ef100d61c6b3857392be820ae7855cc194cfffa90d3b43d0a28b13b5": "3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab", + "8d69df480ceb95c657631fe973f8777f032a807fe36e698458813ae8ac5276e4": "0000000000000000000000000000000000000000000000000000000000000001", + "90ac1c964e1edcf937f9332f953f971919ef44a105ec663be0eb6707ef52de9b": "0002", + "91bbd8d35060a647704e6e8410263135b9df075665d0286495fba2ad2129d178": "0000000000000000000000000000000000000000000000000000000000000001", + "93d390c50ad9871ea4b3ec9de9c3f10646951691931e069e03c0de0675bc6b05": "00", + "96cf34086b42afae29477ebe8d6eeba6fef1da1690e0ea32d8c4947466324569": "0000000000000000000000000000000000000000000000000000000000000000", + "993d6040be7987f83bb56811395b7d76d577bd885b943d2755b44fda0b44cf50": "0000000000000000000000000000000000000000000000000000000000000000", + "996f9283a0477c8eaddbd50c4a9927c80b0281d3193538469f79ae95f8ec2f5e": "0000000000000000000000000000000000000000000000000000000000000001", + "9ab09ec74fdfe6a0f390d51b70f6b31a9b99287080d91395864c689ec8ef96e1": "0000000000000000000000000000000000000000000000000000000000000050", + "9c3a806764dc757a3c4f3e4ab27f2d645f13684a5d0f65b3e527fd144464d052": "0000000000000000000000000000000000000000000000000000000000000000", + "9ce2281a0a9ead36edc758647abc060766f200a5210d5b97a9b7d1752578c3ee": "0000000000000000000000000000000000000000000000000000000000008615", + "9e24cd89db1e412aa85e71e9ea955e00a1c22d66716bbd19fc92df1a122a71bf": "01", + "9e6a8ff68b83a4a01c2c344f507ab1c738cf5df1f6f846d47fea6f5d397b06e4": "000000000000000000000000000000000001", + "a05b578a2942544883921581b74d7bc5f44de59ae5d1a3cc21626658b5d9cf41": "0000000000000000000000000000000000000000000000000000000000000001", + "a4ddac19e1b86ed2a29ecc5ca2e2d840923f30380f5c2a732b746427b97c7970": "0000000000000000000000000000000000000000000000000000000000000001", + "a923d0e400cbbe1e0915c5a699cb8a51578ae87755f1aae7929289166ff23f33": "0000000000000000000000000000000000000000000000000000000000000001", + "ab76f1d5488b8542336a386818cf99412b7aa17c589d244c29f9ae9cb3901815": "0000000000000000000000000000000000000000000000000000000000000001", + "ada673786089f911b5dc7c5fc3405c206e6e7564e4dd4466b563d03e659e94a2": "0000000000000000000000000000000000000000000000000000000000000000", + "b07a3d24561ccfb56dd51bed4d640a0f00d5d86fe953d986846be0930c35157d": "0000000000000000000000000000000000000000000000000000000000000000", + "b0e9dd0b5749795680b0cc0db0167b85f1d2417acf9b44869d17a876a4f422ba": "02", + "b2f231521511b65fba5f194f65a93426b16df90c4ca4bbf0b51e2c3b02d59b2b": "0000000000000000000000000000000000000000000000000000000000000001", + "b5a34ff06af3b01441b6ee4ffac60feee6f0b63ed6be80a21c8aaf8b9e7f0b4d": "0000000000000000000000000000000000000000000000000000000000000000", + "b7c17933a8cb769998187b25ea82c3ac8dffcf3d1976a60b023b9d06c0cd9a4f": "0000000000000000000000000000000000000000000000000000000000000000", + "b97681ddced4ee8f4efffc5b58044de3100b2dc7c1f7f6b72161200f10b0604c": "0000000000000000000000000000000000000000000000000000000000000001", + "b9d52ce810f7c808324c717f1a5b612512a24a3227d311f508edec3c931344ad": "000000000000000000000000000000000000000000000000000000000000005f", + "bafcbd8a4bbc5837e3a637e432c4ee0a48e30a6b760efaaed699aed606b0c768": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "bc2ae76808e3de30404a4dd4221f3289cf20a272161d4f8c0c58c2e736706256": "3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab", + "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a": "", + "bc8a5df0db3fc6a076ea676a8dd5f6689777de551a235d75f77a520bd243208d": "0000000000000000000000000000000000000000000000000000000000000000", + "bd59618a09cdeb7538ce8cf97820ae2ab18102ac903c34c7de6d72c63c3d0f08": "00", + "bd66e927d01f078a67ba5c98539a6a2f79b7187457430237f7d406ff12558deb": "", + "be17aa6916c3d516ea45c2b8fc312f6bffc47f14325b7a9005786f878e1bb3ba": "0000000000000000000000000000000000000000000000000000000000000001", + "bf528ce5e535e2cf241dc944b153d5925ab2cdd488c386e326716b6a8ecf751a": "0000", + "c1ec6ef309c736331efc3000afc186d2021944309ee6b20a4bf3bc735b7aea75": "0000000000000000000000000000000000000000000000000000000000006801", + "c3e4a3530ca51ae69ee63be92701c84c6ebd820e1f89ca15548c94dbb851101e": "00000000000000000000000000000001", + "c4527e59efc328e49b6926353042b1758cc422461230653e83a433634155adcd": "0000000000000000000000000000000000000000000000000000000000000000", + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470": "", + "cba5ff6688618456c8228b8c2bfb4ed254ad8620b99ef3ed8fbcb5bc66feb478": "0000000000000000000000000000000000000000000000000000000000000000", + "cd223a9e187147d1712bdeed93889e2edad86091108b10bb97790428717dee31": "0000000000000000000000000000000000000000000000000000000000000000", + "ce9b2bf13532af4013c467e57479a71625bf1a7c8190393f29ffe8d3f3275aae": "0000000000000000000000000000000000000000000000000000000000000000", + "d09419104ce1c64b6a06bcf063e98c2c91ad9e1beaf98b21c9d4734b4a3c9956": "0000000000000000000000000000000000000000000000000000000000000000", + "d6c0c03ec1f713b63be3d39b4fa8ef082b3407adc29baf74669fd2a574c638ac": "01", + "d837f9dcf93155fe558c02c7a660edc0cd238a8b8f95ee6b68e4a5c6a41fc70a": "0000000000000000000000000000000000000000000000000000000000000001", + "d9e1670598e5304eaf7da7b328570d20fe98b6977064f5b922c361d5c75751b9": "", + "db5d4994d6dae845a6fd76e91ade4d3a35f270d86673ccc32405042c3c3d37ba": "0000000000000000000000000000000000000000000000000000000000000001", + "dbc6ddf9220c7ccfc94057fd3d25b712a0d7f51c3ff44e291458f2daf4ef2ec4": "0000000000000000000000000000000000000000000000000000000000000000", + "df244f503af99f62276115256c481d3cf0786d477553cf0bb25df1579dbc9ee3": "0000000000000000000000000000000000000000000000000000000000000001", + "dfab0a2d13154e415f4f999b6570efd185de14a2cf07a14eb543feef7542a5fa": "000000000000000000000001", + "e0aed3305cfbf6b99096f7ea895c0f2d721dea396d08c75c892152e757668eb8": "0000000000000000000000000000000000000000000000000000000000000001", + "e1223738398f40c909a2f63d7f617ea86f1c6b8bd82786ec6e3ff0a8729ee803": "0000000000000000000000000000000000000000000000000000000000000000", + "e1d19f16b8648afb5fd13c5bd437554c9d1bd61855b47cf4069d6068f27f90c5": "0000000000000000000000000000000000000000000000000000000000000001", + "e6f0c93cd48787b5c65c1df991ab038e7fd1512ae6fa680ca79051348e4bd2c5": "2b", + "e7e08425a2da0d12f7d6cdefc8722e15f577c8b7908924ef5a6f09dc8a8df381": "0000000000000000000000000000000000000000000000000000000000000001", + "e9321ede4409baf4d20ce11283a0267a934062cd546b6fb0097d755686ff0194": "0000000000000000000000000000000000000000000000000000000000000000", + "e99b55f3b486798837a08b10ad2cd917ab907b7c3d62ab7cc31f0d9aeb19c043": "0000000000000000000000000000000000000000000000000000000000000001", + "e9c48c3e8bcc466c06599e85e1209d23de86ec441fe5ec9b1042a6275f2c818c": "", + "ebd3e19945cff9b7462359bb882a8005d9d1d69d9f82db099f29508447ec7b59": "0000000000000000000000000000000000000000000000000000000000000000", + "ece1937784110ebc937ef343c108c6385a8b13b3e8d0617d30bb6bd95701f270": "01", + "efdc1fd8d4c7bc0df6a2dcd82e30e65d2964daf02b52c51067c3d2e525943f18": "", + "f0001b79c0ca5c8fa824f187c3e987fd066688f64c1763648df46d59bfcd7a32": "0000000000000000000000000000000000000000000000000000000000000000", + "f109ca1998eda403604fe597551159daf3bf1c60b6a9f28b02c66fea4594fa33": "0000000000000000000000000000000000000000000000000000000000000001", + "f206ef1f61673596e4abc05dca7be9148dbd34841d85584e8c41d75ecdf5a936": "0000000000000000000000000000000000000000000000000000000000000000", + "f344c28b47c6de556d35ec1e82c6ec3d06f1951d36aa1cd7351d4255e7f04a9c": "0000000000000000000000000000000000000000000000000000000000000001", + "f3f136516fd855c4cd4bd193c2bc38fab112196b023eb22510da3c6cc276eb72": "0000000000000000000000000000000000000000000000000000000000000000", + "f402d2cd2eaaede36f70e970a0e397dcf76e4488dd6304bcbc77f8ba8bc423d0": "", + "f6183b77357ae6ff58dc23d48b3f1d9e76098e6f884751ed03a261a0e7bab231": "0000000000000000000000000000000000000000000000000000000000000001", + "f77262efc56997fdcd4a91cc1449b01f93ebca8c758efcc1c85027e69cc6618b": "cd433bbd1fa6457602a79d957ee85a37e2496d0a", + "f9adfd03d4d3cf7e9245f9677b882459f0f0ea492b36ebbe34fe965bf3b4e05c": "000000000000000000000000000000000000000000000000000000000000002b", + "fa22beaea48d8a5e37b2f00efdc83600d4a9d1e1ff5a08cea987db6e6d168833": "0000000000000000000000000000000000000000000000000000000000000001", + "faccb2379850753cd96f3a4f37dd3f431863cab480cd1f808f696b0cafab5da4": "0000000000000000000000000000000000000000000000000000000000000000", + "fb859356d00b38d191345159ca428ce6b47c7c03000e91d93ba541f2db07ee75": "0000000000000000000000000000000000000000000000000000000000000000", + "fc08a758057657032bc36068292a2e3dfa490f21697d4e5841ce2bcbf50b12ba": "0000000000000000000000000000000000000000000000000000000000000000", + "fc94ce88596dbda4103ce1ee25fe0f05e0d8e1a57a2d8660d45800ef89ea2f64": "0000000000000000000000000000000000000000000000000000000000000000", + "fe0d647b508fe5dbc76db4136a295fcc960ec1990c7639bb8ddcd06c1761e9e5": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "012893657d8eb2efad4de0a91bcd0e39ad9837745dec3ea923737ea803fc8e3d": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "087853ba5e0cab850ae6242dde6d98ef48e6d88902ad81639bafa8a34d6f49b0": "059a381fec09e29448a58ae8905f41d1eb8ff0ed755aa0f827821aefde02ec7d269d2516bf8c4f5798cc1267162e59add561e5537a328fe0f28a252fa287a72a", + "089579a4ffcde57eb85cde7bde7a82070763b1f99942cce953cce0e2e9df83e3": null, + "0b4163cbc5404e24a3d2c9d78e8f289eadd9dbf93f4a5a823bfdd0d2fc9c1468": "1f4d1d80177b1377743d1901f70d7389be7f7a35a35bfd234a8aaee615b88c49018683193ae021a2f8920fed186cde5d9b1365116865281ccf884c1f28b1df8f", + "0ba4ab054e27484052c149d30ceb22514904ca1576715ab4144cdc33ab4f4fdf": null, + "1e990e27f0d7976bf2adbd60e20384da0125b76e2885a96aa707bcb054108b0d": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "1fe4b678a932ecc673c8da1eec72a4015be345e71eeffd5fa56ebf858521bad0": "255e468453d7636cc1563e43f7521755f95e6c56043c7321b4ae04e772945fb00225c5f1623620fd84bfbab2d861a9d1e570f7727c540f403085998ebaf407c4", + "2080ae5ce684e2b718fb2b3d44ff77943c095f21df08c8cb5095eb9dc74b9f66": "1fd3b816d9951dcb9aa9797d25e51a865987703ae83cd69c4658679f0350ae2b069610f239e3c41640045a90b6e1988d4ede443735aad701aa1a7fc644dc15a0", + "209b88501c3e213902ac4a0107d718a82fd1ab47afea7df282097e99614e5d42": "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba", + "2a61041edd2708655ab16256060cafcec93e715b457d1f118a16bc8ad0dbdc6c": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "3a709301f7eafe917c7a06e209b077a9f3942799fb24b913407674a4c1485893": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "4169dd4e123daf8687a2d5c3d192bfcd52fe5930697a65825ec8a4fd9de3db49": "1d78954c630b3895fbbfafac1294f2c0158879fdc70bfe18222890e7bfb66fba101c3346e98b136a7078aebd427dced763722d77e3d7985342e0bffcc6ea4d56", + "43e0f2c14b3a7e08fbe006fb3d772d75a1c40332c5e1be232a3d72a324bc0959": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "4b6a9063777e44ee27179dccf5599749e0baa322c4766b54201fdb8d41dd42a0": "2fa739d4cde056d8fd75427345cbb34159856e06a4ffad64159c4773f23fbf4b1eed5d5325c31fc89dd541a13d7f63b981fae8d4bf78a6b08a38a601fcfea97b", + "4ddf918eb9b12ae0cd9aeeac5f79a53dcf167038c1e155bdbe3d0204c3dfd24e": "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba", + "5446fe9042fa6576c541fc1f51dbfca0da0808a0e9f7a4f2271092bbfdf8113b": "2f588cffe99db877a4434b598ab28f81e0522910ea52b45f0adaa772b2d5d3521d701ec9e3fca50e84777f0f68caff5bff48cf6a6bd4428462ae9366cf0582b0", + "59a9b598fb1cbb4470c1c83c3c7919723927e32dcbfc499369618883f7716c8d": null, + "6100b59abaa8604b0a5d6951ec4baaf7b93496bea06ee940866fe486fa7b0baf": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "63dfd64b22e681f0cc0d54e30ce03421b4da05a2a8353d36c5df9c9dd40fd0e1": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "6512b6e482081b0b3ea65d88b8b428c62ff6b89e46f69186c1d58a754f93e541": "15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f", + "694596c3962bbb9a958855415014b10a87c287659db9abf4aabf5fe2010b1a97": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "6f5e8cbdf88b245fc2759de4436caa2738abc9917d104672bd7f709bf241ca4e": "0ccbec17235f5b9cc5e42f3df6364a76ecdd0101ddda8fc5dc0ba0b59c0e5628069ef5e376c0a1ea82f9dfc2e0001a7f385d655eef9a6f976c7a5d2c493ea3ad", + "6f8ce260b70482f55afd521252d239b61a0f04064cb4d071b1008aa3b85869ef": "1fd3b816d9951dcb9aa9797d25e51a865987703ae83cd69c4658679f0350ae2b29ce3d80a74ddc13784beb25ca9fbfd048a3265a32c6f38b92060c5093a0e7a7", + "7fadc430d0dec6b6e0f213585c75955d9ef7b7370ef129c286f057cd5178e000": "2f588cffe99db877a4434b598ab28f81e0522910ea52b45f0adaa772b2d5d35212f42fa8fd34fb1b33d8c6a718b6590198389b26fc9d8808d971f8b009777a97", + "818901c99b5392251e6a8d13b1a8a9ca180639b65d7e744706237c541757fd0b": "1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2860217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4", + "83563313efd2835227e5d96f709bc84c8f7609f0e03b8e5396f007229f8ddd41": null, + "8414e61c90e5e365475ec73cdb9e817ca321ac4f089c731e307e8ed4ae7dab13": null, + "94053252705d2109c767122b07092a83795f2e01592208eb24e06bec96a62cf5": null, + "9611dc1757b109073c8058e4e117a856676ba6868ee12dde989c8eb584d6c31c": "0769bf9ac56bea3ff40232bcb1b6bd159315d84715b8e679f2d355961915abf005acb4b400e90c0063006a39f478f3e865e306dd5cd56f356e2e8cd8fe7edae6", + "98fc7813abc874e5ede492594e5f9c17d2e4898531ff7ca5cb24abcdaa9343da": "1f4d1d80177b1377743d1901f70d7389be7f7a35a35bfd234a8aaee615b88c492eddcb59a6517e86bfbe35c9691479fffc6e0580000ca2706c983ff7afcb1db8", + "9f3654a7131bde2ca3892dc6a744102195844e30c3cd887d21bee2b478fc904a": null, + "9fa94947233ff18c33a7d71ea5e70bf427dbd099f535873033e71bbbd444ae8d": "0ccbec17235f5b9cc5e42f3df6364a76ecdd0101ddda8fc5dc0ba0b59c0e562829c5588f6a70fe3f355665f3a1813dde5f24053278d75af5cfa62eea8f3e599a", + "a446f380799bc37eda79425d0e5c0824597f999331811b6774ad5c35e49a0114": "113aeccecdaf57cd8c0aace591774949dcdaf892555fa86726fa7e679b89c0670bffba84127a19abde488a8251a9a3fce33b34a76f96aafb11ab4a6cef3e9979", + "a6ec34af2b0198fbeb64e50ac8b0f2da428489a054fc3732cb7c6c3c7f5f6c01": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + "a9479f519cbe0f8c355898abc7c22878253448b76f3cb6dc97c3ce334d1e8e59": "1f4d1d80177b1377743d1901f70d7389be7f7a35a35bfd234a8aaee615b88c49018683193ae021a2f8920fed186cde5d9b1365116865281ccf884c1f28b1df8f", + "ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "b033f51f4db914bf9d626769036ac44b44c1b724fd7b44fef43e335b73c1d270": "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba", + "b89869015f780e8a53577c7f6e2405031aaa7660517b94e1e074d8edf1f87d31": "1d78954c630b3895fbbfafac1294f2c0158879fdc70bfe18222890e7bfb66fba20481b2bf7a68cbf47d796f93f038986340f3d19849a3239f93fcc1a1192aff1", + "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "c86bb6b92c0c1c6be3ae712335b967f18e191d583ac7ad81ae7bbf62bf4188ce": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "cf77bc69c2c3bb37003db39ef18a918dd96c66332a8429c097ee2df63d913dff": null, + "d41981a62a65bc8d3ec7e86aeaadf0a5069f58c61705f64ead9d6a33f56f6b5b": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "d4f54b594db007f1fc6b71bdc64a6c9f1c2606781b50f067a5a61e9fc97d639d": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83", + "da9978f0bc086d41a18d2b99f16c51583c2a38ee4c9346aa834dc50e66b4964d": null, + "e59dd4bca360eab19889fd0a947eed0cd133f03d9e7607ee32ac00275583ac19": "000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45", + "e90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "ecdd2ab037bc00abba4fc8f792146c265c2fab8e61f473576390d2a1770073a7": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "ed1ce265dfecac5ea3c399a8fe98850a7783ac3dc659fc05227a531d6a021cf1": "113aeccecdaf57cd8c0aace591774949dcdaf892555fa86726fa7e679b89c067246493eeceb7867dda07bb342fd7b460b44635e9f8db1f922a7541a9e93e63ce", + "ed625fcc26177f39b4fc71b3ff53137a323292ec20deb963562edfbf464e30e9": "0769bf9ac56bea3ff40232bcb1b6bd159315d84715b8e679f2d355961915abf02ab799bee0489429554fdb7c8d086475319e63b40b9c5b57cdf1ff3dd9fe2261", + "f19ca958b80b85694d174bc382abb57982336924086e48c18fb2f4df89f56d0e": "1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2860217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4", + "fb407753c8e83acbc2864aaaf46fce7e9de416d8c7f9acfb23a2904960a0f778": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + "fd6606457d19fae43d0564a64332e8ef149d6831958e2af8162b1f7ad02c9542": "2fa739d4cde056d8fd75427345cbb34159856e06a4ffad64159c4773f23fbf4b1176f11fbb6e80611a7b04154401f4a4158681bca8f923dcb1e7e614db7e53cc", + "ffea936086ca95b2dd963e8ab813c77474fbb3653c54c5d8920323f7932161ab": null + }, + { + "0029fb025a294d850032d464d2d64ca320feac7242d52b76a2dcad5aef6b9074": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "012893657d8eb2efad4de0a91bcd0e39ad9837745dec3ea923737ea803fc8e3d": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "02538696193579f388ba022d22804a1404ec028970991c051088c527022ac9e8": "08e2142845db159bd105879a109fe7a6f254ed3ddae0e9cd8a2aeae05e5f647b0e5345847fdd0656d7af3479dfd8ffba497c0af3c59ebc1ed16cf9668ee8b2b5", + "04ca9ed1ab28cdd7c66fd06892abe6782dae89629b169696641822da6e5e38fd": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "053f3d9211b10914f2b89c599a756d65039019e769c52e0fd1b794dc5b7739b2": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "058c714e4d5a9e9939de6ec321a6b4076c9d3a53f8967b2d8b050a30fea97730": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", + "067c674da350d4cf2d99ad49e040d5c4676b37a4eaba81ddd871ad0e56d0d9a3": "03d64e49ebb3c56c99e0769c1833879c9b86ead23945e1e7477cbd057e961c500d6840b39f8c2fefe0eced3e7d210b830f50831e756f1cc9039af65dc292e6d0", + "08c5246e29bb21092d615664edcca7ac43502f639c6eeb3ca6b1303ae571db3e": null, + "0a10b8f8bd270b26371eecf64c6ce2fc516f0b0396f26a599c3f91be0aeba443": null, + "0dac7d7f3ba7feac84d47bed8b63231f6e0286ac4c8a3e0e630a2363f207c0ee": "255e468453d7636cc1563e43f7521755f95e6c56043c7321b4ae04e772945fb00225c5f1623620fd84bfbab2d861a9d1e570f7727c540f403085998ebaf407c4", + "0db604ab45b2d4fe2a1d9eec33fa159203e0dc9f7ad0bfd9fe934cf2c11f65dc": "000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45", + "0f682b3818529f9588fa7f9a9551e70b5e93f8e3c77ab93a763b7432e2877fcb": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0f7b6802eaa6e11662f31fce71ad891d2514d724f69e365fff2c910db0532582": "2c15ed1902e189486ab6b625aa982510aef6246b21a1e1bcea382da4d735e8ba02103e58cbd2fa8081763442ab46c26a9b8051e9b049c3948c8d7d0e139c5e3f", + "0fd10c27b65425e0e1197ffc9e8294dc9baf81a08c56be2152a9854e7e64c086": null, + "1c10b4ce4b4d5514c9ac638152d9ebe22318a39b9ac0d559aeb8bd1a386cf1d4": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", + "1dae2a9a66d8d6038e6817750576e21ecac9d54b76c456f5b6d69b15522c8b2f": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "1daf3e40d9d490b1eebef01961ded71d1cd3c851e2a733da5f8cf905b6e7bcdb": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "21453ecf7fd9f9f354b2f05d5ec3522ec9f2bd2b9b2093c3ebd9a7b057689105": "2f588cffe99db877a4434b598ab28f81e0522910ea52b45f0adaa772b2d5d35212f42fa8fd34fb1b33d8c6a718b6590198389b26fc9d8808d971f8b009777a97", + "21c182bf3a67519743a345c8710c8198773ff75f242737e4a31574ce4cafa43f": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "25709ff08e817e4d69c96350c24d3b65079a6416b07e8b7414e2a5a270a726a4": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "27eb17d6b599328c754b46de3dda054eab691847bc798d78bd16c74bffe0c925": null, + "28e74e3cb79a90cb50c547a88cc180925d72509a14443f959abd9bbeb267d2fa": null, + "2a0490880ca14797393b4cc6dff702ff4b7d1ea884217bf1c01bf61cf775e448": "1dbad7d39dbc56379f78fac1bca147dc8e66de1b9d183c7b167351bfe0aeab742cd757d51289cd8dbd0acf9e673ad67d0f0a89f912af47ed1be53664f5692575", + "2cfda879dcf534565d413e4bc65be1b6443383eb23288610914a2e85c33e162d": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "303fc8635e73bf76eef7e6f894ae3944df6c09f537c2b58e7d650a3547db691c": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "30e197a2ed4381e5653ef28e7968985813e2d94b72f311dc3bb0e2c37e8acfb8": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "35cdf44288e372dc3e23cba44f9bf2af11728a70e9b43457c8f7a2daac0c79ab": "2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11", + "3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff": null, + "37657cf6ac04258413bdfdad4c38f0b2ad315f9fc73a4673bf3156090d4985a6": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83", + "3a709301f7eafe917c7a06e209b077a9f3942799fb24b913407674a4c1485893": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "3b9586d9ce9b99c2d02536da14607842db8e6bca846cd0fbd2163f0729f7a57f": null, + "3c486c3e0c4d802400904d0087a2c7f09fba492619d7195d3d2e1a2ce061d906": "08e2142845db159bd105879a109fe7a6f254ed3ddae0e9cd8a2aeae05e5f647b221108ee615499d2e0a1113ca1a858a34e055f9da2d30e6e6ab392b049944a92", + "3cffec46bcb0028c6a8dabf90d8c94d0742bccf673b37daf50b5f2fefa5325f0": "1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b", + "3d10be7e19bb353ee63548ba1ac13a3ddaa5b776190922e066dfa54b2075bbd9": null, + "43e0f2c14b3a7e08fbe006fb3d772d75a1c40332c5e1be232a3d72a324bc0959": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "451815ff7eabba9d1077296930b8d2eef8474b8f6821faf8b08d425753442f2e": null, + "45b0fe00f364a1c64f22644b69b1a3acaa12860cce89fcd5c5818190e0ddccce": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451", + "46700b4d40ac5c35af2c22dda2787a91eb567b06c924a8fb8ae9a05b20c08c21": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "46edebb0955a1b0736928529445b915f400a46836693b7a4d29f8964d5f54896": null, + "489c8a9cebfada630e213007ccb8f47d05c192a32e495ad8e2c9f52f4984aa70": null, + "4aa74a2542ef5cba3ef290a9bf4a92ca6d5e59c7ed9cdfeb7a0bfb8e6a65e711": "13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36", + "4bdea052fc25a78b298c9578c906d6d19467c07088504e8f600687e266654c85": null, + "51e2d397029fb80fb918f374e62a247e0b0f0911fa38054e5be437dab97054ad": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "5309245443ea64938839abc0dcf3546927b25daa77e68726b086d2500875b2a6": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451", + "556a3c03566b04196c534f5612f50167917d72e6ab9b687e10e72dbe0e0f9279": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "57cd68ae4aacc9bacc38f018545889d3bfb788ee2f6d1602b98ba6a87bd69c53": "0ccbec17235f5b9cc5e42f3df6364a76ecdd0101ddda8fc5dc0ba0b59c0e562829c5588f6a70fe3f355665f3a1813dde5f24053278d75af5cfa62eea8f3e599a", + "59a9b598fb1cbb4470c1c83c3c7919723927e32dcbfc499369618883f7716c8d": null, + "5b164a05417e4774b9d16930536a24dab259131327bf3c08cb1e0397cc957502": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + "5b2ab17cba6c53a260973bb4e4e34a8dae1c10852aae4c99be6b28e6f4135ba9": "1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2860217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4", + "5cddef8a89d69efebe5b0cf235acdc23845d0b2b9fce36a4555aa746b06b2f10": null, + "5e993bee9fa8550de2393470ef41c461290fd3b6a0bd5b45335ca4d03208f9ee": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "5e9dc281ce55982d26320058f31ce9729dbc7eb9428b0426c17cbd5bd2683a88": "000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45", + "5fc4b734667abc00b7a3506badc3045b05715a094356db5d3b438cd994500b72": null, + "6453c887cfcdcd148a4a5c4300ca4037a594efa72d8f5fce5b8f34cb2d4637ab": null, + "665ad019e44487bdfaa2bce09e1c568df406114d03e35ef8eb189f1e5858ac3d": null, + "678f7e9c5b1135902f5d18a8254d83f556a0faf5ff1da5d19a4e819ed0dcc802": "1f4d1d80177b1377743d1901f70d7389be7f7a35a35bfd234a8aaee615b88c49018683193ae021a2f8920fed186cde5d9b1365116865281ccf884c1f28b1df8f", + "6b8a720dde0076627771561a266a8f85ff6ffc1a69fc876345912f9c87df5041": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "6ca42bc823ca8545a34266e11d95a05708c8b18aadb419ba7e76379ff0dceec5": null, + "6cf5dca6ca4ea8f2b986c0515e09c3b4eb4b4379a92dfefaa23e47b84531a733": null, + "6e0c627900b24bd432fe7b1f713f1b0744091a646a9fe4a65a18dfed21f2949c": "0769bf9ac56bea3ff40232bcb1b6bd159315d84715b8e679f2d355961915abf02ab799bee0489429554fdb7c8d086475319e63b40b9c5b57cdf1ff3dd9fe2261", + "6ea4b3555d9ed649a46eb7f0186eb8050be3c2c91ab25930578229e441f60aa3": null, + "70dc3e6a46e2cde4c3f7ee504130e8d0d92fef898e9de79ae7933f992b283e62": null, + "774fc34071b0a8bf409509d2e89df6d52770db9b49d9fbf0f912f16ac1b7ca7e": null, + "77bbf777c3172667bf6d26ffcd5d8ffa381ba3ac6c3845e3cbee3cd1999bd5ce": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "7906e07848bcd4fce33a66745e2ebc6f8232204d4612408ec82f78dc8ef89528": "2f588cffe99db877a4434b598ab28f81e0522910ea52b45f0adaa772b2d5d35212f42fa8fd34fb1b33d8c6a718b6590198389b26fc9d8808d971f8b009777a97", + "7ca924efc0694161c95cdefc7b665a34b6dfea5521071498c317109fa1f83d18": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "7e66ffa2afc0ec56465d8595595426d226b6af122c7e53f6c91d8473af8158be": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "8188cc60754d8af0651dc0a4e6540b49021a9ca352aac2b6b952c55075536dce": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "848fed49db7023cfb8e9b80465e2a90687303544b4b8d76c9b216ea1ef6488f8": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "849d080a9600f5889060d925734849d28f9a75ed695b7e7a95ec4f741d6da0d6": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "85abc1ede88e37fe9e8467ff2a8b16c70504ebfb165ab45d3bc7cdcf183f4c17": null, + "8a1a74fe494abe17daba9d26942daf6196d747d6bc52b0ae4a0d79e9b5fba81d": "1f4d1d80177b1377743d1901f70d7389be7f7a35a35bfd234a8aaee615b88c492eddcb59a6517e86bfbe35c9691479fffc6e0580000ca2706c983ff7afcb1db8", + "8b3165c1e8b0d9f7e843e277e0eaea0e3667bf135a13818dfd84d39806bdd376": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "8d5a589f63eb5b97aa05b53b2e64529e10298820205ab40196bd1d72b1bc0247": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "8db5e143a31c820e3ea0c08d690f03fd5d0442a8da1b4fe7d4e00f61bdd60335": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "9309cbcbb23fe4d31047c7d548000b159a2c464dcd7b17d8126222ad66f224e2": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "9fc428188049fd0fa72a1e1a8191082eb8a0466052e59e931fa17857a226603d": null, + "a123bcc05164c81bef25c915caa7df64e1e9def5cbc86582b99439ddaaffd9ae": null, + "a15bc60c955c405d20d9149c709e2460f1c2d9a497496a7f46004d1772c3054c": null, + "a555931c728f50406b843eecdaaa7a9e923dd188e106d1b147b917e97f1ddaf0": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "a7819cf665277e23c241e0c7c1fdec6106b5f841fdcd7ea3b1de8b2801fa9974": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "a8937aef5563fdf1d2871afb9f364e13efb42d4ace277bbd68be40629c0761cc": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "ac59ef256e50e52e22162a9e54cc49cc5245331cf529f2d5b6479ef30e9c77d9": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6", + "ad2a1988218a943189518e3baafef7bcda90fce3e60154075bc46802f33b1427": null, + "ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "afe1e714d2cd3ed5b0fa0a04ee95cd564b955ab8661c5665588758b48b66e263": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "b1a4e03e9a4f76ba8e6e7c2f205af4a34dff8f68c71b237ba3dcc438ec17b317": null, + "b427b100769d5222596f8a7c1b745d2cec4d0d583fce0796b539c7ff4cbbae37": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "b600f7004b9e43970a1846957ea322cf941537922388d8414c62d5629c899ddd": null, + "b6bd9a038d72ec0412abf486dd430137f2f593d08e7396907b54e37d7e528c02": "0769bf9ac56bea3ff40232bcb1b6bd159315d84715b8e679f2d355961915abf005acb4b400e90c0063006a39f478f3e865e306dd5cd56f356e2e8cd8fe7edae6", + "bac966e67df58e0b4c67757929a7d5fd4737d3609cfc6057c14c00ff6fb484f8": null, + "bb03b17d32fd2dd007abe32c004b5ad38f5a88060052c1593220a54e804b80d4": "000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45", + "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "bc6dcb9fb4f151eea79e0aa200dd04821cc7a3c55c04cc2f3b33692033938fbf": "2fa739d4cde056d8fd75427345cbb34159856e06a4ffad64159c4773f23fbf4b1eed5d5325c31fc89dd541a13d7f63b981fae8d4bf78a6b08a38a601fcfea97b", + "be18169fb07d71b4799477f51710506842ebc4f8947b6cacf10f1faaf0a9756b": "0ccbec17235f5b9cc5e42f3df6364a76ecdd0101ddda8fc5dc0ba0b59c0e5628069ef5e376c0a1ea82f9dfc2e0001a7f385d655eef9a6f976c7a5d2c493ea3ad", + "be6098f8087523d5b42b98e8c871b437c3f134bfb42f8bf9af5b139d73d74ef1": "2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11", + "bf528ce5e535e2cf241dc944b153d5925ab2cdd488c386e326716b6a8ecf751a": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + "c1134ccf004f7f11c1a6815eaba3a6572cec0fa837e8295d1996298c763cbad0": "1fd3b816d9951dcb9aa9797d25e51a865987703ae83cd69c4658679f0350ae2b069610f239e3c41640045a90b6e1988d4ede443735aad701aa1a7fc644dc15a0", + "c4e43c7ad315c386f53d3fb72b9fa18ba208fdf4f513e74793035116c33ab28a": "2f588cffe99db877a4434b598ab28f81e0522910ea52b45f0adaa772b2d5d3521d701ec9e3fca50e84777f0f68caff5bff48cf6a6bd4428462ae9366cf0582b0", + "c52fdf54073f8252d616136e7c3baab0db60fe1b1966a9dfbd44a858f519904c": null, + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "c67f3dbb9c6aa6988930824dcc90b208f71e9b93e606b001ee4d99f5f8f7c8f1": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "c803b730a6e3116b333938ae3b7fd7b248dcba98b31aa47e139888ec198fe6b7": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "cbfe4baa920060fc34aa65135b74b83fa81df36f6e21d90c8301c8810d2c89d9": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "cc5c9c0d192affb052b231bb723b5e8cbb2a4394a2752554593744063ee2326d": "1dbad7d39dbc56379f78fac1bca147dc8e66de1b9d183c7b167351bfe0aeab742cd757d51289cd8dbd0acf9e673ad67d0f0a89f912af47ed1be53664f5692575", + "cd65f545e45bb323a3a62159ab87c32e2c07be9c0dc545422943b7a72d2a814e": null, + "d0a30b63e7364b9a997d9d91bc1752f2136b872ebd0726a8fef883208d94144e": null, + "d15407cfe9992648c023fed365807007438478fc6dbd88f467f2448accca05b3": "2c15ed1902e189486ab6b625aa982510aef6246b21a1e1bcea382da4d735e8ba2e54101a155ea5a936da1173d63a95f2fc0118a7b82806f8af930f08c4e09f08", + "d499eabc9d44b6ed430fbbd909f6d2d4fd556304b8e3796834c078d54998c366": "1fd3b816d9951dcb9aa9797d25e51a865987703ae83cd69c4658679f0350ae2b29ce3d80a74ddc13784beb25ca9fbfd048a3265a32c6f38b92060c5093a0e7a7", + "d7bb278c9e616d23822caf15b26fd271f9ab8b8f0207e6053267518afc65baee": "13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36", + "d7f62b8c5399336828fd4d5a0620cdbaf207e616f11053406af6ca1b1b04609d": "1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b", + "da4f3012b62992b1b1fd8c8eabc19b0d516d879177d3bdc33644b5c17bfd50e9": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83", + "da9978f0bc086d41a18d2b99f16c51583c2a38ee4c9346aa834dc50e66b4964d": null, + "daa77426c30c02a43d9fba4e841a6556c524d47030762eb14dc4af897e605d9b": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "db579b30808cb2aa2bcee828f672341884413d2cecd9c836ac754965b99f67e4": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "db7faaa8166d502b98ae135bd9241263b5f40474a117706ddbe87a575448fcab": "1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b", + "dfc7054f7e556cdc2d4cbcede032e6e55d7f7f2f1e0d9cc5c2429cc32806b2ba": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "e3f7b4a842122149e1a3f1e969cb61d6e0e01750a40a7c8d7488dc25512293c5": "2fa739d4cde056d8fd75427345cbb34159856e06a4ffad64159c4773f23fbf4b1176f11fbb6e80611a7b04154401f4a4158681bca8f923dcb1e7e614db7e53cc", + "e4ec95a37af53bd0e28428aa169351d5b3daaa97c7cdc117b83aa948f3684e83": null, + "e5a3b3b10436c79bd4f0097b3cce534d6ade0be3d26072cefaff77db724d3b7e": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6", + "e5b7541fc4ab4e82445c6549e3b5fe580b0cd1c066cbdddee4afcf37153c5853": "13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36", + "e90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "ead59a785823331c690355fce6d486e5af45c04a3a44c3052defaaca4c30ea95": "03d64e49ebb3c56c99e0769c1833879c9b86ead23945e1e7477cbd057e961c500d6840b39f8c2fefe0eced3e7d210b830f50831e756f1cc9039af65dc292e6d0", + "ecc2cd90dd72f4f45f84575c0dc253f0e61c5db4635c4ef972b6f0555d65e0ac": "255e468453d7636cc1563e43f7521755f95e6c56043c7321b4ae04e772945fb00225c5f1623620fd84bfbab2d861a9d1e570f7727c540f403085998ebaf407c4", + "ee37af4cb72275b346592f512af478612dadcc3e927993ff125d9e9a3cb62d8a": null, + "ee6733774a983e1e6921ab7c09c04f466c1b9748b54b849bfc96cb3ac08bad53": null, + "f2b53097de121a0fb6352179e7de2078ad0d88f3150e0b564a8bed30b5bb12eb": "1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2860217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4", + "f947201a1362b943e410452f0c0014443d11ddba664d237cafe0d2a9f1413c9e": null, + "fa58fbc6150e7cec624278debd2b857592af7a4fcc66cc8d7fa82152c51cfd30": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "fd4e1783f7f6294d2ff12ac9015b97ab20feee1a465b28abd1701a3923b74381": null, + "fd5546c2496cb4df4b5e4bb86604ee8e8f36ad92844251227e89d9b07bb542ec": null, + "fdd792837fdc39009c8aa21f72e64fc95df92f3246b4385713f28c833383937f": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4" + }, + { + "006b0484c653b1be16a359057269baa24e343db52e44dce7c6cefeef149735f3": "0000000000000000000000000000000000000000000000000000000000000001", + "012893657d8eb2efad4de0a91bcd0e39ad9837745dec3ea923737ea803fc8e3d": null, + "0352781082b63358a3b608d0a3797a054de3f008afe2f66c0e9ef8e6c95f4fee": null, + "086b338f7e1848d3b4403b1c68ec8aca7a528ede6b8ec2fe224befd44be88fce": "0000000000000000000000000000000000000000000000000000000000000000", + "1c99829c90fc052bddb247280db7e125d01ea5fa3837be302bb4385faf04c21e": "0000000000000000000000000000000000000000000000000000000000000000", + "1d6f02e093f23931ba8ca6054ade0f38e275e444f0f4e27e3a0a1a78ccab2a09": null, + "2549e1c511f9844e1db34c08642177686d490c699474dc995b3ae263ae3b246d": null, + "2fe4971f59c3dedb114db9798d3bdd9141ff8396e083e72ac3ce6cfedcf4e0b0": "0000000000000000000000000000000000000000000000000000000000000001", + "34ab9af661244dbcf8f5579970f5052c7d3c210ce13b6ca1c11172c7863a10f0": "0000000000000000000000000000000000000000000000000000000000000001", + "40653f9463fc27af1ae2d102513f34a73d3b3b7ddcecdd5b610ff03edeaf72c9": "0000000000000000000000000000000000000000000000000000000000000000", + "47b9c702be76fe4a97bf77b482a6b6fdcf92a7625c6a8d66be63659ced591999": null, + "5101633c6b687ee8aee29d9618ac1397a30cd7a14ff339cb19608101ed74813c": "0000000000000000000000000000000000000000000000000000000000000001", + "58272cd6bf0816a2a7bcc15804d2e94efb1dc38505d3349b6372f0bbcf5e1a6c": "0000000000000000000000000000000000000000000000000000000000000001", + "5a815339f8a25c8e84000b0372b4cbb4dd70277eb1f53dba5f51a419673348be": "0000000000000000000000000000000000000000000000000000000000000000", + "5e8c3b1154f324f528a87fd8ee700753aa61df9ac087029cca81909985a16ccd": "0000000000000000000000000000000000000000000000000000000000000001", + "60774953ab2e5bbd1ec195cb7d76557b747f69d3fa18e4c3f0d30330ddb0b27e": null, + "722bf5c9235aae2151346ce1d19ef04b006aa7766268bf836377445092da5441": "0000000000000000000000000000000000000000000000000000000000000000", + "730792bc8e23a24142495d77d62d22713f03bd3171abbe79e41eed071b064347": "0000000000000000000000000000000000000000000000000000000000000000", + "74ca988ae7d6995f81f6c3a04c6f619c9567a95949d2f2e197bcf06fc1ca38e6": null, + "79b0f933a47d870f4605811e2bcb2ca804b5d0afbae398b2f1b8106b30afa6af": "0000000000000000000000000000000000000000000000000000000000000001", + "86400f22e06689a2968f0a4089bda8c60df97f463e7166b7b967c7e919edf0ff": "0000000000000000000000000000000000000000000000000000000000000001", + "86efd7f5227806a4fc5de316f59ff565242eeb4cffcb8023616ed52069762b86": null, + "8efdc5eb586e50d63299241d89edb4f3eda845e9200dec5bd1f9e309347b52e8": null, + "982485363eccb2a35b40cb7c5389901fe540e00bc4261bb3d856a9b49f11207f": "0000000000000000000000000000000000000000000000000000000000000001", + "9bb3e6d1c58fbd7a54ab877163f65f8d593038532266f669f965d93289ff5f21": null, + "9eb22b148582de60152b381545be446f8b394c876d1401d42cabd689b76472dd": null, + "a60b9fc20ee07592f3581aca8ac1f77e609a1b353b3a66a6f4c29f521e533b73": "0000000000000000000000000000000000000000000000000000000000000001", + "bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a": null, + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470": "0000000000000000000000000000000000000000000000000000000000000001", + "d0c775f8d408d1c6e863c2d529a7edfbe3df1737d86bb6b69edc7508ad4e4926": "0000000000000000000000000000000000000000000000000000000000000001", + "d3eb0c32becbfb2d9c6c15edf0d51f84daac9dda3ce2d6506e1d4573db29bb89": "0000000000000000000000000000000000000000000000000000000000000001", + "d41981a62a65bc8d3ec7e86aeaadf0a5069f58c61705f64ead9d6a33f56f6b5b": "0000000000000000000000000000000000000000000000000000000000000001", + "da9978f0bc086d41a18d2b99f16c51583c2a38ee4c9346aa834dc50e66b4964d": null, + "e45e2aa1bb354e722458c3425e59c37bb6a544397e5b4e8a5814ec97283dbfc7": null + }, + { + "0537dab8bcfa337395fdfbd203d054ac25c08722e9416a0ac259b779a2c87721": "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", + "13d12ef157bef72bdae72d1981ac6bc16ab74176742f7fb689ecef08d3d6bf0d": "d82c6a670dc90af9d7f77644eacbeddfed91b760c65c927871784abceaab3f813759733a1736254fb1cfc515dbfee467930955af56e27ee435f836fc3e65969f", + "2699f65d0bde17d17b834840e823616c33fb78e1a63f31fb6613bd1b08b888b4": "68790ca7594dd6fc28f0a86b7ddce0a225a8ea8fc2637f910eb71f6e54d9f8fa3e6302691015f11b15b755076d316823e6ce2ee4dd4aef60efc9189f6bd21bfd", + "30e40ece3441a7de9a9451e74fab98b455c4823f2485b2373a43a8b6c928a9fb": null, + "44b96fb380480dfeed4c297b46250c1ecc1a09e3e2fc2db0c1fb62fbe396eae4": "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735", + "47a0bef21f27e645f4fcee8531e8ee64c91472c3c49f6dc12ba19eca9ab49e05": "cf087b9b6ae026d358a13c577a04a4af4e65293be70b7cb2a7e00bd1317440af94b896bca7c282001aeb86cc307973096917897eadc97ed8eefb0d2b3c309a8b", + "5440bab497f09b1558b910e1f0df278ae9ac9fedc88daa3648115e004cddc8ce": "59c7c9896cdc9fda0a77bd41adba14bdd6cb47cbbd7c338482f5382d7be16ac44a2ddfe6833bf9a15737dd66469d2d0495d39a9cb3c8ed93152684d92a74f8bc", + "72834c36258c46436fcd43d43893fb32103ebd8827774c031a2e64decbe71d6a": "a2c1eb780a6e1249156fe0751e5d4687ea9357b0651c78df660ab004cb4773636298bbbc683e4a0261574b6d857a6a99e06b2eea50b16f86343d2625ff222b98", + "7b12d31724098d4879b481a4d462ebc685bda0f24252af010a62ccc6f4ffc60c": "bc5e888ed71b546da7b1506179bdd6c184a6410c40de33f9c3302074177978895dbe74144468aefe5c2afce693c62dbca99e5e076dd467fe90a41278b16d691e", + "7ded868868aebb7359c79ef488bed027b61633040eb7da66493e546245a4a662": "38dfb111db6c59c39c9bea26c8c872620d89dec22fd7da93c47d0708a3973f522858fd9c60fae53f366d7e2820040a8662b336de6d859764f20747acbb8999fe", + "87d33c8eabd067a14a94f02cb8ccfdb7ecff66aedbc0f0b13ae4ab0e06a5c4c7": "689419d2bf32b5a9901a2c733b9946727026a60d8773117eabb35f04a52cdcf1b8fb4473454cf03d46c36a10b3f784aae4dc80a24424960e66a8ad5a8c2bfb30", + "8dea8fe46ba1734457ae75ffdbb4ef76cc7dfccbb059a8eed9612f2369c2ea8f": "b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421", + "8ff18398e840c4041ffc0bcafac552cfb6c3440c67ce4075f3d370e227d14476": "7476f1f8e159b30b156b0e9fffbaee5badbb45abb488ea9cfa04f60d3a0964087535a649e438ba993f03cfc0d8d8676a792030a996b6a6fde5c29108b6bfb871", + "93e382390cb513261e11e03f772356de95ce13c4ff3d1d91e8db0bf8e10f516c": "afd469613835ad3c75a54cd3087160eb308f5d6cd2151f1490f51b182dc5d13016428bf21e474e2921023bbeec971429210a51f0b63741583b0153fe8f6c27b6", + "98e4e90f2de200ae941b184f513fe7cb2a07db782ef99db0552da0a88e6c08ce": "94e963dcaa85d33dad6c0043b6700f5e227a2d8bed804bd16970e64fa6f1e16307399239bcddf968612c8c9ba953d9b173575c31ef269c3a8721cb9bf1c02012", + "ac284f457255542cfce05626f14734707a56698403c663e598a9305ce509b665": "74097ae7b16ffd18c742aee5c55dc89d54b6f1a8a19e6139ccfb38afba56b6b02cc35c441c19c21194fefb6841e72202f7c9d05eb9c3cfd8f94c67aa77d473c1", + "af40afaebdf61faac67fca7412c81973e9b053a85195ebc80a6f10c6a4b5d233": "5d6ff04d5ebaee5687d634613ab21e9a7d36f782033c74f91d562669aaf9d592c86346cb2df390243a952834306b389e656876a67934e2c023bce4918a016d4e", + "b7c8e0e46ba3b6a9b345fd795b9e328c51f3eb535bc9d775517a965af6b72521": "f3e89a60ec4b0b1854744984e421d22b82f181bd4601fb9b1726b2662da61c29dff09e75814acb2639fd79e56616e55fc135f8476f0302b3dc8d44e082eb83a8", + "bed4c5ce99729a220c87ca0ef21acbbe1274b29855df4cccba2510fd58ae1353": "a65aadbf393aad57c4b06d6471134c5c01002c23dfe8290e115e024e05bc1bf1084d1651de54a83902ed582cb8f2ba381c69687cceaecea0cd8fe5529f86686e", + "de7f79eb16d7357b75271fd4aa93af1237cbdd2297894cdec0033c1efb33ab2a": "bc112be5618b20d24be64c9e1c6efd63fea38cc79d53692fad6568b16e953eb6128c1ec8ffaf9a2d69e3cb043d6e11e1c7afd48573311052b6e7ec0960371186", + "ded8b44cbafe26629d64d2019a702d6eea0d6bfe68e313beacfa7935a9433640": "7df6f69476a03ae29e944814846460b058d1762fffe77f938ea723d1033de0d5bb1f8234bd73afaf955622fa2cdde95594577a8d53191908eb69b316a53c985b", + "eea1b2d664c19b902ea74b63cc5166346e9ce4de1de41dd5b72dbc75709871a1": "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b", + "f352cd3242546c7cb1ee7c4dbf7c4cba948d505150b17fae38bff05efb7018fb": "a8ef8236e5f48a74af375df15681d128457891c1cc4706f30747b2d40300b2f49d19f80fbd0945fd87736e1fc1ff10a80fd85a7aa5125154f3aaa3789ddff673", + "f6f043c5d533a3310a6ccbc5ec11199f7038a750a570ff5be9e715eb3614c0b1": "6d2ce9e534d50e18ff866ae92d70cceba79bbcd14c63819fe48752c8aca87a4bb7dcc230d22a4047f0486cfcfb50a17b24b2899eb8fca370f22240adb5170189", + "fb59d1e38c2473ebc92cd9d9bded35e13a214ab589f11fb07ffc0703784eb33d": "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b" + } +] From 0f43598827ddb54cb37ac2ac86e264a6a3c4a88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Aug 2022 07:56:54 +0200 Subject: [PATCH 09/72] ci: Enable precompiles stub for state tests --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 8be835818e..e279efd018 100644 --- a/circle.yml +++ b/circle.yml @@ -355,7 +355,7 @@ jobs: name: "State tests" working_directory: ~/build # TODO: Some state tests are expected to fail because precompiles are not implemented. - command: bin/evmone-statetest ~/tests/GeneralStateTests ~/tests/LegacyTests/Constantinople/GeneralStateTests || true + command: EVMONE_PRECOMPILES_STUB=~/project/test/state/precompiles_stub.json bin/evmone-statetest ~/tests/GeneralStateTests ~/tests/LegacyTests/Constantinople/GeneralStateTests - collect_coverage_gcc - upload_coverage: flags: statetests From 9d4697fb47ac4f9a3016d5c97a3ce6e8949553ec Mon Sep 17 00:00:00 2001 From: rodiazet Date: Fri, 16 Dec 2022 23:20:47 +0100 Subject: [PATCH 10/72] ci: Windows build via CircleCI (#539) --- circle.yml | 55 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/circle.yml b/circle.yml index e279efd018..d075e2c231 100644 --- a/circle.yml +++ b/circle.yml @@ -1,4 +1,6 @@ version: 2.1 +orbs: + win: circleci/windows@5.0 executors: lint: @@ -76,6 +78,12 @@ commands: command: | curl -L https://github.com/Kitware/CMake/releases/download/v<>/cmake-<>-linux-x86_64.tar.gz | sudo tar -xz --strip=1 + checkout_submodules: + steps: + - run: + name: "Update submodules" + command: git submodule update --init --recursive + build_silkworm: parameters: branch: @@ -145,9 +153,7 @@ commands: description: "Build" steps: - checkout - - run: - name: "Update submodules" - command: git submodule update --init --recursive + - checkout_submodules - run: name: "Environment" command: | @@ -195,6 +201,7 @@ commands: steps: - run: name: "Test" + shell: bash working_directory: ~/build command: ctest -R ${TESTS_FILTER:-'.*'} --schedule-random --output-on-failure --parallel $CMAKE_BUILD_PARALLEL_LEVEL --output-junit ~/test_results/evmone.xml - store_test_results: @@ -241,8 +248,9 @@ commands: steps: - run: name: "Build Package" + shell: bash working_directory: ~/package - command: cmake --build ~/build --target package && mv ~/build/evmone*.tar.gz* . + command: cmake --build ~/build --target package && mv ~/build/evmone-*.* . - store_artifacts: path: ~/package destination: package @@ -286,6 +294,38 @@ jobs: - test - package + release-windows: + executor: win/server-2022 + environment: + CMAKE_BUILD_TYPE: Release + CMAKE_BUILD_PARALLEL_LEVEL: 4 + steps: + - checkout + - checkout_submodules + - run: + name: "Setup environment (bash)" + shell: bash + command: | + echo 'export PATH=$PATH:"/c/Program Files/Microsoft Visual Studio/2022/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin"' >> $BASH_ENV + - run: + name: 'Configure' + shell: powershell + command: | + $ErrorActionPreference = "Stop" + & 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\Launch-VsDevShell.ps1' -Arch amd64 + which cmake + cmake -S . -B ~/build -G Ninja -DCMAKE_INSTALL_PREFIX=C:\install -DEVMONE_TESTING=ON + - run: + name: 'Build' + shell: powershell + command: | + $ErrorActionPreference = "Stop" + & 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\Launch-VsDevShell.ps1' -Arch amd64 + cmake --build ~/build + - test + - package + + release-macos: executor: macos environment: @@ -505,15 +545,18 @@ workflows: filters: tags: only: /.*/ + - release-windows: + filters: + tags: + only: /.*/ - release-macos: filters: - branches: - ignore: /.*/ tags: only: /.*/ - deploy: requires: - release-linux + - release-windows - release-macos filters: branches: From 5be5834ae05a4f255f0e69d44a515ecd8632cc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Dec 2022 23:32:15 +0100 Subject: [PATCH 11/72] cmake: Upgrade dependencies (#540) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Hunter 0.24.5 → 0.24.11 - intx 0.8.0 → 0.9.0 (performance improvements for GCC) - GTest 1.11.0 → 1.12.1 --- CMakeLists.txt | 2 +- cmake/Hunter/init.cmake | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f816e04e12..a009a11a5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # Copyright 2019 The evmone Authors. # SPDX-License-Identifier: Apache-2.0 -cmake_minimum_required(VERSION 3.16...3.23) +cmake_minimum_required(VERSION 3.16...3.24) if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/evmc/.git) message(FATAL_ERROR "Git submodules not initialized, execute:\n git submodule update --init") diff --git a/cmake/Hunter/init.cmake b/cmake/Hunter/init.cmake index 64e4e127c8..d130a40e4a 100644 --- a/cmake/Hunter/init.cmake +++ b/cmake/Hunter/init.cmake @@ -7,7 +7,7 @@ set(HUNTER_CONFIGURATION_TYPES Release CACHE STRING "Build type of Hunter packag include(HunterGate) HunterGate( - URL "https://github.com/cpp-pm/hunter/archive/v0.24.5.tar.gz" - SHA1 "d7279c19372938dbb14c6ed511bdcb6e938ac5df" + URL "https://github.com/cpp-pm/hunter/archive/v0.24.11.tar.gz" + SHA1 "e49fb20a135675e406e95fbe9a591a630ccbbeaf" LOCAL ) From 342bc4ccc3eb5873b83a9fc592b3ca4b0bb1c318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sun, 9 Oct 2022 22:09:53 +0200 Subject: [PATCH 12/72] statetest: Support EOF/Shanghai testing (hack) --- test/statetest/statetest_loader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/statetest/statetest_loader.cpp b/test/statetest/statetest_loader.cpp index c5168b9355..e66c4b07c7 100644 --- a/test/statetest/statetest_loader.cpp +++ b/test/statetest/statetest_loader.cpp @@ -108,6 +108,8 @@ evmc_revision to_rev(std::string_view s) return EVMC_LONDON; if (s == "Merge") return EVMC_PARIS; + if (s == "London+3540+3670") + return EVMC_SHANGHAI; throw std::invalid_argument{"unknown revision: " + std::string{s}}; } } // namespace From 12de80bdf7644efe7a6eeeb83c00b228f6b8e608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 2 Nov 2022 17:12:39 +0100 Subject: [PATCH 13/72] tracing: Dump call input --- lib/evmone/tracing.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/evmone/tracing.cpp b/lib/evmone/tracing.cpp index d3762af7a9..018f18f200 100644 --- a/lib/evmone/tracing.cpp +++ b/lib/evmone/tracing.cpp @@ -102,6 +102,7 @@ class InstructionTracer : public Tracer m_out << R"("depth":)" << msg.depth; m_out << R"(,"rev":")" << rev << '"'; m_out << R"(,"static":)" << (((msg.flags & EVMC_STATIC) != 0) ? "true" : "false"); + m_out << R"(,"input":")" << evmc::hex({msg.input_data, msg.input_size}) << '"'; m_out << "}\n"; } From 8c43313ac5e45f47b448549fa3b9b3600e17942a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 2 Nov 2022 15:07:56 +0100 Subject: [PATCH 14/72] eof: Validate initcode and already deployed code --- lib/evmone/baseline.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/evmone/baseline.cpp b/lib/evmone/baseline.cpp index 822822f1d4..fd33d50dbe 100644 --- a/lib/evmone/baseline.cpp +++ b/lib/evmone/baseline.cpp @@ -356,6 +356,26 @@ evmc_result execute(const VM& vm, ExecutionState& state, const CodeAnalysis& ana evmc_result execute(evmc_vm* c_vm, const evmc_host_interface* host, evmc_host_context* ctx, evmc_revision rev, const evmc_message* msg, const uint8_t* code, size_t code_size) noexcept { + if (rev >= EVMC_SHANGHAI && is_eof_code({code, code_size})) + { + // TODO(EOF): The initcode must be validated. Doing this just before execution is + // good because validation can be combined with analysis/loading. But consider also + // other places like create instructions. + if (validate_eof(rev, {code, code_size}) != EOFValidationError::success) + { + if ((msg->kind == EVMC_CREATE || msg->kind == EVMC_CREATE2)) + { + // TODO(EOF): Should this be light error (gas is returned)? + return evmc::Result{EVMC_CONTRACT_VALIDATION_FAILURE, msg->gas}.release_raw(); + } + else + { + // TODO(EOF): This should never happen but protects against invalid tests for now. + return evmc::Result{EVMC_INTERNAL_ERROR}.release_raw(); + } + } + } + auto vm = static_cast(c_vm); const auto jumpdest_map = analyze(rev, {code, code_size}); auto state = From a0ea267fed4455a53bb822b496048a1478df1f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 2 Nov 2022 18:05:49 +0100 Subject: [PATCH 15/72] eof: Validate to-be-deployed EOF code --- test/state/host.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/state/host.cpp b/test/state/host.cpp index 0387295865..3803e08e7d 100644 --- a/test/state/host.cpp +++ b/test/state/host.cpp @@ -5,6 +5,7 @@ #include "host.hpp" #include "precompiles.hpp" #include "rlp.hpp" +#include namespace evmone::state { @@ -219,8 +220,12 @@ evmc::Result Host::create(const evmc_message& msg) noexcept evmc::Result{EVMC_FAILURE}; } - // Reject EF code. - if (m_rev >= EVMC_LONDON && !code.empty() && code[0] == 0xEF) + if (m_rev >= EVMC_SHANGHAI && is_eof_code(code)) + { + if (validate_eof(m_rev, code) != EOFValidationError::success) + return evmc::Result{EVMC_CONTRACT_VALIDATION_FAILURE}; + } + else if (m_rev >= EVMC_LONDON && !code.empty() && code[0] == 0xEF) // Reject EF code. return evmc::Result{EVMC_CONTRACT_VALIDATION_FAILURE}; // TODO: The new_acc pointer is invalid because of the state revert implementation, From 233d5c4a354454a8b0acc1240b9ff288bceabf03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sun, 4 Dec 2022 22:56:32 +0100 Subject: [PATCH 16/72] Revert "tracing: Dump call input" This reverts commit 0441591f03d31156865930e4519de43c6eb711a5. --- lib/evmone/tracing.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/evmone/tracing.cpp b/lib/evmone/tracing.cpp index 018f18f200..d3762af7a9 100644 --- a/lib/evmone/tracing.cpp +++ b/lib/evmone/tracing.cpp @@ -102,7 +102,6 @@ class InstructionTracer : public Tracer m_out << R"("depth":)" << msg.depth; m_out << R"(,"rev":")" << rev << '"'; m_out << R"(,"static":)" << (((msg.flags & EVMC_STATIC) != 0) ? "true" : "false"); - m_out << R"(,"input":")" << evmc::hex({msg.input_data, msg.input_size}) << '"'; m_out << "}\n"; } From 95a69d5f98929bc508849371b9ee2ebc68e26243 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 6 Dec 2022 15:04:49 +0100 Subject: [PATCH 17/72] Implement RJUMP and RJUMPI in Baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Bylica --- lib/evmone/advanced_instructions.cpp | 4 +++- lib/evmone/instructions.hpp | 15 +++++++++++++++ lib/evmone/instructions_opcodes.hpp | 2 ++ lib/evmone/instructions_traits.hpp | 4 ++++ lib/evmone/instructions_xmacro.hpp | 4 ++-- test/unittests/eof_validation_test.cpp | 5 ++++- test/unittests/instructions_test.cpp | 14 ++++++++++++++ 7 files changed, 44 insertions(+), 4 deletions(-) diff --git a/lib/evmone/advanced_instructions.cpp b/lib/evmone/advanced_instructions.cpp index b484912f2d..8c86499c16 100644 --- a/lib/evmone/advanced_instructions.cpp +++ b/lib/evmone/advanced_instructions.cpp @@ -216,7 +216,6 @@ const Instruction* op_undefined(const Instruction*, AdvancedExecutionState& stat return state.exit(EVMC_UNDEFINED_INSTRUCTION); } - constexpr std::array instruction_implementations = []() noexcept { std::array table{}; @@ -245,6 +244,9 @@ constexpr std::array instruction_implementations = []( table[OP_CREATE2] = op_create; table[OP_STATICCALL] = op_call; + table[OP_RJUMP] = op_undefined; + table[OP_RJUMPI] = op_undefined; + table[OP_DUPN] = op_undefined; table[OP_SWAPN] = op_undefined; diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index e525387d83..ccc6f13e9b 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -701,6 +701,21 @@ inline code_iterator jumpi(StackTop stack, ExecutionState& state, code_iterator return cond ? jump_impl(state, dst) : pos + 1; } +inline code_iterator rjump(StackTop /*stack*/, ExecutionState& /*state*/, code_iterator pc) noexcept +{ + // Reading next 2 bytes is guaranteed to be safe by deploy-time validation. + const auto offset_hi = pc[1]; + const auto offset_lo = pc[2]; + const auto offset = static_cast((offset_hi << 8) + offset_lo); + return pc + 3 + offset; // PC_post_rjump + offset +} + +inline code_iterator rjumpi(StackTop stack, ExecutionState& state, code_iterator pc) noexcept +{ + const auto cond = stack.pop(); + return cond ? rjump(stack, state, pc) : pc + 3; +} + inline code_iterator pc(StackTop stack, ExecutionState& state, code_iterator pos) noexcept { stack.push(static_cast(pos - state.analysis.baseline->executable_code.data())); diff --git a/lib/evmone/instructions_opcodes.hpp b/lib/evmone/instructions_opcodes.hpp index fdeb97e843..1c0bc1014b 100644 --- a/lib/evmone/instructions_opcodes.hpp +++ b/lib/evmone/instructions_opcodes.hpp @@ -82,6 +82,8 @@ enum Opcode : uint8_t OP_MSIZE = 0x59, OP_GAS = 0x5a, OP_JUMPDEST = 0x5b, + OP_RJUMP = 0x5c, + OP_RJUMPI = 0x5d, OP_PUSH0 = 0x5f, OP_PUSH1 = 0x60, diff --git a/lib/evmone/instructions_traits.hpp b/lib/evmone/instructions_traits.hpp index ccea01b2fb..e9783caf8e 100644 --- a/lib/evmone/instructions_traits.hpp +++ b/lib/evmone/instructions_traits.hpp @@ -162,6 +162,8 @@ constexpr inline GasCostTable gas_costs = []() noexcept { table[EVMC_SHANGHAI] = table[EVMC_PARIS]; table[EVMC_SHANGHAI][OP_PUSH0] = 2; + table[EVMC_SHANGHAI][OP_RJUMP] = 2; + table[EVMC_SHANGHAI][OP_RJUMPI] = 4; table[EVMC_CANCUN] = table[EVMC_SHANGHAI]; table[EVMC_CANCUN][OP_DUPN] = 3; @@ -286,6 +288,8 @@ constexpr inline std::array traits = []() noexcept { table[OP_MSIZE] = {"MSIZE", 0, false, 0, 1, EVMC_FRONTIER}; table[OP_GAS] = {"GAS", 0, false, 0, 1, EVMC_FRONTIER}; table[OP_JUMPDEST] = {"JUMPDEST", 0, false, 0, 0, EVMC_FRONTIER}; + table[OP_RJUMP] = {"RJUMP", 2, false, 0, 0, EVMC_SHANGHAI}; + table[OP_RJUMPI] = {"RJUMPI", 2, false, 1, -1, EVMC_SHANGHAI}; table[OP_PUSH0] = {"PUSH0", 0, false, 0, 1, EVMC_SHANGHAI}; diff --git a/lib/evmone/instructions_xmacro.hpp b/lib/evmone/instructions_xmacro.hpp index d69b5c13f5..7591211b5e 100644 --- a/lib/evmone/instructions_xmacro.hpp +++ b/lib/evmone/instructions_xmacro.hpp @@ -129,8 +129,8 @@ ON_OPCODE_IDENTIFIER(OP_MSIZE, msize) \ ON_OPCODE_IDENTIFIER(OP_GAS, gas) \ ON_OPCODE_IDENTIFIER(OP_JUMPDEST, jumpdest) \ - ON_OPCODE_UNDEFINED(0x5c) \ - ON_OPCODE_UNDEFINED(0x5d) \ + ON_OPCODE_IDENTIFIER(OP_RJUMP, rjump) \ + ON_OPCODE_IDENTIFIER(OP_RJUMPI, rjumpi) \ ON_OPCODE_UNDEFINED(0x5e) \ ON_OPCODE_IDENTIFIER(OP_PUSH0, push0) \ \ diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 54925bef1e..5a6195b281 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -168,9 +168,12 @@ TEST(eof_validation, EOF1_undefined_opcodes) for (uint16_t opcode = 0; opcode <= 0xff; ++opcode) { - // PUSH* require immediate argument to be valid, checked in a separate test + // Skip opcodes requiring immediate arguments. + // They're all valid in Shanghai and checked in other tests below. if (opcode >= OP_PUSH1 && opcode <= OP_PUSH32) continue; + if (opcode == OP_RJUMP || opcode == OP_RJUMPI) + continue; cont[cont.size() - 2] = static_cast(opcode); diff --git a/test/unittests/instructions_test.cpp b/test/unittests/instructions_test.cpp index e86550724b..7c257e0c68 100644 --- a/test/unittests/instructions_test.cpp +++ b/test/unittests/instructions_test.cpp @@ -55,6 +55,8 @@ constexpr void validate_traits_of() noexcept // immediate_size if constexpr (Op >= OP_PUSH1 && Op <= OP_PUSH32) static_assert(tr.immediate_size == Op - OP_PUSH1 + 1); + else if constexpr (Op == OP_RJUMP || Op == OP_RJUMPI) + static_assert(tr.immediate_size == 2); else if constexpr (Op == OP_DUPN || Op == OP_SWAPN) static_assert(tr.immediate_size == 1); else @@ -103,6 +105,10 @@ TEST(instructions, compare_with_evmc_instruction_tables) for (size_t i = 0; i < evmone_tbl.size(); ++i) { + // TODO pending update in EVMC + if (r >= EVMC_SHANGHAI && (i == OP_RJUMP || i == OP_RJUMPI)) + continue; + // Skip DUPN and SWAPN for Cancun. 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)) @@ -136,6 +142,10 @@ TEST(instructions, compare_undefined_instructions) for (size_t i = 0; i < instr_tbl.size(); ++i) { + // TODO pending update in EVMC + if (r >= EVMC_SHANGHAI && (i == OP_RJUMP || i == OP_RJUMPI)) + continue; + // Skip DUPN and SWAPN. They are not defined in evmc // TODO: Define DUPN and SWAPN in evmc if (Opcode(i) == OP_DUPN || Opcode(i) == OP_SWAPN) @@ -150,6 +160,10 @@ 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) { + // TODO pending update in EVMC + if (i == OP_RJUMP || i == OP_RJUMPI) + continue; + // Skip DUPN and SWAPN. They are not defined in evmc // TODO: Define DUPN and SWAPN in evmc if (Opcode(i) == OP_DUPN || Opcode(i) == OP_SWAPN) From cd225025e5c6e5a6796fee20f2ada04a06e5d3a4 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 6 Dec 2022 15:06:28 +0100 Subject: [PATCH 18/72] test: Tests for RJUMP/RJUMPI --- test/unittests/evm_eof_test.cpp | 129 ++++++++++++++++++++++++++++++++ test/utils/bytecode.hpp | 14 +++- 2 files changed, 142 insertions(+), 1 deletion(-) diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 819a407062..2450b8fbe0 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -217,3 +217,132 @@ TEST_P(evm, eof1_codecopy_out_of_bounds) EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef000101000c02000400601e6000600039601e6000f3deadbeef00000000"_hex); } + +TEST_P(evm, eof2_rjump) +{ + // Relative jumps are not implemented in Advanced. + if (isAdvanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = eof1_bytecode(rjump(1) + OP_INVALID + mstore8(0, 1) + ret(0, 1)); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 1); + + code = eof1_bytecode(rjump(1) + OP_INVALID + mstore8(0, 1) + ret(0, 1), "deadbeef"); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 1); +} + +TEST_P(evm, eof2_rjump_backward) +{ + // Relative jumps are not implemented in Advanced. + if (isAdvanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = + eof1_bytecode(rjump(11) + OP_INVALID + mstore8(0, 1) + ret(0, 1) + rjump(-13) + OP_STOP); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 1); + + code = eof1_bytecode( + rjump(11) + OP_INVALID + mstore8(0, 1) + ret(0, 1) + rjump(-13) + OP_STOP, "deadbeef"); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 1); +} + +TEST_P(evm, eof2_rjump_0_offset) +{ + // Relative jumps are not implemented in Advanced. + if (isAdvanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = eof1_bytecode(rjump(0) + mstore8(0, 1) + ret(0, 1)); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 1); +} + +TEST_P(evm, eof2_rjumpi) +{ + // Relative jumps are not implemented in Advanced. + if (isAdvanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = eof1_bytecode( + rjumpi(10, calldataload(0)) + mstore8(0, 2) + ret(0, 1) + mstore8(0, 1) + ret(0, 1)); + + // RJUMPI condition is true + execute(code, "01"_hex); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 1); + + // RJUMPI condition is false + execute(code, "00"_hex); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 2); +} + +TEST_P(evm, eof2_rjumpi_backwards) +{ + // Relative jumps are not implemented in Advanced. + if (isAdvanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = eof1_bytecode(rjump(11) + OP_INVALID + mstore8(0, 1) + ret(0, 1) + + rjumpi(-16, calldataload(0)) + mstore8(0, 2) + ret(0, 1)); + + // RJUMPI condition is true + execute(code, "01"_hex); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 1); + + // RJUMPI condition is false + execute(code, "00"_hex); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 2); +} + +TEST_P(evm, eof2_rjumpi_0_offset) +{ + // Relative jumps are not implemented in Advanced. + if (isAdvanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = eof1_bytecode(rjumpi(0, calldataload(0)) + mstore8(0, 1) + ret(0, 1)); + + // RJUMPI condition is true + execute(code, "01"_hex); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 1); + + // RJUMPI condition is false + execute(code, "00"_hex); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 1); + EXPECT_EQ(result.output_data[0], 1); +} diff --git a/test/utils/bytecode.hpp b/test/utils/bytecode.hpp index 5cd9b3e53e..35bd676a7d 100644 --- a/test/utils/bytecode.hpp +++ b/test/utils/bytecode.hpp @@ -83,7 +83,9 @@ inline bytecode operator*(int n, Opcode op) return n * bytecode{op}; } -inline bytes big_endian(uint16_t value) +template +inline typename std::enable_if_t || std::is_same_v, bytes> +big_endian(T value) { return {static_cast(value >> 8), static_cast(value)}; } @@ -242,6 +244,16 @@ inline bytecode jumpi(bytecode target, bytecode condition) return condition + target + OP_JUMPI; } +inline bytecode rjump(int16_t offset) +{ + return OP_RJUMP + big_endian(offset); +} + +inline bytecode rjumpi(int16_t offset, bytecode condition) +{ + return condition + OP_RJUMPI + bytecode{big_endian(offset)}; +} + inline bytecode ret(bytecode index, bytecode size) { return size + index + OP_RETURN; From e592a8021c71929d2f925e9f64b7a8fad7e3270d Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Mon, 4 Apr 2022 12:46:38 +0200 Subject: [PATCH 19/72] Validation of RJUMP* instructions --- lib/evmone/eof.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ lib/evmone/eof.hpp | 2 ++ 2 files changed, 46 insertions(+) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 5beeb05c3d..d52325901b 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace evmone { @@ -119,6 +120,41 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe return EOFValidationError::success; } +bool validate_rjump_destinations( + const EOF1Header& header, bytes_view::const_iterator container) noexcept +{ + // Collect relative jump destinations and immediate locations + std::vector rjumpdests; + std::vector immediate_map(header.code_end()); + for (auto i = header.code_begin(); i < header.code_end(); ++i) + { + const auto op = container[i]; + + if (op == OP_RJUMP || op == OP_RJUMPI) + { + const auto offset_hi = container[i + 1]; + const auto offset_lo = container[i + 2]; + const auto offset = static_cast((offset_hi << 8) + offset_lo); + const auto jumpdest = static_cast(i) + 3 + offset; + if (jumpdest < static_cast(header.code_begin()) || + jumpdest >= static_cast(header.code_end())) + return false; + rjumpdests.push_back(static_cast(jumpdest)); + } + + const auto imm_size = instr::traits[op].immediate_size; + std::fill_n(immediate_map.begin() + static_cast(i) + 1, imm_size, true); + i += imm_size; + } + + // Check relative jump destinations against immediate locations. + for (const auto rjumpdest : rjumpdests) + if (immediate_map[rjumpdest]) + return false; + + return true; +} + std::pair validate_eof1( evmc_revision rev, bytes_view container) noexcept { @@ -133,6 +169,9 @@ std::pair validate_eof1( if (error_instr != EOFValidationError::success) return {{}, error_instr}; + if (!validate_rjump_destinations(header, container.begin())) + return {{}, EOFValidationError::invalid_rjump_destination}; + return {header, EOFValidationError::success}; } @@ -148,6 +187,11 @@ size_t EOF1Header::code_begin() const noexcept return 10; // MAGIC + VERSION + SECTION_ID + SIZE + SECTION_ID + SIZE + TERMINATOR } +size_t EOF1Header::code_end() const noexcept +{ + return code_begin() + code_size; +} + bool is_eof_code(bytes_view code) noexcept { return code.size() > 1 && code[0] == MAGIC[0] && code[1] == MAGIC[1]; diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index ed9faef28c..58e9f4109e 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -20,6 +20,7 @@ struct EOF1Header /// Returns offset of code section start. [[nodiscard]] EVMC_EXPORT size_t code_begin() const noexcept; + [[nodiscard]] EVMC_EXPORT size_t code_end() const noexcept; }; /// Checks if code starts with EOF FORMAT + MAGIC, doesn't validate the format. @@ -48,6 +49,7 @@ enum class EOFValidationError invalid_section_bodies_size, undefined_instruction, missing_terminating_instruction, + invalid_rjump_destination, impossible, }; From 75b9dbecb212abb000d0b539eff6a3671a6731f4 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 6 Dec 2022 15:10:16 +0100 Subject: [PATCH 20/72] test: Tests for RJUMP/RJUMPI instruction validation --- test/unittests/eof_validation_test.cpp | 96 ++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 5a6195b281..7af5439fa3 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -237,3 +237,99 @@ TEST(eof_validation, EOF1_terminating_instructions) EXPECT_EQ(validate_eof(container), expected) << hex(code); } } + +TEST(eof_validation, EOF1_valid_rjump) +{ + // offset = 0 + EXPECT_EQ(validate_eof("EF0001 010004 00 5C000000"), EOFValidationError::success); + + // offset = 3 + EXPECT_EQ(validate_eof("EF0001 010007 00 5C000300000000"), EOFValidationError::success); + + // offset = -4 + EXPECT_EQ(validate_eof("EF0001 010005 00 005CFFFC00"), EOFValidationError::success); +} + +TEST(eof_validation, EOF1_valid_rjumpi) +{ + // offset = 0 + EXPECT_EQ(validate_eof("EF0001 010006 00 60005D000000"), EOFValidationError::success); + + // offset = 3 + EXPECT_EQ(validate_eof("EF0001 010009 00 60005D000300000000"), EOFValidationError::success); + + // offset = -5 + EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFFB00"), EOFValidationError::success); +} + +TEST(eof_validation, EOF1_rjump_truncated) +{ + EXPECT_EQ( + validate_eof("EF0001 010001 00 5C"), EOFValidationError::missing_terminating_instruction); + + EXPECT_EQ( + validate_eof("EF0001 010002 00 5C00"), EOFValidationError::missing_terminating_instruction); +} + +TEST(eof_validation, EOF1_rjumpi_truncated) +{ + EXPECT_EQ(validate_eof("EF0001 010003 00 60005D"), + EOFValidationError::missing_terminating_instruction); + + EXPECT_EQ(validate_eof("EF0001 010004 00 60005D00"), + EOFValidationError::missing_terminating_instruction); +} + +TEST(eof_validation, EOF1_rjump_invalid_destination) +{ + // Into header (offset = -5) + EXPECT_EQ( + validate_eof("EF0001 010004 00 5CFFFB00"), EOFValidationError::invalid_rjump_destination); + + // To before code begin (offset = -13) + EXPECT_EQ( + validate_eof("EF0001 010004 00 5CFFF300"), EOFValidationError::invalid_rjump_destination); + + // To after code end (offset = 2) + EXPECT_EQ( + validate_eof("EF0001 010004 00 5C000200"), EOFValidationError::invalid_rjump_destination); + + // To code end (offset = 1) + EXPECT_EQ( + validate_eof("EF0001 010004 00 5C000100"), EOFValidationError::invalid_rjump_destination); + + // To the same RJUMP immediate (offset = -1) + EXPECT_EQ( + validate_eof("EF0001 010004 00 5CFFFF00"), EOFValidationError::invalid_rjump_destination); + + // To PUSH immediate (offset = -4) + EXPECT_EQ(validate_eof("EF0001 010006 00 60005CFFFC00"), + EOFValidationError::invalid_rjump_destination); +} + +TEST(eof_validation, EOF1_rjumpi_invalid_destination) +{ + // Into header (offset = -7) + EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFF900"), + EOFValidationError::invalid_rjump_destination); + + // To before code begin (offset = -15) + EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFF100"), + EOFValidationError::invalid_rjump_destination); + + // To after code end (offset = 2) + EXPECT_EQ(validate_eof("EF0001 010006 00 60005D000200"), + EOFValidationError::invalid_rjump_destination); + + // To code end (offset = 1) + EXPECT_EQ(validate_eof("EF0001 010006 00 60005D000100"), + EOFValidationError::invalid_rjump_destination); + + // To the same RJUMPI immediate (offset = -1) + EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFFF00"), + EOFValidationError::invalid_rjump_destination); + + // To PUSH immediate (offset = -4) + EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFFC00"), + EOFValidationError::invalid_rjump_destination); +} From 02f63d48e3f0ff1a0d8a7ec3822cc3647efe4a03 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Wed, 7 Dec 2022 17:50:55 +0100 Subject: [PATCH 21/72] Undefine RJUMP* instructions in non-EOF code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Bylica --- lib/evmone/baseline.cpp | 6 ++-- lib/evmone/baseline.hpp | 5 ++-- lib/evmone/baseline_instruction_table.cpp | 36 +++++++++++++++-------- lib/evmone/baseline_instruction_table.hpp | 4 ++- test/unittests/evm_eof_test.cpp | 15 ++++++++++ 5 files changed, 49 insertions(+), 17 deletions(-) diff --git a/lib/evmone/baseline.cpp b/lib/evmone/baseline.cpp index fd33d50dbe..b92c7763b3 100644 --- a/lib/evmone/baseline.cpp +++ b/lib/evmone/baseline.cpp @@ -70,7 +70,9 @@ CodeAnalysis analyze_legacy(bytes_view code) CodeAnalysis analyze_eof1(bytes_view eof_container, const EOF1Header& header) { const auto executable_code = eof_container.substr(header.code_begin(), header.code_size); - return {executable_code, analyze_jumpdests(executable_code)}; + + // FIXME: Better way of getting EOF version. + return {executable_code, analyze_jumpdests(executable_code), eof_container[2]}; } } // namespace @@ -321,7 +323,7 @@ evmc_result execute(const VM& vm, ExecutionState& state, const CodeAnalysis& ana const auto code = analysis.executable_code; - const auto& cost_table = get_baseline_cost_table(state.rev); + const auto& cost_table = get_baseline_cost_table(state.rev, analysis.eof_version); auto* tracer = vm.get_tracer(); if (INTX_UNLIKELY(tracer != nullptr)) diff --git a/lib/evmone/baseline.hpp b/lib/evmone/baseline.hpp index 9f9a36cca2..eb16ddfb61 100644 --- a/lib/evmone/baseline.hpp +++ b/lib/evmone/baseline.hpp @@ -25,6 +25,7 @@ class CodeAnalysis bytes_view executable_code; ///< Executable code section. JumpdestMap jumpdest_map; ///< Map of valid jump destinations. + uint8_t eof_version = 0; ///< The EOF version, 0 means legacy code. private: /// Padded code for faster legacy code execution. @@ -38,8 +39,8 @@ class CodeAnalysis m_padded_code{std::move(padded_code)} {} - CodeAnalysis(bytes_view code, JumpdestMap map) - : executable_code{code}, jumpdest_map{std::move(map)} + CodeAnalysis(bytes_view code, JumpdestMap map, uint8_t eof_ver) + : executable_code{code}, jumpdest_map{std::move(map)}, eof_version{eof_ver} {} }; static_assert(std::is_move_constructible_v); diff --git a/lib/evmone/baseline_instruction_table.cpp b/lib/evmone/baseline_instruction_table.cpp index d46d22d765..3f51b53ff6 100644 --- a/lib/evmone/baseline_instruction_table.cpp +++ b/lib/evmone/baseline_instruction_table.cpp @@ -7,21 +7,33 @@ namespace evmone::baseline { -const CostTable& get_baseline_cost_table(evmc_revision rev) noexcept +namespace { - static constexpr auto cost_tables = []() noexcept { - std::array tables{}; - for (size_t r = EVMC_FRONTIER; r <= EVMC_MAX_REVISION; ++r) +constexpr auto eof_cost_tables = []() noexcept { + std::array tables{}; + for (size_t r = EVMC_FRONTIER; r <= EVMC_MAX_REVISION; ++r) + { + auto& table = tables[r]; + for (size_t i = 0; i < table.size(); ++i) { - auto& table = tables[r]; - for (size_t i = 0; i < table.size(); ++i) - { - table[i] = instr::gas_costs[r][i]; // Include instr::undefined in the table. - } + table[i] = instr::gas_costs[r][i]; // Include instr::undefined in the table. } - return tables; - }(); + } + return tables; +}(); - return cost_tables[rev]; +constexpr auto legacy_cost_tables = []() noexcept { + auto tables = eof_cost_tables; + tables[EVMC_SHANGHAI][OP_RJUMP] = instr::undefined; + tables[EVMC_SHANGHAI][OP_RJUMPI] = instr::undefined; + return tables; +}(); + +} // namespace + +const CostTable& get_baseline_cost_table(evmc_revision rev, uint8_t eof_version) noexcept +{ + const auto& tables = (eof_version == 0) ? legacy_cost_tables : eof_cost_tables; + return tables[rev]; } } // namespace evmone::baseline diff --git a/lib/evmone/baseline_instruction_table.hpp b/lib/evmone/baseline_instruction_table.hpp index 7bdbd8b98f..f163bd9742 100644 --- a/lib/evmone/baseline_instruction_table.hpp +++ b/lib/evmone/baseline_instruction_table.hpp @@ -10,5 +10,7 @@ namespace evmone::baseline { using CostTable = std::array; -const CostTable& get_baseline_cost_table(evmc_revision rev) noexcept; +const CostTable& get_baseline_cost_table(evmc_revision rev, uint8_t eof_version) noexcept; + +const CostTable& get_baseline_legacy_cost_table(evmc_revision rev) noexcept; } // namespace evmone::baseline diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 2450b8fbe0..78ec0d15f0 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -346,3 +346,18 @@ TEST_P(evm, eof2_rjumpi_0_offset) ASSERT_EQ(result.output_size, 1); EXPECT_EQ(result.output_data[0], 1); } + + +TEST_P(evm, relative_jumps_undefined_in_legacy) +{ + rev = EVMC_SHANGHAI; + auto code = rjump(1) + OP_INVALID + mstore8(0, 1) + ret(0, 1); + + execute(code); + EXPECT_STATUS(EVMC_UNDEFINED_INSTRUCTION); + + code = rjumpi(10, 1) + mstore8(0, 2) + ret(0, 1) + mstore8(0, 1) + ret(0, 1); + + execute(code); + EXPECT_STATUS(EVMC_UNDEFINED_INSTRUCTION); +} From cba432c01cb243c70ec84a8f8b209c5ae664110a Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 15 Dec 2022 13:14:58 +0100 Subject: [PATCH 22/72] Fix eof branch build after rebasing --- test/unittests/evm_eof_test.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 78ec0d15f0..a921316cdb 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -221,7 +221,7 @@ TEST_P(evm, eof1_codecopy_out_of_bounds) TEST_P(evm, eof2_rjump) { // Relative jumps are not implemented in Advanced. - if (isAdvanced()) + if (is_advanced()) return; rev = EVMC_SHANGHAI; @@ -243,7 +243,7 @@ TEST_P(evm, eof2_rjump) TEST_P(evm, eof2_rjump_backward) { // Relative jumps are not implemented in Advanced. - if (isAdvanced()) + if (is_advanced()) return; rev = EVMC_SHANGHAI; @@ -267,7 +267,7 @@ TEST_P(evm, eof2_rjump_backward) TEST_P(evm, eof2_rjump_0_offset) { // Relative jumps are not implemented in Advanced. - if (isAdvanced()) + if (is_advanced()) return; rev = EVMC_SHANGHAI; @@ -282,7 +282,7 @@ TEST_P(evm, eof2_rjump_0_offset) TEST_P(evm, eof2_rjumpi) { // Relative jumps are not implemented in Advanced. - if (isAdvanced()) + if (is_advanced()) return; rev = EVMC_SHANGHAI; @@ -305,7 +305,7 @@ TEST_P(evm, eof2_rjumpi) TEST_P(evm, eof2_rjumpi_backwards) { // Relative jumps are not implemented in Advanced. - if (isAdvanced()) + if (is_advanced()) return; rev = EVMC_SHANGHAI; @@ -328,7 +328,7 @@ TEST_P(evm, eof2_rjumpi_backwards) TEST_P(evm, eof2_rjumpi_0_offset) { // Relative jumps are not implemented in Advanced. - if (isAdvanced()) + if (is_advanced()) return; rev = EVMC_SHANGHAI; From 4e236de899515661762ab36a86b6bb007ab7eaf5 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Wed, 30 Nov 2022 10:50:26 +0100 Subject: [PATCH 23/72] EIP-3860: Limit and meter initcode --- lib/evmone/instructions_calls.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/evmone/instructions_calls.cpp b/lib/evmone/instructions_calls.cpp index bc92155389..95a3cb5f44 100644 --- a/lib/evmone/instructions_calls.cpp +++ b/lib/evmone/instructions_calls.cpp @@ -125,11 +125,13 @@ evmc_status_code create_impl(StackTop stack, ExecutionState& state) noexcept if (!check_memory(state, init_code_offset, init_code_size)) return EVMC_OUT_OF_GAS; + const auto init_code_words = num_words(static_cast(init_code_size)); + auto salt = uint256{}; if constexpr (Op == OP_CREATE2) { salt = stack.pop(); - auto salt_cost = num_words(static_cast(init_code_size)) * 6; + const auto salt_cost = init_code_words * 6; if ((state.gas_left -= salt_cost) < 0) return EVMC_OUT_OF_GAS; } @@ -137,6 +139,16 @@ evmc_status_code create_impl(StackTop stack, ExecutionState& state) noexcept stack.push(0); state.return_data.clear(); + if (state.rev >= EVMC_SHANGHAI) + { + if (init_code_size > 0xC000) + return EVMC_SUCCESS; + + const auto init_code_cost = init_code_words * 2; + if ((state.gas_left -= init_code_cost) < 0) + return EVMC_OUT_OF_GAS; + } + if (state.msg->depth >= 1024) return EVMC_SUCCESS; From 7377eb871de73c4b42f22aba31d6117f4324d9cf Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 15 Dec 2022 13:44:12 +0100 Subject: [PATCH 24/72] Add "Merge+" rev name suppport --- test/statetest/statetest_loader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/statetest/statetest_loader.cpp b/test/statetest/statetest_loader.cpp index e66c4b07c7..43b12ef979 100644 --- a/test/statetest/statetest_loader.cpp +++ b/test/statetest/statetest_loader.cpp @@ -108,8 +108,11 @@ evmc_revision to_rev(std::string_view s) return EVMC_LONDON; if (s == "Merge") return EVMC_PARIS; + // TODO: Remove London+3540+3670 revision as it's no longer used in ethereum/tests if (s == "London+3540+3670") return EVMC_SHANGHAI; + if (s.starts_with("Merge+")) + return EVMC_SHANGHAI; throw std::invalid_argument{"unknown revision: " + std::string{s}}; } } // namespace From 7e11e9209d528621ae98dc6793596a91abb6f4f4 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 15 Dec 2022 23:13:28 +0100 Subject: [PATCH 25/72] Apply init code cost (EIP3860) --- test/state/state.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/state/state.cpp b/test/state/state.cpp index a161daa574..6b0e36f80f 100644 --- a/test/state/state.cpp +++ b/test/state/state.cpp @@ -36,9 +36,17 @@ int64_t compute_tx_intrinsic_cost(evmc_revision rev, const Transaction& tx) noex { static constexpr auto call_tx_cost = 21000; static constexpr auto create_tx_cost = 53000; + static constexpr auto initcode_word_cost = 2; + static constexpr auto word_size = 32; const bool is_create = !tx.to.has_value(); + const auto num_full_words = tx.data.size() / word_size; + const auto num_word = tx.data.size() % word_size != 0 ? num_full_words + 1 : num_full_words; + const auto init_code_cost = + is_create && rev >= EVMC_SHANGHAI ? initcode_word_cost * num_word : 0; const auto tx_cost = is_create && rev >= EVMC_HOMESTEAD ? create_tx_cost : call_tx_cost; - return tx_cost + compute_tx_data_cost(rev, tx.data) + compute_access_list_cost(tx.access_list); + + return tx_cost + compute_tx_data_cost(rev, tx.data) + compute_access_list_cost(tx.access_list) + + int64_t(init_code_cost); } /// Validates transaction and computes its execution gas limit (the amount of gas provided to EVM). From fdba7dc3f4d369be1708e57100448e165063f067 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 15 Dec 2022 16:10:51 +0100 Subject: [PATCH 26/72] Limit init code size --- test/state/state.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/state/state.cpp b/test/state/state.cpp index 6b0e36f80f..cdf135c73d 100644 --- a/test/state/state.cpp +++ b/test/state/state.cpp @@ -76,6 +76,10 @@ int64_t validate_transaction(const Account& sender_acc, const BlockInfo& block, if (sender_acc.nonce == Account::NonceMax) return -1; + static constexpr auto max_code_size = 24576; + if (rev >= EVMC_SHANGHAI && !tx.to.has_value() && tx.data.size() > 2 * max_code_size) + return -1; // initcode size is limited (EIP-3860). + // Compute and check if sender has enough balance for the theoretical maximum transaction cost. // Note this is different from tx_max_cost computed with effective gas price later. // The computation cannot overflow if done with 512-bit precision. From 08986019320e7b611d5f392600ce7f680d72a22a Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 15 Dec 2022 23:28:34 +0100 Subject: [PATCH 27/72] Fix a subtel bug for mining reward for pre EIP158 --- test/state/state.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/state/state.cpp b/test/state/state.cpp index cdf135c73d..6dfd7d4f6f 100644 --- a/test/state/state.cpp +++ b/test/state/state.cpp @@ -116,7 +116,12 @@ std::optional> transition( auto& sender_acc = state.get(tx.sender); const auto execution_gas_limit = validate_transaction(sender_acc, block, tx, rev); if (execution_gas_limit < 0) + { + // For pre EIP-158 coinbase has to be touched for invalid tx also + if (rev <= EVMC_TANGERINE_WHISTLE) + state.touch(block.coinbase); return {}; + } const auto base_fee = (rev >= EVMC_LONDON) ? block.base_fee : 0; assert(tx.max_gas_price >= base_fee); // Checked at the front. From 4c80f2f4268780eeac14b49e6e27feb4975922f0 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Fri, 16 Dec 2022 19:09:06 +0100 Subject: [PATCH 28/72] Fix the rest of state tests by distinguishing with applied EIPs --- lib/evmone/CMakeLists.txt | 1 + lib/evmone/advanced_instructions.cpp | 2 ++ lib/evmone/baseline_instruction_table.cpp | 2 ++ lib/evmone/eips.hpp | 38 +++++++++++++++++++++++ lib/evmone/instructions_calls.cpp | 3 +- lib/evmone/instructions_storage.cpp | 3 +- test/state/state.cpp | 5 +-- test/statetest/CMakeLists.txt | 1 + test/statetest/statetest_loader.cpp | 33 +++++++++++++++++++- 9 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 lib/evmone/eips.hpp diff --git a/lib/evmone/CMakeLists.txt b/lib/evmone/CMakeLists.txt index b97c325cd7..861f418e25 100644 --- a/lib/evmone/CMakeLists.txt +++ b/lib/evmone/CMakeLists.txt @@ -27,6 +27,7 @@ add_library(evmone instructions_traits.hpp instructions_xmacro.hpp opcodes_helpers.h + eips.hpp tracing.cpp tracing.hpp vm.cpp diff --git a/lib/evmone/advanced_instructions.cpp b/lib/evmone/advanced_instructions.cpp index 8c86499c16..923152608a 100644 --- a/lib/evmone/advanced_instructions.cpp +++ b/lib/evmone/advanced_instructions.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "advanced_analysis.hpp" +#include "eips.hpp" #include "instructions.hpp" #include "instructions_traits.hpp" @@ -256,6 +257,7 @@ constexpr std::array instruction_implementations = []( EVMC_EXPORT const OpTable& get_op_table(evmc_revision rev) noexcept { + rev = clear_eips(rev); static constexpr auto op_tables = []() noexcept { std::array tables{}; for (size_t r = EVMC_FRONTIER; r <= EVMC_MAX_REVISION; ++r) diff --git a/lib/evmone/baseline_instruction_table.cpp b/lib/evmone/baseline_instruction_table.cpp index 3f51b53ff6..ed9b2c0c94 100644 --- a/lib/evmone/baseline_instruction_table.cpp +++ b/lib/evmone/baseline_instruction_table.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "baseline_instruction_table.hpp" +#include "eips.hpp" #include "instructions_traits.hpp" namespace evmone::baseline @@ -33,6 +34,7 @@ constexpr auto legacy_cost_tables = []() noexcept { const CostTable& get_baseline_cost_table(evmc_revision rev, uint8_t eof_version) noexcept { + rev = clear_eips(rev); const auto& tables = (eof_version == 0) ? legacy_cost_tables : eof_cost_tables; return tables[rev]; } diff --git a/lib/evmone/eips.hpp b/lib/evmone/eips.hpp new file mode 100644 index 0000000000..fd85111f1b --- /dev/null +++ b/lib/evmone/eips.hpp @@ -0,0 +1,38 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2021 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +namespace evmone +{ + +/// The list Ethereum EIPs being implemented in evmone. +/// +/// This is not enum class because we want implicit conversion to integers, +/// e.g. for usage as an array index. +enum Eip : int +{ + EIP3540 = (1 << 8), + EIP3670 = (1 << 9), + EIP3855 = (1 << 10), + EIP3860 = (1 << 11) +}; + +inline constexpr evmc_revision add_eip(evmc_revision rev, Eip eip) +{ + return static_cast(rev | static_cast(eip)); +} + +inline constexpr bool has_eip(evmc_revision rev, Eip eip) +{ + return (rev & static_cast(eip)) > 0; +} + +inline constexpr evmc_revision clear_eips(evmc_revision rev) +{ + return static_cast(rev & 0xff); +} + +} // namespace evmone diff --git a/lib/evmone/instructions_calls.cpp b/lib/evmone/instructions_calls.cpp index 95a3cb5f44..c75bd14fbf 100644 --- a/lib/evmone/instructions_calls.cpp +++ b/lib/evmone/instructions_calls.cpp @@ -2,6 +2,7 @@ // Copyright 2019 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 +#include "eips.hpp" #include "instructions.hpp" namespace evmone::instr::core @@ -139,7 +140,7 @@ evmc_status_code create_impl(StackTop stack, ExecutionState& state) noexcept stack.push(0); state.return_data.clear(); - if (state.rev >= EVMC_SHANGHAI) + if (has_eip(state.rev, EIP3860)) { if (init_code_size > 0xC000) return EVMC_SUCCESS; diff --git a/lib/evmone/instructions_storage.cpp b/lib/evmone/instructions_storage.cpp index 4440496f14..8d3797066f 100644 --- a/lib/evmone/instructions_storage.cpp +++ b/lib/evmone/instructions_storage.cpp @@ -2,6 +2,7 @@ // Copyright 2019 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 +#include "eips.hpp" #include "instructions.hpp" namespace evmone::instr::core @@ -130,7 +131,7 @@ evmc_status_code sstore(StackTop stack, ExecutionState& state) noexcept 0; const auto status = state.host.set_storage(state.msg->recipient, key, value); - const auto [gas_cost_warm, gas_refund] = sstore_costs[state.rev][status]; + const auto [gas_cost_warm, gas_refund] = sstore_costs[clear_eips(state.rev)][status]; const auto gas_cost = gas_cost_warm + gas_cost_cold; if ((state.gas_left -= gas_cost) < 0) return EVMC_OUT_OF_GAS; diff --git a/test/state/state.cpp b/test/state/state.cpp index 6dfd7d4f6f..5d146dccf0 100644 --- a/test/state/state.cpp +++ b/test/state/state.cpp @@ -4,6 +4,7 @@ #include "state.hpp" #include "host.hpp" +#include #include #include @@ -42,7 +43,7 @@ int64_t compute_tx_intrinsic_cost(evmc_revision rev, const Transaction& tx) noex const auto num_full_words = tx.data.size() / word_size; const auto num_word = tx.data.size() % word_size != 0 ? num_full_words + 1 : num_full_words; const auto init_code_cost = - is_create && rev >= EVMC_SHANGHAI ? initcode_word_cost * num_word : 0; + is_create && has_eip(rev, EIP3860) ? initcode_word_cost * num_word : 0; const auto tx_cost = is_create && rev >= EVMC_HOMESTEAD ? create_tx_cost : call_tx_cost; return tx_cost + compute_tx_data_cost(rev, tx.data) + compute_access_list_cost(tx.access_list) + @@ -77,7 +78,7 @@ int64_t validate_transaction(const Account& sender_acc, const BlockInfo& block, return -1; static constexpr auto max_code_size = 24576; - if (rev >= EVMC_SHANGHAI && !tx.to.has_value() && tx.data.size() > 2 * max_code_size) + if (has_eip(rev, EIP3860) && !tx.to.has_value() && tx.data.size() > 2 * max_code_size) return -1; // initcode size is limited (EIP-3860). // Compute and check if sender has enough balance for the theoretical maximum transaction cost. diff --git a/test/statetest/CMakeLists.txt b/test/statetest/CMakeLists.txt index be24432054..ada9d2568b 100644 --- a/test/statetest/CMakeLists.txt +++ b/test/statetest/CMakeLists.txt @@ -8,6 +8,7 @@ find_package(nlohmann_json CONFIG REQUIRED) add_library(evmone-statetestutils STATIC) add_library(evmone::statetestutils ALIAS evmone-statetestutils) target_compile_features(evmone-statetestutils PUBLIC cxx_std_20) +target_include_directories(evmone-statetestutils PRIVATE ${evmone_private_include_dir}) target_link_libraries(evmone-statetestutils PRIVATE evmone::state nlohmann_json::nlohmann_json) target_sources( evmone-statetestutils PRIVATE diff --git a/test/statetest/statetest_loader.cpp b/test/statetest/statetest_loader.cpp index 43b12ef979..f571355784 100644 --- a/test/statetest/statetest_loader.cpp +++ b/test/statetest/statetest_loader.cpp @@ -3,8 +3,12 @@ // SPDX-License-Identifier: Apache-2.0 #include "statetest.hpp" +#include #include +#include #include +#include +#include namespace evmone::test { @@ -112,7 +116,34 @@ evmc_revision to_rev(std::string_view s) if (s == "London+3540+3670") return EVMC_SHANGHAI; if (s.starts_with("Merge+")) - return EVMC_SHANGHAI; + { + std::stringstream ss(std::string(s.substr(6))); + std::string token; + + std::vector eips; + while (std::getline(ss, token, '+')) + { + eips.push_back(token); + } + + auto rev = EVMC_SHANGHAI; + for (auto e : eips) + { + if (e == "3540") + rev = add_eip(rev, EIP3540); + else if (e == "3670") + rev = add_eip(rev, EIP3670); + else if (e == "3860") + rev = add_eip(rev, EIP3860); + else if (e == "3855") + rev = add_eip(rev, EIP3855); + else + assert(false); // Unknown EIP + } + + return rev; + } + throw std::invalid_argument{"unknown revision: " + std::string{s}}; } } // namespace From 2c3d305bddd08c90e4a175acf66586818138ddc9 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Fri, 16 Dec 2022 19:22:40 +0100 Subject: [PATCH 29/72] Update state tests to the newest tests/develop --- circle.yml | 2 +- test/statetest/statetest_loader.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index d075e2c231..2d732b930c 100644 --- a/circle.yml +++ b/circle.yml @@ -390,7 +390,7 @@ jobs: steps: - build - download_consensus_tests: - rev: v11.1 + rev: develop - run: name: "State tests" working_directory: ~/build diff --git a/test/statetest/statetest_loader.cpp b/test/statetest/statetest_loader.cpp index f571355784..8dc4e2f55c 100644 --- a/test/statetest/statetest_loader.cpp +++ b/test/statetest/statetest_loader.cpp @@ -127,7 +127,7 @@ evmc_revision to_rev(std::string_view s) } auto rev = EVMC_SHANGHAI; - for (auto e : eips) + for (const auto& e : eips) { if (e == "3540") rev = add_eip(rev, EIP3540); From c4a3775bf546ea0960b69e05a101d6cc59c54ca3 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Wed, 7 Dec 2022 11:34:31 +0100 Subject: [PATCH 30/72] Add CALLF/RETF instructions --- lib/evmone/instructions_opcodes.hpp | 3 +++ lib/evmone/instructions_traits.hpp | 4 ++++ test/unittests/eof_validation_test.cpp | 11 ++++++----- test/unittests/instructions_test.cpp | 11 +++++++---- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/evmone/instructions_opcodes.hpp b/lib/evmone/instructions_opcodes.hpp index 1c0bc1014b..1b7409cbf2 100644 --- a/lib/evmone/instructions_opcodes.hpp +++ b/lib/evmone/instructions_opcodes.hpp @@ -156,6 +156,9 @@ enum Opcode : uint8_t OP_LOG3 = 0xa3, OP_LOG4 = 0xa4, + OP_CALLF = 0xb0, + OP_RETF = 0xb1, + OP_DUPN = 0xb5, OP_SWAPN = 0xb6, diff --git a/lib/evmone/instructions_traits.hpp b/lib/evmone/instructions_traits.hpp index e9783caf8e..196493e670 100644 --- a/lib/evmone/instructions_traits.hpp +++ b/lib/evmone/instructions_traits.hpp @@ -164,6 +164,8 @@ constexpr inline GasCostTable gas_costs = []() noexcept { table[EVMC_SHANGHAI][OP_PUSH0] = 2; table[EVMC_SHANGHAI][OP_RJUMP] = 2; table[EVMC_SHANGHAI][OP_RJUMPI] = 4; + table[EVMC_SHANGHAI][OP_CALLF] = 5; + table[EVMC_SHANGHAI][OP_RETF] = 3; table[EVMC_CANCUN] = table[EVMC_SHANGHAI]; table[EVMC_CANCUN][OP_DUPN] = 3; @@ -376,6 +378,8 @@ constexpr inline std::array traits = []() noexcept { table[OP_DELEGATECALL] = {"DELEGATECALL", 0, false, 6, -5, EVMC_HOMESTEAD}; table[OP_CREATE2] = {"CREATE2", 0, false, 4, -3, EVMC_CONSTANTINOPLE}; table[OP_STATICCALL] = {"STATICCALL", 0, false, 6, -5, EVMC_BYZANTIUM}; + table[OP_CALLF] = {"CALLF", 2, false, 0, 0, EVMC_SHANGHAI}; + table[OP_RETF] = {"RETF", 0, true, 0, 0, EVMC_SHANGHAI}; table[OP_REVERT] = {"REVERT", 0, true, 2, -2, EVMC_BYZANTIUM}; table[OP_INVALID] = {"INVALID", 0, true, 0, 0, EVMC_FRONTIER}; table[OP_SELFDESTRUCT] = {"SELFDESTRUCT", 0, true, 1, -1, EVMC_FRONTIER}; diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 7af5439fa3..79582fbd3c 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -172,7 +172,7 @@ TEST(eof_validation, EOF1_undefined_opcodes) // They're all valid in Shanghai and checked in other tests below. if (opcode >= OP_PUSH1 && opcode <= OP_PUSH32) continue; - if (opcode == OP_RJUMP || opcode == OP_RJUMPI) + if (opcode == OP_RJUMP || opcode == OP_RJUMPI || opcode == OP_CALLF) continue; cont[cont.size() - 2] = static_cast(opcode); @@ -230,10 +230,11 @@ TEST(eof_validation, EOF1_terminating_instructions) code_size_byte = static_cast(code.size()); const auto container = eof_header + code; - const auto expected = ((opcode == OP_STOP || opcode == OP_RETURN || opcode == OP_REVERT || - opcode == OP_INVALID || opcode == OP_SELFDESTRUCT) ? - EOFValidationError::success : - EOFValidationError::missing_terminating_instruction); + const auto expected = + ((opcode == OP_STOP || opcode == OP_RETURN || opcode == OP_RETF || + opcode == OP_REVERT || opcode == OP_INVALID || opcode == OP_SELFDESTRUCT) ? + EOFValidationError::success : + EOFValidationError::missing_terminating_instruction); EXPECT_EQ(validate_eof(container), expected) << hex(code); } } diff --git a/test/unittests/instructions_test.cpp b/test/unittests/instructions_test.cpp index 7c257e0c68..726135e828 100644 --- a/test/unittests/instructions_test.cpp +++ b/test/unittests/instructions_test.cpp @@ -38,6 +38,7 @@ constexpr bool is_terminating(Opcode op) noexcept { case OP_STOP: case OP_RETURN: + case OP_RETF: case OP_REVERT: case OP_INVALID: case OP_SELFDESTRUCT: @@ -55,7 +56,7 @@ constexpr void validate_traits_of() noexcept // immediate_size if constexpr (Op >= OP_PUSH1 && Op <= OP_PUSH32) static_assert(tr.immediate_size == Op - OP_PUSH1 + 1); - else if constexpr (Op == OP_RJUMP || Op == OP_RJUMPI) + else if constexpr (Op == OP_RJUMP || Op == OP_RJUMPI || Op == OP_CALLF) static_assert(tr.immediate_size == 2); else if constexpr (Op == OP_DUPN || Op == OP_SWAPN) static_assert(tr.immediate_size == 1); @@ -106,7 +107,8 @@ TEST(instructions, compare_with_evmc_instruction_tables) for (size_t i = 0; i < evmone_tbl.size(); ++i) { // TODO pending update in EVMC - if (r >= EVMC_SHANGHAI && (i == OP_RJUMP || i == OP_RJUMPI)) + if (r >= EVMC_SHANGHAI && + (i == OP_RJUMP || i == OP_RJUMPI || i == OP_CALLF || i == OP_RETF)) continue; // Skip DUPN and SWAPN for Cancun. They are not defined in evmc @@ -143,7 +145,8 @@ TEST(instructions, compare_undefined_instructions) for (size_t i = 0; i < instr_tbl.size(); ++i) { // TODO pending update in EVMC - if (r >= EVMC_SHANGHAI && (i == OP_RJUMP || i == OP_RJUMPI)) + if (r >= EVMC_SHANGHAI && + (i == OP_RJUMP || i == OP_RJUMPI || i == OP_CALLF || i == OP_RETF)) continue; // Skip DUPN and SWAPN. They are not defined in evmc @@ -161,7 +164,7 @@ TEST(instructions, compare_with_evmc_instruction_names) for (size_t i = 0; i < instr::traits.size(); ++i) { // TODO pending update in EVMC - if (i == OP_RJUMP || i == OP_RJUMPI) + if (i == OP_RJUMP || i == OP_RJUMPI || i == OP_CALLF || i == OP_RETF) continue; // Skip DUPN and SWAPN. They are not defined in evmc From 03ac34dfbdb9786ea638c8909ead84a9ce693ac9 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 23 Aug 2022 16:08:12 +0200 Subject: [PATCH 31/72] Implement EIP-4750 EOF validation --- lib/evmone/advanced_execution.cpp | 3 +- lib/evmone/baseline.cpp | 2 +- lib/evmone/eof.cpp | 190 +++++++++++++++++++------ lib/evmone/eof.hpp | 25 +++- test/unittests/analysis_test.cpp | 3 +- test/unittests/eof_test.cpp | 30 ++-- test/unittests/eof_validation_test.cpp | 41 ++++-- 7 files changed, 213 insertions(+), 81 deletions(-) diff --git a/lib/evmone/advanced_execution.cpp b/lib/evmone/advanced_execution.cpp index eb9a1a56fa..2973efc6af 100644 --- a/lib/evmone/advanced_execution.cpp +++ b/lib/evmone/advanced_execution.cpp @@ -36,7 +36,8 @@ evmc_result execute(evmc_vm* /*unused*/, const evmc_host_interface* host, evmc_h if (rev >= EVMC_SHANGHAI) { const auto eof1_header = read_valid_eof1_header(container.begin()); - analysis = analyze(rev, {&container[eof1_header.code_begin()], eof1_header.code_size}); + analysis = + analyze(rev, {&container[eof1_header.code_begin(0)], eof1_header.code_sizes[0]}); } else // Skip analysis, because it will recognize 01 section id as OP_ADD and return diff --git a/lib/evmone/baseline.cpp b/lib/evmone/baseline.cpp index b92c7763b3..007f72bd50 100644 --- a/lib/evmone/baseline.cpp +++ b/lib/evmone/baseline.cpp @@ -69,7 +69,7 @@ CodeAnalysis analyze_legacy(bytes_view code) CodeAnalysis analyze_eof1(bytes_view eof_container, const EOF1Header& header) { - const auto executable_code = eof_container.substr(header.code_begin(), header.code_size); + const auto executable_code = eof_container.substr(header.code_begin(0), header.code_sizes[0]); // FIXME: Better way of getting EOF version. return {executable_code, analyze_jumpdests(executable_code), eof_container[2]}; diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index d52325901b..caf461f102 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace evmone @@ -18,11 +19,24 @@ constexpr uint8_t MAGIC[] = {0xef, 0x00}; constexpr uint8_t TERMINATOR = 0x00; constexpr uint8_t CODE_SECTION = 0x01; constexpr uint8_t DATA_SECTION = 0x02; -constexpr uint8_t MAX_SECTION = DATA_SECTION; +constexpr uint8_t TYPE_SECTION = 0x03; +constexpr uint8_t MAX_SECTION = TYPE_SECTION; +constexpr auto CODE_SECTION_NUMBER_LIMIT = 1024; -using EOFSectionHeaders = std::array; +using EOFSectionHeaders = std::array, MAX_SECTION + 1>; -std::pair validate_eof_headers(bytes_view container) noexcept +size_t eof_header_size(const EOFSectionHeaders& headers) noexcept +{ + const auto section_count = + headers[TYPE_SECTION].size() + headers[CODE_SECTION].size() + headers[DATA_SECTION].size(); + + constexpr auto section_header_size = 3; // (SECTION_ID + SIZE) per each section + + return sizeof(MAGIC) + 1 + // 1 version byte + section_count * section_header_size + sizeof(TERMINATOR); +} + +std::pair validate_eof_headers(bytes_view container) { enum class State { @@ -46,20 +60,30 @@ std::pair validate_eof_headers(bytes_view switch (section_id) { case TERMINATOR: - if (section_headers[CODE_SECTION] == 0) + if (section_headers[CODE_SECTION].empty()) return {{}, EOFValidationError::code_section_missing}; + if (section_headers[CODE_SECTION].size() > 1 && + section_headers[TYPE_SECTION].empty()) + return {{}, EOFValidationError::mandatory_type_section_missing}; state = State::terminated; break; + case TYPE_SECTION: + if (!section_headers[TYPE_SECTION].empty()) + return {{}, EOFValidationError::multiple_type_sections}; + if (!section_headers[CODE_SECTION].empty()) + return {{}, EOFValidationError::code_section_before_type_section}; + state = State::section_size; + break; case DATA_SECTION: - if (section_headers[CODE_SECTION] == 0) - return {{}, EOFValidationError::code_section_missing}; - if (section_headers[DATA_SECTION] != 0) + if (!section_headers[DATA_SECTION].empty()) return {{}, EOFValidationError::multiple_data_sections}; state = State::section_size; break; case CODE_SECTION: - if (section_headers[CODE_SECTION] != 0) - return {{}, EOFValidationError::multiple_code_sections}; + if (section_headers[CODE_SECTION].size() == CODE_SECTION_NUMBER_LIMIT) + return {{}, EOFValidationError::too_many_code_sections}; + if (!section_headers[DATA_SECTION].empty()) + return {{}, EOFValidationError::data_section_before_code_section}; state = State::section_size; break; default: @@ -77,7 +101,7 @@ std::pair validate_eof_headers(bytes_view if (section_size == 0) return {{}, EOFValidationError::zero_section_size}; - section_headers[section_id] = section_size; + section_headers[section_id].emplace_back(section_size); state = State::section_id; break; } @@ -89,14 +113,46 @@ std::pair validate_eof_headers(bytes_view if (state != State::terminated) return {{}, EOFValidationError::section_headers_not_terminated}; - const auto section_bodies_size = section_headers[CODE_SECTION] + section_headers[DATA_SECTION]; + const auto section_bodies_size = + (!section_headers[TYPE_SECTION].empty() ? section_headers[TYPE_SECTION].front() : 0) + + std::accumulate( + section_headers[CODE_SECTION].begin(), section_headers[CODE_SECTION].end(), 0) + + (!section_headers[DATA_SECTION].empty() ? section_headers[DATA_SECTION].front() : 0); const auto remaining_container_size = container_end - it; if (section_bodies_size != remaining_container_size) return {{}, EOFValidationError::invalid_section_bodies_size}; + if (!section_headers[TYPE_SECTION].empty() && + section_headers[TYPE_SECTION][0] != section_headers[CODE_SECTION].size() * 2) + return {{}, EOFValidationError::invalid_type_section_size}; + return {section_headers, EOFValidationError::success}; } +std::pair>, EOFValidationError> validate_types( + bytes_view container, size_t header_size, std::vector type_section_sizes) noexcept +{ + assert(!container.empty()); // guaranteed by EOF headers validation + assert(type_section_sizes.size() <= 1); // guaranteed by EOF headers validation + + if (type_section_sizes.empty()) + return {{{0, 0}}, EOFValidationError::success}; + + std::vector> types; + + // guaranteed by EOF headers validation + assert(header_size + type_section_sizes[0] < container.size()); + + for (auto offset = header_size; offset < header_size + type_section_sizes[0]; offset += 2) + types.emplace_back(container[offset], container[offset + 1]); + + // check 1st section is (0, 0) + if (types[0].first != 0 || types[0].second != 0) + return {{}, EOFValidationError::invalid_fist_section_type}; + + return {types, EOFValidationError::success}; +} + EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noexcept { assert(!code.empty()); // guaranteed by EOF headers validation @@ -121,23 +177,24 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe } bool validate_rjump_destinations( - const EOF1Header& header, bytes_view::const_iterator container) noexcept + const EOF1Header& header, size_t code_idx, bytes_view::const_iterator container) noexcept { // Collect relative jump destinations and immediate locations std::vector rjumpdests; - std::vector immediate_map(header.code_end()); - for (auto i = header.code_begin(); i < header.code_end(); ++i) + const auto code_size = header.code_sizes[code_idx]; + std::vector immediate_map(code_size); + for (size_t i = 0; i < code_size; ++i) { - const auto op = container[i]; + const auto op_pos = header.code_begin(code_idx) + i; + const auto op = container[op_pos]; if (op == OP_RJUMP || op == OP_RJUMPI) { - const auto offset_hi = container[i + 1]; - const auto offset_lo = container[i + 2]; + const auto offset_hi = container[op_pos + 1]; + const auto offset_lo = container[op_pos + 2]; const auto offset = static_cast((offset_hi << 8) + offset_lo); const auto jumpdest = static_cast(i) + 3 + offset; - if (jumpdest < static_cast(header.code_begin()) || - jumpdest >= static_cast(header.code_end())) + if (jumpdest < 0 || jumpdest >= code_size) return false; rjumpdests.push_back(static_cast(jumpdest)); } @@ -162,34 +219,54 @@ std::pair validate_eof1( if (error_header != EOFValidationError::success) return {{}, error_header}; - EOF1Header header{section_headers[CODE_SECTION], section_headers[DATA_SECTION]}; + const auto& code_sizes = section_headers[CODE_SECTION]; + const auto data_size = + section_headers[DATA_SECTION].empty() ? uint16_t{0} : section_headers[DATA_SECTION][0]; - const auto error_instr = - validate_instructions(rev, {&container[header.code_begin()], header.code_size}); - if (error_instr != EOFValidationError::success) - return {{}, error_instr}; + const auto header_size = eof_header_size(section_headers); - if (!validate_rjump_destinations(header, container.begin())) - return {{}, EOFValidationError::invalid_rjump_destination}; + std::vector code_offsets; + auto offset = header_size; + for (const auto code_size : code_sizes) + { + code_offsets.emplace_back(offset); + offset += code_size; + } + + const auto [types, error_types] = + validate_types(container, eof_header_size(section_headers), section_headers[TYPE_SECTION]); + if (error_types != EOFValidationError::success) + return {{}, error_types}; + + EOF1Header header{code_sizes, code_offsets, data_size, types}; + + for (size_t code_idx = 0; code_idx < header.code_sizes.size(); ++code_idx) + { + const auto error_instr = validate_instructions( + rev, {&container[header.code_begin(code_idx)], header.code_sizes[code_idx]}); + if (error_instr != EOFValidationError::success) + return {{}, error_instr}; + + if (!validate_rjump_destinations(header, code_idx, container.begin())) + return {{}, EOFValidationError::invalid_rjump_destination}; + } return {header, EOFValidationError::success}; } } // namespace -size_t EOF1Header::code_begin() const noexcept +size_t EOF1Header::code_begin(size_t index) const noexcept { - assert(code_size != 0); - - if (data_size == 0) - return 7; // MAGIC + VERSION + SECTION_ID + SIZE + TERMINATOR - else - return 10; // MAGIC + VERSION + SECTION_ID + SIZE + SECTION_ID + SIZE + TERMINATOR + assert(index < code_offsets.size()); + return code_offsets[index]; } -size_t EOF1Header::code_end() const noexcept +size_t EOF1Header::code_end(size_t index) const noexcept { - return code_begin() + code_size; + assert(index < code_offsets.size()); + assert(index < code_sizes.size()); + return size_t{code_offsets[index]} + code_sizes[index]; } bool is_eof_code(bytes_view code) noexcept @@ -197,18 +274,45 @@ bool is_eof_code(bytes_view code) noexcept return code.size() > 1 && code[0] == MAGIC[0] && code[1] == MAGIC[1]; } -EOF1Header read_valid_eof1_header(bytes_view::const_iterator code) noexcept +EOF1Header read_valid_eof1_header(bytes_view container) { + EOFSectionHeaders section_headers; + auto it = container.begin() + std::size(MAGIC) + 1; // MAGIC + VERSION + while (*it != TERMINATOR) + { + const auto section_id = *it++; + const auto section_size_hi = *it++; + const auto section_size_lo = *it++; + const auto section_size = static_cast((section_size_hi << 8) | section_size_lo); + section_headers[section_id].emplace_back(section_size); + } + const auto header_size = eof_header_size(section_headers); + EOF1Header header; - const auto code_size_offset = 4; // MAGIC + VERSION + CODE_SECTION_ID - header.code_size = - static_cast((code[code_size_offset] << 8) | code[code_size_offset + 1]); - if (code[code_size_offset + 2] == 2) // is data section present + + if (section_headers[TYPE_SECTION].empty()) + header.types.emplace_back(0, 0); + else { - const auto data_size_offset = code_size_offset + 3; - header.data_size = - static_cast((code[data_size_offset] << 8) | code[data_size_offset + 1]); + for (auto type_offset = header_size; + type_offset < header_size + section_headers[TYPE_SECTION][0]; type_offset += 2) + header.types.emplace_back(container[type_offset], container[type_offset + 1]); } + + header.code_sizes = section_headers[CODE_SECTION]; + std::vector code_offsets; + auto code_offset = + header_size + + (section_headers[TYPE_SECTION].empty() ? uint16_t{0} : section_headers[TYPE_SECTION][0]); + for (const auto code_size : header.code_sizes) + { + header.code_offsets.emplace_back(code_offset); + code_offset += code_size; + } + + header.data_size = + section_headers[DATA_SECTION].empty() ? uint16_t{0} : section_headers[DATA_SECTION][0]; + return header; } diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index 58e9f4109e..c1206e8bca 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace evmone { @@ -15,21 +16,25 @@ using bytes_view = std::basic_string_view; struct EOF1Header { - uint16_t code_size = 0; + /// Size of every code section. + std::vector code_sizes; + /// Offset of every code section start; + std::vector code_offsets; uint16_t data_size = 0; + std::vector> types; + /// Returns offset of code section start. - [[nodiscard]] EVMC_EXPORT size_t code_begin() const noexcept; - [[nodiscard]] EVMC_EXPORT size_t code_end() const noexcept; + [[nodiscard]] EVMC_EXPORT size_t code_begin(size_t index) const noexcept; + [[nodiscard]] EVMC_EXPORT size_t code_end(size_t index) const noexcept; }; /// Checks if code starts with EOF FORMAT + MAGIC, doesn't validate the format. [[nodiscard]] EVMC_EXPORT bool is_eof_code(bytes_view code) noexcept; -/// Reads the section sizes assuming that code has valid format. +/// Reads the section sizes assuming that container has valid format. /// (must be true for all EOF contracts on-chain) -[[nodiscard]] EVMC_EXPORT EOF1Header read_valid_eof1_header( - bytes_view::const_iterator code) noexcept; +[[nodiscard]] EVMC_EXPORT EOF1Header read_valid_eof1_header(bytes_view container); enum class EOFValidationError { @@ -41,7 +46,6 @@ enum class EOFValidationError incomplete_section_size, code_section_missing, - multiple_code_sections, multiple_data_sections, unknown_section_id, zero_section_size, @@ -50,6 +54,13 @@ enum class EOFValidationError undefined_instruction, missing_terminating_instruction, invalid_rjump_destination, + code_section_before_type_section, + multiple_type_sections, + mandatory_type_section_missing, + too_many_code_sections, + data_section_before_code_section, + invalid_type_section_size, + invalid_fist_section_type, impossible, }; diff --git a/test/unittests/analysis_test.cpp b/test/unittests/analysis_test.cpp index 4238208a0e..3684218635 100644 --- a/test/unittests/analysis_test.cpp +++ b/test/unittests/analysis_test.cpp @@ -261,7 +261,8 @@ TEST(analysis, example1_eof1) const auto code = eof1_bytecode( push(0x2a) + push(0x1e) + OP_MSTORE8 + OP_MSIZE + push(0) + OP_SSTORE, "deadbeef"); const auto header = evmone::read_valid_eof1_header(bytes_view(code).begin()); - const auto analysis = analyze(EVMC_SHANGHAI, {&code[header.code_begin()], header.code_size}); + const auto analysis = + analyze(EVMC_SHANGHAI, {&code[header.code_begin(0)], header.code_sizes[0]}); ASSERT_EQ(analysis.instrs.size(), 8); diff --git a/test/unittests/eof_test.cpp b/test/unittests/eof_test.cpp index f2daa7e292..e17e9aadd2 100644 --- a/test/unittests/eof_test.cpp +++ b/test/unittests/eof_test.cpp @@ -8,20 +8,20 @@ using namespace evmone; -TEST(eof, code_begin) -{ - EOF1Header header1{1, 0}; - EXPECT_EQ(header1.code_begin(), 7); - - EOF1Header header2{10, 0}; - EXPECT_EQ(header2.code_begin(), 7); - - EOF1Header header3{1, 1}; - EXPECT_EQ(header3.code_begin(), 10); - - EOF1Header header4{1, 10}; - EXPECT_EQ(header4.code_begin(), 10); -} +// TEST(eof, code_begin) +//{ +// EOF1Header header1{1, 0}; +// EXPECT_EQ(header1.code_begin(), 7); +// +// EOF1Header header2{10, 0}; +// EXPECT_EQ(header2.code_begin(), 7); +// +// EOF1Header header3{1, 1}; +// EXPECT_EQ(header3.code_begin(), 10); +// +// EOF1Header header4{1, 10}; +// EXPECT_EQ(header4.code_begin(), 10); +// } TEST(eof, is_eof_code) { @@ -59,7 +59,7 @@ TEST(eof, read_valid_eof1_header) { const auto code = from_spaced_hex(test_case.code).value(); const auto header = read_valid_eof1_header(bytes_view(code).begin()); - EXPECT_EQ(header.code_size, test_case.code_size) << test_case.code; + EXPECT_EQ(header.code_sizes[0], test_case.code_size) << test_case.code; EXPECT_EQ(header.data_size, test_case.data_size) << test_case.code; } } diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 79582fbd3c..ecf5b3ed5e 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -77,7 +77,7 @@ TEST(eof_validation, minimal_valid_EOF1_code_with_data) TEST(eof_validation, EOF1_code_section_missing) { EXPECT_EQ(validate_eof("EF0001 00"), EOFValidationError::code_section_missing); - EXPECT_EQ(validate_eof("EF0001 020001 DA"), EOFValidationError::code_section_missing); + EXPECT_EQ(validate_eof("EF0001 020001 00 DA"), EOFValidationError::code_section_missing); } TEST(eof_validation, EOF1_code_section_0_size) @@ -91,18 +91,19 @@ TEST(eof_validation, EOF1_data_section_0_size) EXPECT_EQ(validate_eof("EF0001 010001 020000 00 FE"), EOFValidationError::zero_section_size); } -TEST(eof_validation, EOF1_multiple_code_sections) -{ - EXPECT_EQ( - validate_eof("EF0001 010001 010001 00 FE FE"), EOFValidationError::multiple_code_sections); - EXPECT_EQ(validate_eof("EF0001 010001 010001 020001 00 FE FE DA"), - EOFValidationError::multiple_code_sections); -} +// TEST(eof_validation, EOF1_multiple_code_sections) +//{ +// EXPECT_EQ( +// validate_eof("EF0001 010001 010001 00 FE FE"), +// EOFValidationError::multiple_code_sections); +// EXPECT_EQ(validate_eof("EF0001 010001 010001 020001 00 FE FE DA"), +// EOFValidationError::multiple_code_sections); +// } TEST(eof_validation, EOF1_data_section_before_code_section) { - EXPECT_EQ( - validate_eof("EF0001 020001 010001 00 AA FE"), EOFValidationError::code_section_missing); + EXPECT_EQ(validate_eof("EF0001 020001 010001 00 AA FE"), + EOFValidationError::data_section_before_code_section); } TEST(eof_validation, EOF1_multiple_data_sections) @@ -113,13 +114,13 @@ TEST(eof_validation, EOF1_multiple_data_sections) TEST(eof_validation, EOF1_unknown_section) { - EXPECT_EQ(validate_eof("EF0001 030001 00 FE"), EOFValidationError::unknown_section_id); + EXPECT_EQ(validate_eof("EF0001 040001 00 FE"), EOFValidationError::unknown_section_id); EXPECT_EQ(validate_eof("EF0001 FF0001 00 FE"), EOFValidationError::unknown_section_id); EXPECT_EQ( - validate_eof("EF0001 010001 030001 00 FE 00"), EOFValidationError::unknown_section_id); + validate_eof("EF0001 010001 040001 00 FE 00"), EOFValidationError::unknown_section_id); EXPECT_EQ( validate_eof("EF0001 010001 FF0001 00 FE 00"), EOFValidationError::unknown_section_id); - EXPECT_EQ(validate_eof("EF0001 010001 020001 030001 00 FE AA 00"), + EXPECT_EQ(validate_eof("EF0001 010001 020001 040001 00 FE AA 00"), EOFValidationError::unknown_section_id); EXPECT_EQ(validate_eof("EF0001 010001 020001 FF0001 00 FE AA 00"), EOFValidationError::unknown_section_id); @@ -152,6 +153,20 @@ TEST(eof_validation, EOF1_truncated_section) EOFValidationError::invalid_section_bodies_size); } +TEST(eof_validation, EOF1_code_section_offset) +{ + const auto eof = "EF0001 030004 010002 010001 00 0000 0000 fefe fe"_hex; + ASSERT_EQ(validate_eof(EVMC_CANCUN, eof), EOFValidationError::success); + + const auto header = read_valid_eof1_header(eof); + ASSERT_EQ(header.code_sizes.size(), 2); + EXPECT_EQ(header.code_sizes[0], 2); + EXPECT_EQ(header.code_sizes[1], 1); + ASSERT_EQ(header.code_offsets.size(), 2); + EXPECT_EQ(header.code_offsets[0], 17); + EXPECT_EQ(header.code_offsets[1], 19); +} + TEST(eof_validation, EOF1_trailing_bytes) { EXPECT_EQ(validate_eof("EF0001 010001 00 FE DEADBEEF"), From 18f36e453a94f3d363d549d82518ac8da774e24b Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 6 Dec 2022 19:59:56 +0100 Subject: [PATCH 32/72] test: Add EOF functions example test --- lib/evmone/eof.cpp | 2 +- test/unittests/evm_eof_test.cpp | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index caf461f102..909aedd738 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -226,7 +226,7 @@ std::pair validate_eof1( const auto header_size = eof_header_size(section_headers); std::vector code_offsets; - auto offset = header_size; + auto offset = header_size + (section_headers.empty() ? 0 : section_headers[TYPE_SECTION][0]); for (const auto code_size : code_sizes) { code_offsets.emplace_back(offset); diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index a921316cdb..a723bf2323 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "evm_fixture.hpp" +#include "evmone/eof.hpp" using evmone::test::evm; @@ -361,3 +362,23 @@ TEST_P(evm, relative_jumps_undefined_in_legacy) execute(code); EXPECT_STATUS(EVMC_UNDEFINED_INSTRUCTION); } + +TEST_P(evm, eof_function_example1) +{ + // Relative jumps are not implemented in Advanced. + if (isAdvanced()) + return; + + rev = EVMC_SHANGHAI; + const auto code = + "EF00 01 030004 01000f 010002 00" + "0000 0201" + "6001 6008 b00001 " + + ret_top() + "03b1"; + + ASSERT_EQ((int)evmone::validate_eof(rev, code), (int)evmone::EOFValidationError{}); + + execute(code); + EXPECT_GAS_USED(EVMC_SUCCESS, 32); + EXPECT_OUTPUT_INT(7); +} From 7619e3031276d7e311c8d5e6c28d4778ed8ae856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Sep 2022 16:39:30 +0200 Subject: [PATCH 33/72] Fix EOF validation with type section --- lib/evmone/eof.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 909aedd738..69befd55b2 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -225,19 +225,21 @@ std::pair validate_eof1( const auto header_size = eof_header_size(section_headers); + const auto [types, error_types] = + validate_types(container, header_size, section_headers[TYPE_SECTION]); + if (error_types != EOFValidationError::success) + return {{}, error_types}; + std::vector code_offsets; - auto offset = header_size + (section_headers.empty() ? 0 : section_headers[TYPE_SECTION][0]); + const auto type_section_size = + section_headers[TYPE_SECTION].empty() ? 0u : section_headers[TYPE_SECTION][0]; + auto offset = header_size + type_section_size; for (const auto code_size : code_sizes) { code_offsets.emplace_back(offset); offset += code_size; } - const auto [types, error_types] = - validate_types(container, eof_header_size(section_headers), section_headers[TYPE_SECTION]); - if (error_types != EOFValidationError::success) - return {{}, error_types}; - EOF1Header header{code_sizes, code_offsets, data_size, types}; for (size_t code_idx = 0; code_idx < header.code_sizes.size(); ++code_idx) From 392bb44d23d842d29e41fd80ebb5e88faef1eec8 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Wed, 7 Dec 2022 11:32:09 +0100 Subject: [PATCH 34/72] Implement CALLF/RETF --- lib/evmone/advanced_instructions.cpp | 2 ++ lib/evmone/baseline.hpp | 1 + lib/evmone/execution_state.hpp | 2 ++ lib/evmone/instructions.hpp | 16 ++++++++++++++++ lib/evmone/instructions_xmacro.hpp | 4 ++-- 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/evmone/advanced_instructions.cpp b/lib/evmone/advanced_instructions.cpp index 923152608a..1a942b964f 100644 --- a/lib/evmone/advanced_instructions.cpp +++ b/lib/evmone/advanced_instructions.cpp @@ -247,6 +247,8 @@ constexpr std::array instruction_implementations = []( table[OP_RJUMP] = op_undefined; table[OP_RJUMPI] = op_undefined; + table[OP_CALLF] = op_undefined; + table[OP_RETF] = op_undefined; table[OP_DUPN] = op_undefined; table[OP_SWAPN] = op_undefined; diff --git a/lib/evmone/baseline.hpp b/lib/evmone/baseline.hpp index eb16ddfb61..692c4d416d 100644 --- a/lib/evmone/baseline.hpp +++ b/lib/evmone/baseline.hpp @@ -26,6 +26,7 @@ class CodeAnalysis bytes_view executable_code; ///< Executable code section. JumpdestMap jumpdest_map; ///< Map of valid jump destinations. uint8_t eof_version = 0; ///< The EOF version, 0 means legacy code. + std::vector code_offsets; private: /// Padded code for faster legacy code execution. diff --git a/lib/evmone/execution_state.hpp b/lib/evmone/execution_state.hpp index c212da8809..8aa54353ca 100644 --- a/lib/evmone/execution_state.hpp +++ b/lib/evmone/execution_state.hpp @@ -154,6 +154,8 @@ class ExecutionState const advanced::AdvancedCodeAnalysis* advanced; } analysis{}; + std::vector call_stack; + /// Stack space allocation. /// /// This is the last field to make other fields' offsets of reasonable values. diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index ccc6f13e9b..87998e46f9 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -913,6 +913,22 @@ evmc_status_code create_impl(StackTop stack, ExecutionState& state) noexcept; inline constexpr auto create = create_impl; inline constexpr auto create2 = create_impl; +inline code_iterator callf(StackTop /*stack*/, ExecutionState& state, code_iterator pos) noexcept +{ + const auto index = (size_t{pos[1]} << 8) | pos[2]; + state.call_stack.push_back(pos + 3); + const auto offset = state.analysis.baseline->code_offsets[index]; + auto code = state.analysis.baseline->executable_code; + return code + offset; +} + +inline code_iterator retf(StackTop /*stack*/, ExecutionState& state, code_iterator /*pos*/) noexcept +{ + const auto p = state.call_stack.back(); + state.call_stack.pop_back(); + return p; +} + template inline StopToken return_impl(StackTop stack, ExecutionState& state) noexcept { diff --git a/lib/evmone/instructions_xmacro.hpp b/lib/evmone/instructions_xmacro.hpp index 7591211b5e..b411206497 100644 --- a/lib/evmone/instructions_xmacro.hpp +++ b/lib/evmone/instructions_xmacro.hpp @@ -219,8 +219,8 @@ ON_OPCODE_UNDEFINED(0xae) \ ON_OPCODE_UNDEFINED(0xaf) \ \ - ON_OPCODE_UNDEFINED(0xb0) \ - ON_OPCODE_UNDEFINED(0xb1) \ + ON_OPCODE_IDENTIFIER(OP_CALLF, callf) \ + ON_OPCODE_IDENTIFIER(OP_RETF, retf) \ ON_OPCODE_UNDEFINED(0xb2) \ ON_OPCODE_UNDEFINED(0xb3) \ ON_OPCODE_UNDEFINED(0xb4) \ From f072bf3661d6cf7ca1cda6f0c043e6c3c2314272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Sep 2022 16:18:34 +0200 Subject: [PATCH 35/72] Pass all code sections as executable code --- lib/evmone/baseline.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/evmone/baseline.cpp b/lib/evmone/baseline.cpp index 007f72bd50..6fd2972432 100644 --- a/lib/evmone/baseline.cpp +++ b/lib/evmone/baseline.cpp @@ -69,10 +69,20 @@ CodeAnalysis analyze_legacy(bytes_view code) CodeAnalysis analyze_eof1(bytes_view eof_container, const EOF1Header& header) { - const auto executable_code = eof_container.substr(header.code_begin(0), header.code_sizes[0]); + auto beg = header.code_begin(0); + auto end = header.code_end(header.code_sizes.size() - 1); + const auto executable_code = eof_container.substr(beg, end - beg); + + const auto o = header.code_offsets[0]; + std::vector offs; + for (auto x : header.code_offsets) + offs.push_back(x - o); // FIXME: Better way of getting EOF version. - return {executable_code, analyze_jumpdests(executable_code), eof_container[2]}; + auto a = + CodeAnalysis{executable_code.data(), analyze_jumpdests(executable_code), eof_container[2]}; + a.code_offsets = std::move(offs); + return a; } } // namespace From 0a46f69d4a284523d2a2967c54e352db2acb3d72 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 6 Dec 2022 20:03:20 +0100 Subject: [PATCH 36/72] Add unit test with big example --- test/unittests/evm_eof_test.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index a723bf2323..1f3c701684 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -382,3 +382,34 @@ TEST_P(evm, eof_function_example1) EXPECT_GAS_USED(EVMC_SUCCESS, 32); EXPECT_OUTPUT_INT(7); } + +TEST_P(evm, eof_function_example2) +{ + // Relative jumps are not implemented in Advanced. + if (isAdvanced()) + return; + + rev = EVMC_SHANGHAI; + const auto code = + "ef0001 030006 01003b 010017 01001d 00 000001010101" + "60043560003560e01c63c766526781145d001c63c6c2ea1781145d00065050600080fd50b00002600052602060" + "00f350b0000160005260206000f3" + "600181115d0004506001b160018103b0000181029050b1" + "600281115d0004506001b160028103b0000260018203b00002019050b1"_hex; + + ASSERT_EQ((int)evmone::validate_eof(rev, code), (int)evmone::EOFValidationError{}); + + // Call fac(5) + const auto calldata_fac = + "c76652670000000000000000000000000000000000000000000000000000000000000005"_hex; + execute(bytecode{code}, calldata_fac); + EXPECT_GAS_USED(EVMC_SUCCESS, 246); + EXPECT_EQ(output, "0000000000000000000000000000000000000000000000000000000000000078"_hex); + + // Call fib(15) + const auto calldata_fib = + "c6c2ea17000000000000000000000000000000000000000000000000000000000000000f"_hex; + execute(bytecode{code}, calldata_fib); + EXPECT_GAS_USED(EVMC_SUCCESS, 44544); + EXPECT_EQ(output, "0000000000000000000000000000000000000000000000000000000000000262"_hex); +} From eb6fec587e7aea2e00d0888de48b8a53587d30f9 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Thu, 29 Sep 2022 18:46:57 +0200 Subject: [PATCH 37/72] Fix typo --- lib/evmone/eof.cpp | 2 +- lib/evmone/eof.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 69befd55b2..e8373f0e61 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -148,7 +148,7 @@ std::pair>, EOFValidationError> validate // check 1st section is (0, 0) if (types[0].first != 0 || types[0].second != 0) - return {{}, EOFValidationError::invalid_fist_section_type}; + return {{}, EOFValidationError::invalid_first_section_type}; return {types, EOFValidationError::success}; } diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index c1206e8bca..8c8ec5d765 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -60,7 +60,7 @@ enum class EOFValidationError too_many_code_sections, data_section_before_code_section, invalid_type_section_size, - invalid_fist_section_type, + invalid_first_section_type, impossible, }; From 1b18fca6a755fd4986d55e708195eeb340cb6758 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Thu, 29 Sep 2022 18:47:26 +0200 Subject: [PATCH 38/72] Add more validation unit tests --- test/unittests/eof_validation_test.cpp | 98 +++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 9 deletions(-) diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index ecf5b3ed5e..3b116c23a1 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -74,6 +74,31 @@ TEST(eof_validation, minimal_valid_EOF1_code_with_data) EXPECT_EQ(validate_eof("EF0001 010001 020001 00 FE DA"), EOFValidationError::success); } +TEST(eof_validation, minimal_valid_EOF1_code_with_type) +{ + // no data section + EXPECT_EQ(validate_eof("EF0001 030002 01000100 0000 FE"), EOFValidationError::success); + // with data section + EXPECT_EQ( + validate_eof("EF0001 030002 010001 020001 00 0000 FE DA"), EOFValidationError::success); +} + +TEST(eof_validation, minimal_valid_EOF1_multiple_code_sections) +{ + // no data section + EXPECT_EQ( + validate_eof("EF0001 030004 010001 010001 00 00000000 FE FE"), EOFValidationError::success); + // with data section + EXPECT_EQ(validate_eof("EF0001 030004 010001 010001 020001 00 00000000 FE FE DA"), + EOFValidationError::success); + + // non-void input and output types + EXPECT_EQ( + validate_eof( + "EF0001 030008 010001 010002 010002 010002 00 0000010000010203 FE 5000 3000 8000"), + EOFValidationError::success); +} + TEST(eof_validation, EOF1_code_section_missing) { EXPECT_EQ(validate_eof("EF0001 00"), EOFValidationError::code_section_missing); @@ -91,15 +116,6 @@ TEST(eof_validation, EOF1_data_section_0_size) EXPECT_EQ(validate_eof("EF0001 010001 020000 00 FE"), EOFValidationError::zero_section_size); } -// TEST(eof_validation, EOF1_multiple_code_sections) -//{ -// EXPECT_EQ( -// validate_eof("EF0001 010001 010001 00 FE FE"), -// EOFValidationError::multiple_code_sections); -// EXPECT_EQ(validate_eof("EF0001 010001 010001 020001 00 FE FE DA"), -// EOFValidationError::multiple_code_sections); -// } - TEST(eof_validation, EOF1_data_section_before_code_section) { EXPECT_EQ(validate_eof("EF0001 020001 010001 00 AA FE"), @@ -175,6 +191,70 @@ TEST(eof_validation, EOF1_trailing_bytes) EOFValidationError::invalid_section_bodies_size); } +TEST(eof_validation, EOF1_no_type_section) +{ + EXPECT_EQ(validate_eof("EF0001 010001 010001 00 FE FE"), + EOFValidationError::mandatory_type_section_missing); +} + +TEST(eof_validation, EOF1_multiple_type_sections) +{ + EXPECT_EQ(validate_eof("EF0001 030002 030002 010001 010001 00 0000 0000 FE FE"), + EOFValidationError::multiple_type_sections); + + EXPECT_EQ(validate_eof("EF0001 030002 010001 010001 030002 00 0000 FE FE 0000"), + EOFValidationError::multiple_type_sections); +} + +TEST(eof_validation, EOF1_type_section_not_first) +{ + EXPECT_EQ(validate_eof("EF0001 010001 030002 00 FE 0000"), + EOFValidationError::code_section_before_type_section); + + EXPECT_EQ(validate_eof("EF0001 010001 030002 010001 00 FE 0000 FE"), + EOFValidationError::code_section_before_type_section); + + EXPECT_EQ(validate_eof("EF0001 010001 030002 020003 00 FE 0000 AABBCC"), + EOFValidationError::code_section_before_type_section); + + EXPECT_EQ(validate_eof("EF0001 010001 020003 030002 00 FE AABBCC 0000"), + EOFValidationError::code_section_before_type_section); +} + +TEST(eof_validation, EOF1_invalid_type_section_size) +{ + EXPECT_EQ(validate_eof("EF0001 030001 010001 00 00 FE"), + EOFValidationError::invalid_type_section_size); + EXPECT_EQ(validate_eof("EF0001 030004 010001 00 00000000 FE"), + EOFValidationError::invalid_type_section_size); + + EXPECT_EQ(validate_eof("EF0001 030004 010001 010001 010001 00 00000000 FE FE FE"), + EOFValidationError::invalid_type_section_size); + EXPECT_EQ(validate_eof("EF0001 030008 010001 010001 010001 00 0000000000000000 FE FE FE"), + EOFValidationError::invalid_type_section_size); +} + +TEST(eof_validation, EOF1_invalid_section_0_type) +{ + EXPECT_EQ(validate_eof("EF0001 030002 010003 00 0001 60005C"), + EOFValidationError::invalid_first_section_type); + EXPECT_EQ(validate_eof("EF0001 030002 010002 00 0100 5000"), + EOFValidationError::invalid_first_section_type); + EXPECT_EQ(validate_eof("EF0001 030002 010003 00 0203 60005C"), + EOFValidationError::invalid_first_section_type); +} + +TEST(eof_validation, EOF1_too_many_code_sections) +{ + const auto valid = "EF0001 030800" + 1024 * bytecode{"010001"} + "00" + + 1024 * bytecode{"0000"} + 1024 * bytecode{"FE"}; + EXPECT_EQ(validate_eof(valid), EOFValidationError::success); + + const auto invalid = "EF0001 030801" + 1025 * bytecode{"010001"} + "00" + + 1025 * bytecode{"0000"} + 1025 * bytecode{"FE"}; + EXPECT_EQ(validate_eof(invalid), EOFValidationError::too_many_code_sections); +} + TEST(eof_validation, EOF1_undefined_opcodes) { auto cont = "EF0001 010002 00 0000"_hex; From 955038fb43dd631ff3a29b824d2cdf76c6875063 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Mon, 19 Dec 2022 12:34:54 +0100 Subject: [PATCH 39/72] Fix building after rebasing --- lib/evmone/baseline.cpp | 3 +-- lib/evmone/instructions.hpp | 2 +- test/unittests/evm_eof_test.cpp | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/evmone/baseline.cpp b/lib/evmone/baseline.cpp index 6fd2972432..029093072e 100644 --- a/lib/evmone/baseline.cpp +++ b/lib/evmone/baseline.cpp @@ -79,8 +79,7 @@ CodeAnalysis analyze_eof1(bytes_view eof_container, const EOF1Header& header) offs.push_back(x - o); // FIXME: Better way of getting EOF version. - auto a = - CodeAnalysis{executable_code.data(), analyze_jumpdests(executable_code), eof_container[2]}; + auto a = CodeAnalysis{executable_code, analyze_jumpdests(executable_code), eof_container[2]}; a.code_offsets = std::move(offs); return a; } diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index 87998e46f9..4afc632b57 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -919,7 +919,7 @@ inline code_iterator callf(StackTop /*stack*/, ExecutionState& state, code_itera state.call_stack.push_back(pos + 3); const auto offset = state.analysis.baseline->code_offsets[index]; auto code = state.analysis.baseline->executable_code; - return code + offset; + return code.data() + offset; } inline code_iterator retf(StackTop /*stack*/, ExecutionState& state, code_iterator /*pos*/) noexcept diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 1f3c701684..f9dadcfd99 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -366,7 +366,7 @@ TEST_P(evm, relative_jumps_undefined_in_legacy) TEST_P(evm, eof_function_example1) { // Relative jumps are not implemented in Advanced. - if (isAdvanced()) + if (is_advanced()) return; rev = EVMC_SHANGHAI; @@ -386,7 +386,7 @@ TEST_P(evm, eof_function_example1) TEST_P(evm, eof_function_example2) { // Relative jumps are not implemented in Advanced. - if (isAdvanced()) + if (is_advanced()) return; rev = EVMC_SHANGHAI; From 166dbf0d8439ae087746cdd239030b67402ebdd2 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Mon, 19 Dec 2022 14:18:16 +0100 Subject: [PATCH 40/72] Fix Windows build --- lib/evmone/advanced_execution.cpp | 2 +- lib/evmone/baseline.cpp | 2 +- lib/evmone/eof.cpp | 4 ++-- test/unittests/analysis_test.cpp | 2 +- test/unittests/eof_test.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/evmone/advanced_execution.cpp b/lib/evmone/advanced_execution.cpp index 2973efc6af..48cd5b4086 100644 --- a/lib/evmone/advanced_execution.cpp +++ b/lib/evmone/advanced_execution.cpp @@ -35,7 +35,7 @@ evmc_result execute(evmc_vm* /*unused*/, const evmc_host_interface* host, evmc_h { if (rev >= EVMC_SHANGHAI) { - const auto eof1_header = read_valid_eof1_header(container.begin()); + const auto eof1_header = read_valid_eof1_header(container); analysis = analyze(rev, {&container[eof1_header.code_begin(0)], eof1_header.code_sizes[0]}); } diff --git a/lib/evmone/baseline.cpp b/lib/evmone/baseline.cpp index 029093072e..e4d0cd244d 100644 --- a/lib/evmone/baseline.cpp +++ b/lib/evmone/baseline.cpp @@ -90,7 +90,7 @@ CodeAnalysis analyze(evmc_revision rev, bytes_view code) if (rev < EVMC_SHANGHAI || !is_eof_code(code)) return analyze_legacy(code); - const auto eof1_header = read_valid_eof1_header(code.begin()); + const auto eof1_header = read_valid_eof1_header(code); return analyze_eof1(code, eof1_header); } diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index e8373f0e61..57682a7968 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -236,7 +236,7 @@ std::pair validate_eof1( auto offset = header_size + type_section_size; for (const auto code_size : code_sizes) { - code_offsets.emplace_back(offset); + code_offsets.emplace_back(static_cast(offset)); offset += code_size; } @@ -308,7 +308,7 @@ EOF1Header read_valid_eof1_header(bytes_view container) (section_headers[TYPE_SECTION].empty() ? uint16_t{0} : section_headers[TYPE_SECTION][0]); for (const auto code_size : header.code_sizes) { - header.code_offsets.emplace_back(code_offset); + header.code_offsets.emplace_back(static_cast(code_offset)); code_offset += code_size; } diff --git a/test/unittests/analysis_test.cpp b/test/unittests/analysis_test.cpp index 3684218635..ab39482819 100644 --- a/test/unittests/analysis_test.cpp +++ b/test/unittests/analysis_test.cpp @@ -260,7 +260,7 @@ TEST(analysis, example1_eof1) { const auto code = eof1_bytecode( push(0x2a) + push(0x1e) + OP_MSTORE8 + OP_MSIZE + push(0) + OP_SSTORE, "deadbeef"); - const auto header = evmone::read_valid_eof1_header(bytes_view(code).begin()); + const auto header = evmone::read_valid_eof1_header(bytes_view(code)); const auto analysis = analyze(EVMC_SHANGHAI, {&code[header.code_begin(0)], header.code_sizes[0]}); diff --git a/test/unittests/eof_test.cpp b/test/unittests/eof_test.cpp index e17e9aadd2..7ecb14e52b 100644 --- a/test/unittests/eof_test.cpp +++ b/test/unittests/eof_test.cpp @@ -58,7 +58,7 @@ TEST(eof, read_valid_eof1_header) for (const auto& test_case : test_cases) { const auto code = from_spaced_hex(test_case.code).value(); - const auto header = read_valid_eof1_header(bytes_view(code).begin()); + const auto header = read_valid_eof1_header(bytes_view(code)); EXPECT_EQ(header.code_sizes[0], test_case.code_size) << test_case.code; EXPECT_EQ(header.data_size, test_case.data_size) << test_case.code; } From 75a38b25f443e9936b135884aad85d8e851b675a Mon Sep 17 00:00:00 2001 From: rodiazet Date: Mon, 19 Dec 2022 14:43:02 +0100 Subject: [PATCH 41/72] Bump stack usage --- lib/evmone/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/evmone/CMakeLists.txt b/lib/evmone/CMakeLists.txt index 861f418e25..c16d1ad1e0 100644 --- a/lib/evmone/CMakeLists.txt +++ b/lib/evmone/CMakeLists.txt @@ -42,7 +42,7 @@ if(CABLE_COMPILER_GNULIKE) target_compile_options( evmone PRIVATE -fno-exceptions - $<$:-Wstack-usage=2500> + $<$:-Wstack-usage=2600> ) if(NOT SANITIZE MATCHES undefined) # RTTI can be disabled except for UBSan which checks vptr integrity. From e463a46711df87ac2d2464afafa58534aa5b1342 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Mon, 19 Dec 2022 23:58:37 +0100 Subject: [PATCH 42/72] Implement EOF functions according to the newest unified spec --- lib/evmone/eof.cpp | 102 ++++++++++++++++++++++---------- lib/evmone/eof.hpp | 15 ++++- test/unittests/evm_eof_test.cpp | 6 +- 3 files changed, 89 insertions(+), 34 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 57682a7968..4e425d9f81 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -17,23 +17,26 @@ namespace { constexpr uint8_t MAGIC[] = {0xef, 0x00}; constexpr uint8_t TERMINATOR = 0x00; -constexpr uint8_t CODE_SECTION = 0x01; -constexpr uint8_t DATA_SECTION = 0x02; -constexpr uint8_t TYPE_SECTION = 0x03; -constexpr uint8_t MAX_SECTION = TYPE_SECTION; +constexpr uint8_t TYPE_SECTION = 0x01; +constexpr uint8_t CODE_SECTION = 0x02; +constexpr uint8_t DATA_SECTION = 0x03; +constexpr uint8_t MAX_SECTION = DATA_SECTION; constexpr auto CODE_SECTION_NUMBER_LIMIT = 1024; +constexpr auto MAX_STACK_HEIGHT = 0x0400; using EOFSectionHeaders = std::array, MAX_SECTION + 1>; size_t eof_header_size(const EOFSectionHeaders& headers) noexcept { - const auto section_count = - headers[TYPE_SECTION].size() + headers[CODE_SECTION].size() + headers[DATA_SECTION].size(); + const auto non_code_section_count = headers[TYPE_SECTION].size() + headers[DATA_SECTION].size(); + const auto code_section_count = headers[CODE_SECTION].size(); - constexpr auto section_header_size = 3; // (SECTION_ID + SIZE) per each section + constexpr auto non_code_section_header_size = 3; // (SECTION_ID + SIZE) per each section + constexpr auto code_section_size_size = 2; return sizeof(MAGIC) + 1 + // 1 version byte - section_count * section_header_size + sizeof(TERMINATOR); + non_code_section_count * non_code_section_header_size + sizeof(CODE_SECTION) + 2 + + code_section_count * code_section_size_size + sizeof(TERMINATOR); } std::pair validate_eof_headers(bytes_view container) @@ -47,6 +50,7 @@ std::pair validate_eof_headers(bytes_view auto state = State::section_id; uint8_t section_id = 0; + uint16_t section_num = 0; EOFSectionHeaders section_headers{}; const auto container_end = container.end(); auto it = container.begin() + std::size(MAGIC) + 1; // MAGIC + VERSION @@ -80,12 +84,19 @@ std::pair validate_eof_headers(bytes_view state = State::section_size; break; case CODE_SECTION: + { if (section_headers[CODE_SECTION].size() == CODE_SECTION_NUMBER_LIMIT) return {{}, EOFValidationError::too_many_code_sections}; if (!section_headers[DATA_SECTION].empty()) return {{}, EOFValidationError::data_section_before_code_section}; + const auto section_number_hi = *it++; + if (it == container_end) + return {{}, EOFValidationError::incomplete_section_number}; + const auto section_number_lo = *it++; + section_num = static_cast((section_number_hi << 8) | section_number_lo); state = State::section_size; break; + } default: return {{}, EOFValidationError::unknown_section_id}; } @@ -93,15 +104,19 @@ std::pair validate_eof_headers(bytes_view } case State::section_size: { - const auto size_hi = *it++; - if (it == container_end) - return {{}, EOFValidationError::incomplete_section_size}; - const auto size_lo = *it++; - const auto section_size = static_cast((size_hi << 8) | size_lo); - if (section_size == 0) - return {{}, EOFValidationError::zero_section_size}; + for (size_t i = 0; i < (section_id == CODE_SECTION ? section_num : 1); ++i) + { + const auto size_hi = *it++; + if (it == container_end) + return {{}, EOFValidationError::incomplete_section_size}; + const auto size_lo = *it++; + const auto section_size = static_cast((size_hi << 8) | size_lo); + if (section_size == 0) + return {{}, EOFValidationError::zero_section_size}; + + section_headers[section_id].emplace_back(section_size); + } - section_headers[section_id].emplace_back(section_size); state = State::section_id; break; } @@ -123,33 +138,39 @@ std::pair validate_eof_headers(bytes_view return {{}, EOFValidationError::invalid_section_bodies_size}; if (!section_headers[TYPE_SECTION].empty() && - section_headers[TYPE_SECTION][0] != section_headers[CODE_SECTION].size() * 2) + section_headers[TYPE_SECTION][0] != section_headers[CODE_SECTION].size() * 4) return {{}, EOFValidationError::invalid_type_section_size}; return {section_headers, EOFValidationError::success}; } -std::pair>, EOFValidationError> validate_types( +std::pair, EOFValidationError> validate_types( bytes_view container, size_t header_size, std::vector type_section_sizes) noexcept { assert(!container.empty()); // guaranteed by EOF headers validation assert(type_section_sizes.size() <= 1); // guaranteed by EOF headers validation if (type_section_sizes.empty()) - return {{{0, 0}}, EOFValidationError::success}; + return {{{0, 0, 0}}, EOFValidationError::success}; - std::vector> types; + std::vector types; // guaranteed by EOF headers validation assert(header_size + type_section_sizes[0] < container.size()); - for (auto offset = header_size; offset < header_size + type_section_sizes[0]; offset += 2) - types.emplace_back(container[offset], container[offset + 1]); + for (auto offset = header_size; offset < header_size + type_section_sizes[0]; offset += 4) + { + types.emplace_back(EOF1TypeHeader{container[offset], container[offset + 1], + static_cast(container[offset + 2] << 8 | container[offset + 3])}); + } // check 1st section is (0, 0) - if (types[0].first != 0 || types[0].second != 0) + if (types[0].inputs_num != 0 || types[0].outputs_num != 0) return {{}, EOFValidationError::invalid_first_section_type}; + if (types[0].max_stack_height > MAX_STACK_HEIGHT) + return {{}, EOFValidationError::invalid_max_stack_height}; + return {types, EOFValidationError::success}; } @@ -283,22 +304,43 @@ EOF1Header read_valid_eof1_header(bytes_view container) while (*it != TERMINATOR) { const auto section_id = *it++; - const auto section_size_hi = *it++; - const auto section_size_lo = *it++; - const auto section_size = static_cast((section_size_hi << 8) | section_size_lo); - section_headers[section_id].emplace_back(section_size); + if (section_id == CODE_SECTION) + { + const auto code_section_num_hi = *it++; + const auto code_section_num_lo = *it++; + const auto code_section_num = + static_cast((code_section_num_hi << 8) | code_section_num_lo); + for (uint16_t i = 0; i < code_section_num; ++i) + { + const auto section_size_hi = *it++; + const auto section_size_lo = *it++; + const auto section_size = + static_cast((section_size_hi << 8) | section_size_lo); + section_headers[section_id].emplace_back(section_size); + } + } + else + { + const auto section_size_hi = *it++; + const auto section_size_lo = *it++; + const auto section_size = + static_cast((section_size_hi << 8) | section_size_lo); + section_headers[section_id].emplace_back(section_size); + } } const auto header_size = eof_header_size(section_headers); EOF1Header header; if (section_headers[TYPE_SECTION].empty()) - header.types.emplace_back(0, 0); + header.types.emplace_back(0, 0, 0); else { for (auto type_offset = header_size; - type_offset < header_size + section_headers[TYPE_SECTION][0]; type_offset += 2) - header.types.emplace_back(container[type_offset], container[type_offset + 1]); + type_offset < header_size + section_headers[TYPE_SECTION][0]; type_offset += 4) + + header.types.emplace_back(container[type_offset], container[type_offset + 1], + container[type_offset + 2] << 8 | container[type_offset + 3]); } header.code_sizes = section_headers[CODE_SECTION]; diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index 8c8ec5d765..beef7d7d68 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -14,6 +14,17 @@ namespace evmone { using bytes_view = std::basic_string_view; +struct EOF1TypeHeader +{ + uint8_t inputs_num; + uint8_t outputs_num; + uint16_t max_stack_height; + + EOF1TypeHeader(uint8_t inputs_num_, uint8_t outputs_num_, uint16_t max_stack_height_) + : inputs_num(inputs_num_), outputs_num(outputs_num_), max_stack_height(max_stack_height_) + {} +}; + struct EOF1Header { /// Size of every code section. @@ -22,7 +33,7 @@ struct EOF1Header std::vector code_offsets; uint16_t data_size = 0; - std::vector> types; + std::vector types; /// Returns offset of code section start. [[nodiscard]] EVMC_EXPORT size_t code_begin(size_t index) const noexcept; @@ -45,6 +56,7 @@ enum class EOFValidationError eof_version_unknown, incomplete_section_size, + incomplete_section_number, code_section_missing, multiple_data_sections, unknown_section_id, @@ -61,6 +73,7 @@ enum class EOFValidationError data_section_before_code_section, invalid_type_section_size, invalid_first_section_type, + invalid_max_stack_height, impossible, }; diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index f9dadcfd99..92429438c6 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -371,8 +371,8 @@ TEST_P(evm, eof_function_example1) rev = EVMC_SHANGHAI; const auto code = - "EF00 01 030004 01000f 010002 00" - "0000 0201" + "EF00 01 010008 020002 000f 0002 00" + "00000005 02010000" "6001 6008 b00001 " + ret_top() + "03b1"; @@ -391,7 +391,7 @@ TEST_P(evm, eof_function_example2) rev = EVMC_SHANGHAI; const auto code = - "ef0001 030006 01003b 010017 01001d 00 000001010101" + "ef0001 01000c 020003 003b 0017 001d 00 00000400 01010400 01010400" "60043560003560e01c63c766526781145d001c63c6c2ea1781145d00065050600080fd50b00002600052602060" "00f350b0000160005260206000f3" "600181115d0004506001b160018103b0000181029050b1" From 3bdacd85527f2ddb0be982ac55a2ec184f519f29 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Tue, 20 Dec 2022 17:07:27 +0100 Subject: [PATCH 43/72] Update unit tests to reflect the unified spec. --- lib/evmone/eof.hpp | 2 + test/unittests/eof_test.cpp | 16 +- test/unittests/eof_validation_test.cpp | 207 ++++++++++++++----------- 3 files changed, 127 insertions(+), 98 deletions(-) diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index beef7d7d68..c646a2beed 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -58,6 +58,7 @@ enum class EOFValidationError incomplete_section_size, incomplete_section_number, code_section_missing, + type_section_missing, multiple_data_sections, unknown_section_id, zero_section_size, @@ -71,6 +72,7 @@ enum class EOFValidationError mandatory_type_section_missing, too_many_code_sections, data_section_before_code_section, + data_section_before_types_section, invalid_type_section_size, invalid_first_section_type, invalid_max_stack_height, diff --git a/test/unittests/eof_test.cpp b/test/unittests/eof_test.cpp index 7ecb14e52b..e9ef27c080 100644 --- a/test/unittests/eof_test.cpp +++ b/test/unittests/eof_test.cpp @@ -34,8 +34,8 @@ TEST(eof, is_eof_code) EXPECT_FALSE(is_eof_code("FE"_hex)); EXPECT_TRUE(is_eof_code("EF00"_hex)); - EXPECT_TRUE(is_eof_code("EF00 01 010001 00 00"_hex)); - EXPECT_TRUE(is_eof_code("EF00 01 010001 020004 00 00 AABBCCDD"_hex)); + EXPECT_TRUE(is_eof_code("EF00 01 010004 0200010001 00 00000000 00"_hex)); + EXPECT_TRUE(is_eof_code("EF00 01 010004 0200010001 030004 00 00000000 00 AABBCCDD"_hex)); EXPECT_TRUE(is_eof_code("EF00 02 ABCFEF"_hex)); } @@ -44,15 +44,16 @@ TEST(eof, read_valid_eof1_header) struct TestCase { std::string code; + uint16_t types_size; uint16_t code_size; uint16_t data_size; }; const TestCase test_cases[] = { - {"EF00 01 010001 00 00", 1, 0}, - {"EF00 01 010006 00 600160005500", 6, 0}, - {"EF00 01 010001 020001 00 00 00 AA", 1, 1}, - {"EF00 01 010006 020004 00 600160005500 AABBCCDD", 6, 4}, - {"EF00 01 010100 021000 00" + std::string(256, '0') + std::string(4096, 'F'), 256, 4096}, + {"EF00 01 010004 0200010001 00 00000000 00", 4, 1, 0}, + {"EF00 01 010004 0200010006 00 00000400 600160005500", 4, 6, 0}, + {"EF00 01 010004 0200010001 030001 00 00000000 00 00 AA", 4, 1, 1}, + {"EF00 01 010004 0200010006 030004 00 00000000 600160005500 AABBCCDD", 4, 6, 4}, + {"EF00 01 010004 0200010100 031000 00 00000000" + std::string(256, '0') + std::string(4096, 'F'), 4, 256, 4096}, }; for (const auto& test_case : test_cases) @@ -61,5 +62,6 @@ TEST(eof, read_valid_eof1_header) const auto header = read_valid_eof1_header(bytes_view(code)); EXPECT_EQ(header.code_sizes[0], test_case.code_size) << test_case.code; EXPECT_EQ(header.data_size, test_case.data_size) << test_case.code; + EXPECT_EQ(header.types.size() * 4, test_case.types_size) << test_case.code; } } diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 3b116c23a1..54d8f494ff 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -40,7 +40,7 @@ TEST(eof_validation, validate_EOF_prefix) EXPECT_EQ(validate_eof("EF0001"), EOFValidationError::section_headers_not_terminated); // valid except for magic - EXPECT_EQ(validate_eof("EFFF01 010003 020004 00 600000 AABBCCDD"), + EXPECT_EQ(validate_eof("EFFF 01 010004 0200010003 030004 00 00000000 600000 AABBCCDD"), EOFValidationError::invalid_prefix); } @@ -50,81 +50,100 @@ TEST(eof_validation, validate_EOF_version) EXPECT_EQ(validate_eof("EF00FF"), EOFValidationError::eof_version_unknown); // valid except version - EXPECT_EQ(validate_eof("EF00000 10003 020004 00 600000 AABBCCDD"), + EXPECT_EQ(validate_eof("EF0000 010004 0200010003 020004 00 00000000 600000 AABBCCDD"), EOFValidationError::eof_version_unknown); - EXPECT_EQ(validate_eof("EF00020 10003 020004 00 600000 AABBCCDD"), + EXPECT_EQ(validate_eof("EF0002 010004 0200010003 020004 00 00000000 600000 AABBCCDD"), EOFValidationError::eof_version_unknown); - EXPECT_EQ(validate_eof("EF00FF0 10003 020004 00 600000 AABBCCDD"), + EXPECT_EQ(validate_eof("EF00FF 010004 0200010003 020004 00 00000000 600000 AABBCCDD"), EOFValidationError::eof_version_unknown); } TEST(eof_validation, valid_EOF1_code_pre_shanghai) { EXPECT_EQ( - validate_eof("EF0001 010001 00 FE", EVMC_PARIS), EOFValidationError::eof_version_unknown); + validate_eof("EF0001 010004 0200010001 00 00000000 FE", EVMC_PARIS), EOFValidationError::eof_version_unknown); } TEST(eof_validation, minimal_valid_EOF1_code) { - EXPECT_EQ(validate_eof("EF0001 010001 00 FE"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 00 00000000 FE"), EOFValidationError::success); } TEST(eof_validation, minimal_valid_EOF1_code_with_data) { - EXPECT_EQ(validate_eof("EF0001 010001 020001 00 FE DA"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 00 00000000 FE DA"), EOFValidationError::success); } -TEST(eof_validation, minimal_valid_EOF1_code_with_type) -{ - // no data section - EXPECT_EQ(validate_eof("EF0001 030002 01000100 0000 FE"), EOFValidationError::success); - // with data section - EXPECT_EQ( - validate_eof("EF0001 030002 010001 020001 00 0000 FE DA"), EOFValidationError::success); -} +// Types section is mandatory +//TEST(eof_validation, minimal_valid_EOF1_code_with_type) +//{ +// // no data section +// EXPECT_EQ(validate_eof("EF0001 030002 01000100 0000 FE"), EOFValidationError::success); +// // with data section +// EXPECT_EQ( +// validate_eof("EF0001 030002 010001 020001 00 0000 FE DA"), EOFValidationError::success); +//} TEST(eof_validation, minimal_valid_EOF1_multiple_code_sections) { // no data section EXPECT_EQ( - validate_eof("EF0001 030004 010001 010001 00 00000000 FE FE"), EOFValidationError::success); + validate_eof("EF0001 010008 02000200010001 00 00000000 00000000 FE FE"), EOFValidationError::success); // with data section - EXPECT_EQ(validate_eof("EF0001 030004 010001 010001 020001 00 00000000 FE FE DA"), + EXPECT_EQ(validate_eof("EF0001 010008 02000200010001 030001 00 00000000 00000000 FE FE DA"), EOFValidationError::success); // non-void input and output types EXPECT_EQ( validate_eof( - "EF0001 030008 010001 010002 010002 010002 00 0000010000010203 FE 5000 3000 8000"), + "EF0001 0100F0 0100040001000200020002 00 000000000 010000000 000100000 020300000 FE 5000 3000 8000"), EOFValidationError::success); } +TEST(eof_validation, EOF1_types_section_missing) +{ + EXPECT_EQ(validate_eof("EF0001 0200010001 00 FE"), EOFValidationError::type_section_missing); + EXPECT_EQ(validate_eof("EF0001 0200010001 030001 00 FE DA"), EOFValidationError::type_section_missing); +} + +TEST(eof_validation, EOF1_types_section_0_size) +{ + EXPECT_EQ(validate_eof("EF0001 010000 0200010001 00 FE"), EOFValidationError::zero_section_size); + EXPECT_EQ(validate_eof("EF0001 010000 0200010001 030001 00 FE DA"), EOFValidationError::zero_section_size); +} + TEST(eof_validation, EOF1_code_section_missing) { - EXPECT_EQ(validate_eof("EF0001 00"), EOFValidationError::code_section_missing); - EXPECT_EQ(validate_eof("EF0001 020001 00 DA"), EOFValidationError::code_section_missing); + EXPECT_EQ(validate_eof("EF0001 010004 00"), EOFValidationError::code_section_missing); + EXPECT_EQ(validate_eof("EF0001 010004 030001 00 00000000 DA"), EOFValidationError::code_section_missing); } TEST(eof_validation, EOF1_code_section_0_size) { - EXPECT_EQ(validate_eof("EF0001 010000 00"), EOFValidationError::zero_section_size); - EXPECT_EQ(validate_eof("EF0001 010000 020001 00 DA"), EOFValidationError::zero_section_size); + EXPECT_EQ(validate_eof("EF0001 010004 020000 00"), EOFValidationError::zero_section_size); + EXPECT_EQ(validate_eof("EF0001 010004 020000 020001 00 DA"), EOFValidationError::zero_section_size); } TEST(eof_validation, EOF1_data_section_0_size) { - EXPECT_EQ(validate_eof("EF0001 010001 020000 00 FE"), EOFValidationError::zero_section_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030000 00 00000000 FE"), EOFValidationError::zero_section_size); } TEST(eof_validation, EOF1_data_section_before_code_section) { - EXPECT_EQ(validate_eof("EF0001 020001 010001 00 AA FE"), + EXPECT_EQ(validate_eof("EF0001 010004 030001 0200010001 00 00000000 AA FE"), EOFValidationError::data_section_before_code_section); } +TEST(eof_validation, EOF1_data_section_before_types_section) +{ + EXPECT_EQ(validate_eof("EF0001 030001 010004 0200010001 00 AA 00000000 FE"), + EOFValidationError::data_section_before_types_section); +} + TEST(eof_validation, EOF1_multiple_data_sections) { - EXPECT_EQ(validate_eof("EF0001 010001 020001 020001 00 FE DA DA"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 020001 020001 00 00000000 FE DA DA"), EOFValidationError::multiple_data_sections); } @@ -133,45 +152,46 @@ TEST(eof_validation, EOF1_unknown_section) EXPECT_EQ(validate_eof("EF0001 040001 00 FE"), EOFValidationError::unknown_section_id); EXPECT_EQ(validate_eof("EF0001 FF0001 00 FE"), EOFValidationError::unknown_section_id); EXPECT_EQ( - validate_eof("EF0001 010001 040001 00 FE 00"), EOFValidationError::unknown_section_id); + validate_eof("EF0001 010004 0200010001 040001 00 00000000 FE 00"), EOFValidationError::unknown_section_id); EXPECT_EQ( - validate_eof("EF0001 010001 FF0001 00 FE 00"), EOFValidationError::unknown_section_id); - EXPECT_EQ(validate_eof("EF0001 010001 020001 040001 00 FE AA 00"), + validate_eof("EF0001 010004 0200010001 FF0001 00 00000000 FE 00"), EOFValidationError::unknown_section_id); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 040001 00 00000000 FE AA 00"), EOFValidationError::unknown_section_id); - EXPECT_EQ(validate_eof("EF0001 010001 020001 FF0001 00 FE AA 00"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010001 020001 FF0001 00 00000000 FE AA 00"), EOFValidationError::unknown_section_id); } TEST(eof_validation, EOF1_incomplete_section_size) { EXPECT_EQ(validate_eof("EF0001 0100"), EOFValidationError::incomplete_section_size); - EXPECT_EQ(validate_eof("EF0001 010001 0200"), EOFValidationError::incomplete_section_size); + EXPECT_EQ(validate_eof("EF0001 0100010001 0200"), EOFValidationError::incomplete_section_size); } TEST(eof_validation, EOF1_header_not_terminated) { EXPECT_EQ(validate_eof("EF0001 01"), EOFValidationError::section_headers_not_terminated); - EXPECT_EQ(validate_eof("EF0001 010001"), EOFValidationError::section_headers_not_terminated); - EXPECT_EQ(validate_eof("EF0001 010001 FE"), EOFValidationError::unknown_section_id); - EXPECT_EQ(validate_eof("EF0001 010001 02"), EOFValidationError::section_headers_not_terminated); + EXPECT_EQ(validate_eof("EF0001 010004"), EOFValidationError::section_headers_not_terminated); + EXPECT_EQ(validate_eof("EF0001 010004 FE"), EOFValidationError::unknown_section_id); + EXPECT_EQ(validate_eof("EF0001 010004 02"), EOFValidationError::section_headers_not_terminated); EXPECT_EQ( - validate_eof("EF0001 010001 020001"), EOFValidationError::section_headers_not_terminated); - EXPECT_EQ(validate_eof("EF0001 010001 020001 FE AA"), EOFValidationError::unknown_section_id); + validate_eof("EF0001 010004 0200010001 030001"), EOFValidationError::section_headers_not_terminated); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 FE AA"), EOFValidationError::unknown_section_id); } TEST(eof_validation, EOF1_truncated_section) { - EXPECT_EQ(validate_eof("EF0001 010002 00"), EOFValidationError::invalid_section_bodies_size); - EXPECT_EQ(validate_eof("EF0001 010002 00 FE"), EOFValidationError::invalid_section_bodies_size); - EXPECT_EQ(validate_eof("EF0001 010001 020002 00 FE"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00"), EOFValidationError::invalid_section_bodies_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00 000000"), EOFValidationError::invalid_section_bodies_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00 00000000 FE"), EOFValidationError::invalid_section_bodies_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030002 00 00000000 FE"), EOFValidationError::invalid_section_bodies_size); - EXPECT_EQ(validate_eof("EF0001 010001 020002 00 FE AA"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030002 00 00000000 FE AA"), EOFValidationError::invalid_section_bodies_size); } TEST(eof_validation, EOF1_code_section_offset) { - const auto eof = "EF0001 030004 010002 010001 00 0000 0000 fefe fe"_hex; + const auto eof = "EF0001 010008 02000200020001 030004 00 0000000000000000 fefe fe 0000 0000"_hex; ASSERT_EQ(validate_eof(EVMC_CANCUN, eof), EOFValidationError::success); const auto header = read_valid_eof1_header(eof); @@ -179,85 +199,90 @@ TEST(eof_validation, EOF1_code_section_offset) EXPECT_EQ(header.code_sizes[0], 2); EXPECT_EQ(header.code_sizes[1], 1); ASSERT_EQ(header.code_offsets.size(), 2); - EXPECT_EQ(header.code_offsets[0], 17); - EXPECT_EQ(header.code_offsets[1], 19); + EXPECT_EQ(header.code_offsets[0], 25); + EXPECT_EQ(header.code_offsets[1], 27); } TEST(eof_validation, EOF1_trailing_bytes) { - EXPECT_EQ(validate_eof("EF0001 010001 00 FE DEADBEEF"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 00 00000000 FE DEADBEEF"), EOFValidationError::invalid_section_bodies_size); - EXPECT_EQ(validate_eof("EF0001 010001 020002 00 FE AABB DEADBEEF"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030002 00 00000000 FE AABB DEADBEEF"), EOFValidationError::invalid_section_bodies_size); } TEST(eof_validation, EOF1_no_type_section) { - EXPECT_EQ(validate_eof("EF0001 010001 010001 00 FE FE"), + EXPECT_EQ(validate_eof("EF0001 0200010001 00 FE"), + EOFValidationError::mandatory_type_section_missing); + EXPECT_EQ(validate_eof("EF0001 02000200010001 00 FE FE"), EOFValidationError::mandatory_type_section_missing); } TEST(eof_validation, EOF1_multiple_type_sections) { - EXPECT_EQ(validate_eof("EF0001 030002 030002 010001 010001 00 0000 0000 FE FE"), + EXPECT_EQ(validate_eof("EF0001 010004 010004 02000200010001 00 00000000 00000000 FE FE"), EOFValidationError::multiple_type_sections); - EXPECT_EQ(validate_eof("EF0001 030002 010001 010001 030002 00 0000 FE FE 0000"), - EOFValidationError::multiple_type_sections); +// Section order is must be (Types, Code+, Data) +// EXPECT_EQ(validate_eof("EF0001 030002 010001 010001 030002 00 0000 FE FE 0000"), +// EOFValidationError::multiple_type_sections); } TEST(eof_validation, EOF1_type_section_not_first) { - EXPECT_EQ(validate_eof("EF0001 010001 030002 00 FE 0000"), + EXPECT_EQ(validate_eof("EF0001 0200010001 010004 00 FE 00000000"), EOFValidationError::code_section_before_type_section); - EXPECT_EQ(validate_eof("EF0001 010001 030002 010001 00 FE 0000 FE"), + EXPECT_EQ(validate_eof("EF0001 02000200010001 010004 00 FE FE 00000000"), EOFValidationError::code_section_before_type_section); - EXPECT_EQ(validate_eof("EF0001 010001 030002 020003 00 FE 0000 AABBCC"), + EXPECT_EQ(validate_eof("EF0001 0200010001 010004 030003 00 FE 00000000 AABBCC"), EOFValidationError::code_section_before_type_section); - EXPECT_EQ(validate_eof("EF0001 010001 020003 030002 00 FE AABBCC 0000"), + EXPECT_EQ(validate_eof("EF0001 0200010001 030003 010004 00 FE AABBCC 00000000"), EOFValidationError::code_section_before_type_section); } TEST(eof_validation, EOF1_invalid_type_section_size) { - EXPECT_EQ(validate_eof("EF0001 030001 010001 00 00 FE"), + EXPECT_EQ(validate_eof("EF0001 010001 0200010001 00 00 FE"), + EOFValidationError::invalid_type_section_size); + EXPECT_EQ(validate_eof("EF0001 010002 0200010001 00 0000 FE"), EOFValidationError::invalid_type_section_size); - EXPECT_EQ(validate_eof("EF0001 030004 010001 00 00000000 FE"), + EXPECT_EQ(validate_eof("EF0001 010008 0200010001 00 0000000000000000 FE"), EOFValidationError::invalid_type_section_size); - EXPECT_EQ(validate_eof("EF0001 030004 010001 010001 010001 00 00000000 FE FE FE"), + EXPECT_EQ(validate_eof("EF0001 010008 020002000100010001 00 0000000000000000 FE FE FE"), EOFValidationError::invalid_type_section_size); - EXPECT_EQ(validate_eof("EF0001 030008 010001 010001 010001 00 0000000000000000 FE FE FE"), + EXPECT_EQ(validate_eof("EF0001 01000c 020003000100010001 00 000000000000000000000000 FE FE FE"), EOFValidationError::invalid_type_section_size); } TEST(eof_validation, EOF1_invalid_section_0_type) { - EXPECT_EQ(validate_eof("EF0001 030002 010003 00 0001 60005C"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010003 00 00010000 60005C"), EOFValidationError::invalid_first_section_type); - EXPECT_EQ(validate_eof("EF0001 030002 010002 00 0100 5000"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00 01000000 5000"), EOFValidationError::invalid_first_section_type); - EXPECT_EQ(validate_eof("EF0001 030002 010003 00 0203 60005C"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010003 00 02030000 60005C"), EOFValidationError::invalid_first_section_type); } TEST(eof_validation, EOF1_too_many_code_sections) { - const auto valid = "EF0001 030800" + 1024 * bytecode{"010001"} + "00" + - 1024 * bytecode{"0000"} + 1024 * bytecode{"FE"}; + const auto valid = "EF0001 011000" + bytecode{"020400"} + 0x400 * bytecode{"0001"} + "00" + + 0x400 * bytecode{"00000000"} + 0x400 * bytecode{"FE"}; EXPECT_EQ(validate_eof(valid), EOFValidationError::success); - const auto invalid = "EF0001 030801" + 1025 * bytecode{"010001"} + "00" + - 1025 * bytecode{"0000"} + 1025 * bytecode{"FE"}; + const auto invalid = "EF0001 011002" + bytecode{"020401"} + 0x401 * bytecode{"0001"} + "00" + + 0x401 * bytecode{"00000000"} + 0x401 * bytecode{"FE"}; EXPECT_EQ(validate_eof(invalid), EOFValidationError::too_many_code_sections); } TEST(eof_validation, EOF1_undefined_opcodes) { - auto cont = "EF0001 010002 00 0000"_hex; + auto cont = "EF0001 010004 0100010002 00 00000000 0000"_hex; const auto& gas_table = evmone::instr::gas_costs[EVMC_SHANGHAI]; @@ -278,13 +303,13 @@ TEST(eof_validation, EOF1_undefined_opcodes) EXPECT_EQ(validate_eof(cont), expected) << hex(cont); } - EXPECT_EQ(validate_eof("EF0001 010001 00 FE"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 00 00000000 FE"), EOFValidationError::success); } TEST(eof_validation, EOF1_truncated_push) { - auto eof_header = "EF0001 010001 00"_hex; - auto& code_size_byte = eof_header[5]; + auto eof_header = "EF0001 010004 0100010001 00 00000000"_hex; + auto& code_size_byte = eof_header[10]; for (uint8_t opcode = OP_PUSH1; opcode <= OP_PUSH32; ++opcode) { const auto required_bytes = static_cast(opcode) - OP_PUSH1 + 1; @@ -308,8 +333,8 @@ TEST(eof_validation, EOF1_truncated_push) TEST(eof_validation, EOF1_terminating_instructions) { - auto eof_header = "EF0001 010001 00"_hex; - auto& code_size_byte = eof_header[5]; + auto eof_header = "EF0001 010004 0200010001 00"_hex; + auto& code_size_byte = eof_header[10]; const auto& traits = evmone::instr::traits; @@ -337,42 +362,42 @@ TEST(eof_validation, EOF1_terminating_instructions) TEST(eof_validation, EOF1_valid_rjump) { // offset = 0 - EXPECT_EQ(validate_eof("EF0001 010004 00 5C000000"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010004 00 00000000 5C000000"), EOFValidationError::success); // offset = 3 - EXPECT_EQ(validate_eof("EF0001 010007 00 5C000300000000"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010007 00 00000000 5C000300000000"), EOFValidationError::success); // offset = -4 - EXPECT_EQ(validate_eof("EF0001 010005 00 005CFFFC00"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010005 00 00000000 005CFFFC00"), EOFValidationError::success); } TEST(eof_validation, EOF1_valid_rjumpi) { // offset = 0 - EXPECT_EQ(validate_eof("EF0001 010006 00 60005D000000"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005D000000"), EOFValidationError::success); // offset = 3 - EXPECT_EQ(validate_eof("EF0001 010009 00 60005D000300000000"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0100010009 00 00000000 60005D000300000000"), EOFValidationError::success); // offset = -5 - EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFFB00"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFFB00"), EOFValidationError::success); } TEST(eof_validation, EOF1_rjump_truncated) { EXPECT_EQ( - validate_eof("EF0001 010001 00 5C"), EOFValidationError::missing_terminating_instruction); + validate_eof("EF0001 010004 0100010001 00 00000000 5C"), EOFValidationError::missing_terminating_instruction); EXPECT_EQ( - validate_eof("EF0001 010002 00 5C00"), EOFValidationError::missing_terminating_instruction); + validate_eof("EF0001 010004 0100010002 00 00000000 5C00"), EOFValidationError::missing_terminating_instruction); } TEST(eof_validation, EOF1_rjumpi_truncated) { - EXPECT_EQ(validate_eof("EF0001 010003 00 60005D"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010003 00 00000000 60005D"), EOFValidationError::missing_terminating_instruction); - EXPECT_EQ(validate_eof("EF0001 010004 00 60005D00"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010004 00 00000000 60005D00"), EOFValidationError::missing_terminating_instruction); } @@ -380,52 +405,52 @@ TEST(eof_validation, EOF1_rjump_invalid_destination) { // Into header (offset = -5) EXPECT_EQ( - validate_eof("EF0001 010004 00 5CFFFB00"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0100010004 00 00000000 5CFFFB00"), EOFValidationError::invalid_rjump_destination); // To before code begin (offset = -13) EXPECT_EQ( - validate_eof("EF0001 010004 00 5CFFF300"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0100010004 00 00000000 5CFFF300"), EOFValidationError::invalid_rjump_destination); // To after code end (offset = 2) EXPECT_EQ( - validate_eof("EF0001 010004 00 5C000200"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0100010004 00 00000000 5C000200"), EOFValidationError::invalid_rjump_destination); // To code end (offset = 1) EXPECT_EQ( - validate_eof("EF0001 010004 00 5C000100"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0100010004 00 00000000 5C000100"), EOFValidationError::invalid_rjump_destination); // To the same RJUMP immediate (offset = -1) EXPECT_EQ( - validate_eof("EF0001 010004 00 5CFFFF00"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0100010004 00 00000000 5CFFFF00"), EOFValidationError::invalid_rjump_destination); // To PUSH immediate (offset = -4) - EXPECT_EQ(validate_eof("EF0001 010006 00 60005CFFFC00"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005CFFFC00"), EOFValidationError::invalid_rjump_destination); } TEST(eof_validation, EOF1_rjumpi_invalid_destination) { // Into header (offset = -7) - EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFF900"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFF900"), EOFValidationError::invalid_rjump_destination); // To before code begin (offset = -15) - EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFF100"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFF100"), EOFValidationError::invalid_rjump_destination); // To after code end (offset = 2) - EXPECT_EQ(validate_eof("EF0001 010006 00 60005D000200"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005D000200"), EOFValidationError::invalid_rjump_destination); // To code end (offset = 1) - EXPECT_EQ(validate_eof("EF0001 010006 00 60005D000100"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005D000100"), EOFValidationError::invalid_rjump_destination); // To the same RJUMPI immediate (offset = -1) - EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFFF00"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFFF00"), EOFValidationError::invalid_rjump_destination); // To PUSH immediate (offset = -4) - EXPECT_EQ(validate_eof("EF0001 010006 00 60005DFFFC00"), + EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFFC00"), EOFValidationError::invalid_rjump_destination); } From 054f4bbcac0654608567295c71d9dd1136e38c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Dec 2022 09:51:18 +0100 Subject: [PATCH 44/72] test: Disable all unit tests for Advanced --- test/unittests/evm_fixture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittests/evm_fixture.cpp b/test/unittests/evm_fixture.cpp index 22342e9602..862b527bdc 100644 --- a/test/unittests/evm_fixture.cpp +++ b/test/unittests/evm_fixture.cpp @@ -26,7 +26,7 @@ const char* print_vm_name(const testing::TestParamInfo& info) noexcep } // namespace INSTANTIATE_TEST_SUITE_P( - evmone, evm, testing::Values(&advanced_vm, &baseline_vm, &bnocgoto_vm), print_vm_name); + evmone, evm, testing::Values(/*&advanced_vm,*/ &baseline_vm, &bnocgoto_vm), print_vm_name); bool evm::is_advanced() noexcept { From 94028338ddddb34bf3b9b621b18bf02a32be3a28 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 21 Dec 2022 10:50:32 +0100 Subject: [PATCH 45/72] Fix unit tests and add section order test --- test/unittests/eof_validation_test.cpp | 67 ++++++++++++++++++-------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 54d8f494ff..dd7c8928aa 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -374,30 +374,30 @@ TEST(eof_validation, EOF1_valid_rjump) TEST(eof_validation, EOF1_valid_rjumpi) { // offset = 0 - EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005D000000"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005D000000"), EOFValidationError::success); // offset = 3 - EXPECT_EQ(validate_eof("EF0001 010004 0100010009 00 00000000 60005D000300000000"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010009 00 00000000 60005D000300000000"), EOFValidationError::success); // offset = -5 - EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFFB00"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005DFFFB00"), EOFValidationError::success); } TEST(eof_validation, EOF1_rjump_truncated) { EXPECT_EQ( - validate_eof("EF0001 010004 0100010001 00 00000000 5C"), EOFValidationError::missing_terminating_instruction); + validate_eof("EF0001 010004 0200010001 00 00000000 5C"), EOFValidationError::missing_terminating_instruction); EXPECT_EQ( - validate_eof("EF0001 010004 0100010002 00 00000000 5C00"), EOFValidationError::missing_terminating_instruction); + validate_eof("EF0001 010004 0200010002 00 00000000 5C00"), EOFValidationError::missing_terminating_instruction); } TEST(eof_validation, EOF1_rjumpi_truncated) { - EXPECT_EQ(validate_eof("EF0001 010004 0100010003 00 00000000 60005D"), + EXPECT_EQ(validate_eof("EF0001 020004 0100010003 00 00000000 60005D"), EOFValidationError::missing_terminating_instruction); - EXPECT_EQ(validate_eof("EF0001 010004 0100010004 00 00000000 60005D00"), + EXPECT_EQ(validate_eof("EF0001 020004 0100010004 00 00000000 60005D00"), EOFValidationError::missing_terminating_instruction); } @@ -405,52 +405,81 @@ TEST(eof_validation, EOF1_rjump_invalid_destination) { // Into header (offset = -5) EXPECT_EQ( - validate_eof("EF0001 010004 0100010004 00 00000000 5CFFFB00"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0200010004 00 00000000 5CFFFB00"), EOFValidationError::invalid_rjump_destination); // To before code begin (offset = -13) EXPECT_EQ( - validate_eof("EF0001 010004 0100010004 00 00000000 5CFFF300"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0200010004 00 00000000 5CFFF300"), EOFValidationError::invalid_rjump_destination); // To after code end (offset = 2) EXPECT_EQ( - validate_eof("EF0001 010004 0100010004 00 00000000 5C000200"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0200010004 00 00000000 5C000200"), EOFValidationError::invalid_rjump_destination); // To code end (offset = 1) EXPECT_EQ( - validate_eof("EF0001 010004 0100010004 00 00000000 5C000100"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0200010004 00 00000000 5C000100"), EOFValidationError::invalid_rjump_destination); // To the same RJUMP immediate (offset = -1) EXPECT_EQ( - validate_eof("EF0001 010004 0100010004 00 00000000 5CFFFF00"), EOFValidationError::invalid_rjump_destination); + validate_eof("EF0001 010004 0200010004 00 00000000 5CFFFF00"), EOFValidationError::invalid_rjump_destination); // To PUSH immediate (offset = -4) - EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005CFFFC00"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005CFFFC00"), EOFValidationError::invalid_rjump_destination); } TEST(eof_validation, EOF1_rjumpi_invalid_destination) { // Into header (offset = -7) - EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFF900"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005DFFF900"), EOFValidationError::invalid_rjump_destination); // To before code begin (offset = -15) - EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFF100"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005DFFF100"), EOFValidationError::invalid_rjump_destination); // To after code end (offset = 2) - EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005D000200"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005D000200"), EOFValidationError::invalid_rjump_destination); // To code end (offset = 1) - EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005D000100"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005D000100"), EOFValidationError::invalid_rjump_destination); // To the same RJUMPI immediate (offset = -1) - EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFFF00"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005DFFFF00"), EOFValidationError::invalid_rjump_destination); // To PUSH immediate (offset = -4) - EXPECT_EQ(validate_eof("EF0001 010004 0100010006 00 00000000 60005DFFFC00"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005DFFFC00"), EOFValidationError::invalid_rjump_destination); } + +TEST(oef_validation, EOF1_section_order) +{ + // 01 02 03 + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 030002 00 00000000 60005D000000 AABB"), + EOFValidationError::success); + + // 01 03 02 + EXPECT_EQ(validate_eof("EF0001 010004 030002 0200010006 00 00000000 AABB 60005D000000"), + EOFValidationError::data_section_before_code_section); + + // 02 01 03 + EXPECT_EQ(validate_eof("EF0001 0200010006 010004 030002 00 60005D000000 00000000 AABB"), + EOFValidationError::code_section_before_type_section); + + // 02 03 01 + EXPECT_EQ(validate_eof("EF0001 0200010006 030002 010004 00 60005D000000 AABB 00000000"), + EOFValidationError::data_section_before_types_section); + + // 03 01 02 + EXPECT_EQ(validate_eof("EF0001 030002 010004 0200010006 00 AABB 00000000 60005D000000"), + EOFValidationError::data_section_before_types_section); + + // 03 02 01 + EXPECT_EQ(validate_eof("EF0001 030002 0200010006 010004 00 AABB 60005D000000 00000000"), + EOFValidationError::data_section_before_code_section); + + +} From 2a4062b37d7670945086eda2379c6af4f5290a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Dec 2022 11:17:53 +0100 Subject: [PATCH 46/72] Allow empty data section --- lib/evmone/eof.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 4e425d9f81..df4b111e11 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -111,7 +111,7 @@ std::pair validate_eof_headers(bytes_view return {{}, EOFValidationError::incomplete_section_size}; const auto size_lo = *it++; const auto section_size = static_cast((size_hi << 8) | size_lo); - if (section_size == 0) + if (section_size == 0 && section_id != DATA_SECTION) return {{}, EOFValidationError::zero_section_size}; section_headers[section_id].emplace_back(section_size); From 234b884916c7214c430d47cd23055463bb1d3ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Dec 2022 11:18:23 +0100 Subject: [PATCH 47/72] Migrate bytecode helpers to new EOF format --- test/utils/bytecode.hpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/utils/bytecode.hpp b/test/utils/bytecode.hpp index 35bd676a7d..e676a6688d 100644 --- a/test/utils/bytecode.hpp +++ b/test/utils/bytecode.hpp @@ -93,13 +93,11 @@ big_endian(T value) inline bytecode eof_header(uint8_t version, uint16_t code_size, uint16_t data_size) { bytecode out{bytes{0xEF, 0x00, version}}; - - out += "01" + big_endian(code_size); - - if (data_size != 0) - out += "02" + big_endian(data_size); - + out += "01" + big_endian(uint16_t{4}); // type header + out += "02"_hex + big_endian(uint16_t{1}) + big_endian(code_size); + out += "03" + big_endian(data_size); out += "00"; + out += "00000000"; // type section return out; } From 8bc94db9b6311cb80920d5cc9d87417afb3fd378 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 21 Dec 2022 14:53:08 +0100 Subject: [PATCH 48/72] Fix and update EOF validation unit tests --- lib/evmone/eof.cpp | 14 ++++++-- test/unittests/eof_validation_test.cpp | 46 +++++++++++++------------- test/unittests/evm_eof_test.cpp | 38 ++++++++++----------- 3 files changed, 54 insertions(+), 44 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index df4b111e11..c9323a2472 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -79,21 +79,29 @@ std::pair validate_eof_headers(bytes_view state = State::section_size; break; case DATA_SECTION: + if (section_headers[TYPE_SECTION].empty()) + return {{}, EOFValidationError::data_section_before_types_section}; + if (section_headers[CODE_SECTION].empty()) + return {{}, EOFValidationError::data_section_before_code_section}; if (!section_headers[DATA_SECTION].empty()) return {{}, EOFValidationError::multiple_data_sections}; state = State::section_size; break; case CODE_SECTION: { - if (section_headers[CODE_SECTION].size() == CODE_SECTION_NUMBER_LIMIT) - return {{}, EOFValidationError::too_many_code_sections}; + if (section_headers[TYPE_SECTION].empty()) + return {{}, EOFValidationError::code_section_before_type_section}; if (!section_headers[DATA_SECTION].empty()) return {{}, EOFValidationError::data_section_before_code_section}; + if (it == container_end) + return {{}, EOFValidationError::incomplete_section_number}; const auto section_number_hi = *it++; if (it == container_end) return {{}, EOFValidationError::incomplete_section_number}; const auto section_number_lo = *it++; section_num = static_cast((section_number_hi << 8) | section_number_lo); + if (section_num == 0) + return {{}, EOFValidationError::zero_section_size}; state = State::section_size; break; } @@ -114,6 +122,8 @@ std::pair validate_eof_headers(bytes_view if (section_size == 0 && section_id != DATA_SECTION) return {{}, EOFValidationError::zero_section_size}; + if (section_headers[CODE_SECTION].size() == CODE_SECTION_NUMBER_LIMIT) + return {{}, EOFValidationError::too_many_code_sections}; section_headers[section_id].emplace_back(section_size); } diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index dd7c8928aa..a2692c4309 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -96,14 +96,14 @@ TEST(eof_validation, minimal_valid_EOF1_multiple_code_sections) // non-void input and output types EXPECT_EQ( validate_eof( - "EF0001 0100F0 0100040001000200020002 00 000000000 010000000 000100000 020300000 FE 5000 3000 8000"), + "EF0001 010010 0200040001000200020002 00 00000000 01000000 00010000 02030000 FE 5000 3000 8000"), EOFValidationError::success); } TEST(eof_validation, EOF1_types_section_missing) { - EXPECT_EQ(validate_eof("EF0001 0200010001 00 FE"), EOFValidationError::type_section_missing); - EXPECT_EQ(validate_eof("EF0001 0200010001 030001 00 FE DA"), EOFValidationError::type_section_missing); + EXPECT_EQ(validate_eof("EF0001 0200010001 00 FE"), EOFValidationError::code_section_before_type_section); + EXPECT_EQ(validate_eof("EF0001 0200010001 030001 00 FE DA"), EOFValidationError::code_section_before_type_section); } TEST(eof_validation, EOF1_types_section_0_size) @@ -115,18 +115,18 @@ TEST(eof_validation, EOF1_types_section_0_size) TEST(eof_validation, EOF1_code_section_missing) { EXPECT_EQ(validate_eof("EF0001 010004 00"), EOFValidationError::code_section_missing); - EXPECT_EQ(validate_eof("EF0001 010004 030001 00 00000000 DA"), EOFValidationError::code_section_missing); + EXPECT_EQ(validate_eof("EF0001 010004 030001 00 00000000 DA"), EOFValidationError::data_section_before_code_section); } TEST(eof_validation, EOF1_code_section_0_size) { EXPECT_EQ(validate_eof("EF0001 010004 020000 00"), EOFValidationError::zero_section_size); - EXPECT_EQ(validate_eof("EF0001 010004 020000 020001 00 DA"), EOFValidationError::zero_section_size); + EXPECT_EQ(validate_eof("EF0001 010004 020000 030001 00 DA"), EOFValidationError::zero_section_size); } TEST(eof_validation, EOF1_data_section_0_size) { - EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030000 00 00000000 FE"), EOFValidationError::zero_section_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030000 00 00000000 FE"), EOFValidationError::success); } TEST(eof_validation, EOF1_data_section_before_code_section) @@ -143,7 +143,7 @@ TEST(eof_validation, EOF1_data_section_before_types_section) TEST(eof_validation, EOF1_multiple_data_sections) { - EXPECT_EQ(validate_eof("EF0001 010004 0200010001 020001 020001 00 00000000 FE DA DA"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 030001 00 00000000 FE DA DA"), EOFValidationError::multiple_data_sections); } @@ -157,14 +157,16 @@ TEST(eof_validation, EOF1_unknown_section) validate_eof("EF0001 010004 0200010001 FF0001 00 00000000 FE 00"), EOFValidationError::unknown_section_id); EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 040001 00 00000000 FE AA 00"), EOFValidationError::unknown_section_id); - EXPECT_EQ(validate_eof("EF0001 010004 0100010001 020001 FF0001 00 00000000 FE AA 00"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 FF0001 00 00000000 FE AA 00"), EOFValidationError::unknown_section_id); } TEST(eof_validation, EOF1_incomplete_section_size) { EXPECT_EQ(validate_eof("EF0001 0100"), EOFValidationError::incomplete_section_size); - EXPECT_EQ(validate_eof("EF0001 0100010001 0200"), EOFValidationError::incomplete_section_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200"), EOFValidationError::incomplete_section_number); + EXPECT_EQ(validate_eof("EF0001 010004 02000100"), EOFValidationError::incomplete_section_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 0300"), EOFValidationError::incomplete_section_size); } TEST(eof_validation, EOF1_header_not_terminated) @@ -172,7 +174,7 @@ TEST(eof_validation, EOF1_header_not_terminated) EXPECT_EQ(validate_eof("EF0001 01"), EOFValidationError::section_headers_not_terminated); EXPECT_EQ(validate_eof("EF0001 010004"), EOFValidationError::section_headers_not_terminated); EXPECT_EQ(validate_eof("EF0001 010004 FE"), EOFValidationError::unknown_section_id); - EXPECT_EQ(validate_eof("EF0001 010004 02"), EOFValidationError::section_headers_not_terminated); + EXPECT_EQ(validate_eof("EF0001 010004 02"), EOFValidationError::incomplete_section_number); EXPECT_EQ( validate_eof("EF0001 010004 0200010001 030001"), EOFValidationError::section_headers_not_terminated); EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 FE AA"), EOFValidationError::unknown_section_id); @@ -214,9 +216,9 @@ TEST(eof_validation, EOF1_trailing_bytes) TEST(eof_validation, EOF1_no_type_section) { EXPECT_EQ(validate_eof("EF0001 0200010001 00 FE"), - EOFValidationError::mandatory_type_section_missing); + EOFValidationError::code_section_before_type_section); EXPECT_EQ(validate_eof("EF0001 02000200010001 00 FE FE"), - EOFValidationError::mandatory_type_section_missing); + EOFValidationError::code_section_before_type_section); } TEST(eof_validation, EOF1_multiple_type_sections) @@ -253,9 +255,9 @@ TEST(eof_validation, EOF1_invalid_type_section_size) EXPECT_EQ(validate_eof("EF0001 010008 0200010001 00 0000000000000000 FE"), EOFValidationError::invalid_type_section_size); - EXPECT_EQ(validate_eof("EF0001 010008 020002000100010001 00 0000000000000000 FE FE FE"), + EXPECT_EQ(validate_eof("EF0001 010008 020003000100010001 00 0000000000000000 FE FE FE"), EOFValidationError::invalid_type_section_size); - EXPECT_EQ(validate_eof("EF0001 01000c 020003000100010001 00 000000000000000000000000 FE FE FE"), + EXPECT_EQ(validate_eof("EF0001 010010 020003000100010001 00 00000000000000000000000000000000 FE FE FE"), EOFValidationError::invalid_type_section_size); } @@ -282,7 +284,7 @@ TEST(eof_validation, EOF1_too_many_code_sections) TEST(eof_validation, EOF1_undefined_opcodes) { - auto cont = "EF0001 010004 0100010002 00 00000000 0000"_hex; + auto cont = "EF0001 010004 0200010002 00 00000000 0000"_hex; const auto& gas_table = evmone::instr::gas_costs[EVMC_SHANGHAI]; @@ -308,7 +310,7 @@ TEST(eof_validation, EOF1_undefined_opcodes) TEST(eof_validation, EOF1_truncated_push) { - auto eof_header = "EF0001 010004 0100010001 00 00000000"_hex; + auto eof_header = "EF0001 010004 0200010001 00 00000000"_hex; auto& code_size_byte = eof_header[10]; for (uint8_t opcode = OP_PUSH1; opcode <= OP_PUSH32; ++opcode) { @@ -333,7 +335,7 @@ TEST(eof_validation, EOF1_truncated_push) TEST(eof_validation, EOF1_terminating_instructions) { - auto eof_header = "EF0001 010004 0200010001 00"_hex; + auto eof_header = "EF0001 010004 0200010001 00 00000000"_hex; auto& code_size_byte = eof_header[10]; const auto& traits = evmone::instr::traits; @@ -394,10 +396,10 @@ TEST(eof_validation, EOF1_rjump_truncated) TEST(eof_validation, EOF1_rjumpi_truncated) { - EXPECT_EQ(validate_eof("EF0001 020004 0100010003 00 00000000 60005D"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010003 00 00000000 60005D"), EOFValidationError::missing_terminating_instruction); - EXPECT_EQ(validate_eof("EF0001 020004 0100010004 00 00000000 60005D00"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010004 00 00000000 60005D00"), EOFValidationError::missing_terminating_instruction); } @@ -471,7 +473,7 @@ TEST(oef_validation, EOF1_section_order) // 02 03 01 EXPECT_EQ(validate_eof("EF0001 0200010006 030002 010004 00 60005D000000 AABB 00000000"), - EOFValidationError::data_section_before_types_section); + EOFValidationError::code_section_before_type_section); // 03 01 02 EXPECT_EQ(validate_eof("EF0001 030002 010004 0200010006 00 AABB 00000000 60005D000000"), @@ -479,7 +481,5 @@ TEST(oef_validation, EOF1_section_order) // 03 02 01 EXPECT_EQ(validate_eof("EF0001 030002 0200010006 010004 00 AABB 60005D000000 00000000"), - EOFValidationError::data_section_before_code_section); - - + EOFValidationError::data_section_before_types_section); } diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 92429438c6..509f917f8d 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -129,71 +129,71 @@ TEST_P(evm, eof1_codesize) execute(code); EXPECT_STATUS(EVMC_SUCCESS); ASSERT_EQ(result.output_size, 1); - EXPECT_EQ(result.output_data[0], 16); + EXPECT_EQ(result.output_data[0], 28); code = eof1_bytecode(mstore8(0, OP_CODESIZE) + ret(0, 1), "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); ASSERT_EQ(result.output_size, 1); - EXPECT_EQ(result.output_data[0], 23); + EXPECT_EQ(result.output_data[0], 32); } TEST_P(evm, eof1_codecopy_full) { rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(bytecode{19} + 0 + 0 + OP_CODECOPY + ret(0, 19)); + auto code = eof1_bytecode(bytecode{31} + 0 + 0 + OP_CODECOPY + ret(0, 31)); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "ef000101000c006013600060003960136000f3"_hex); + "ef0001010004020001000c0300000000000000601f6000600039601f6000f3"_hex); - code = eof1_bytecode(bytecode{26} + 0 + 0 + OP_CODECOPY + ret(0, 26), "deadbeef"); + code = eof1_bytecode(bytecode{35} + 0 + 0 + OP_CODECOPY + ret(0, 35), "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "ef000101000c02000400601a6000600039601a6000f3deadbeef"_hex); + "ef0001010004020001000c03000400000000006023600060003960236000f3deadbeef"_hex); } TEST_P(evm, eof1_codecopy_header) { rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(bytecode{7} + 0 + 0 + OP_CODECOPY + ret(0, 7)); + auto code = eof1_bytecode(bytecode{15} + 0 + 0 + OP_CODECOPY + ret(0, 15)); execute(code); EXPECT_STATUS(EVMC_SUCCESS); - EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef000101000c00"_hex); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef0001010004020001000c03000000"_hex); - code = eof1_bytecode(bytecode{10} + 0 + 0 + OP_CODECOPY + ret(0, 10), "deadbeef"); + code = eof1_bytecode(bytecode{15} + 0 + 0 + OP_CODECOPY + ret(0, 15), "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); - EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef000101000c02000400"_hex); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef0001010004020001000c03000400"_hex); } TEST_P(evm, eof1_codecopy_code) { rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(bytecode{12} + 7 + 0 + OP_CODECOPY + ret(0, 12)); + auto code = eof1_bytecode(bytecode{12} + 19 + 0 + OP_CODECOPY + ret(0, 12)); execute(code); EXPECT_STATUS(EVMC_SUCCESS); - EXPECT_EQ(bytes_view(result.output_data, result.output_size), "600c6007600039600c6000f3"_hex); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), "600c6013600039600c6000f3"_hex); - code = eof1_bytecode(bytecode{12} + 10 + 0 + OP_CODECOPY + ret(0, 12), "deadbeef"); + code = eof1_bytecode(bytecode{12} + 19 + 0 + OP_CODECOPY + ret(0, 12), "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); - EXPECT_EQ(bytes_view(result.output_data, result.output_size), "600c600a600039600c6000f3"_hex); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), "600c6013600039600c6000f3"_hex); } TEST_P(evm, eof1_codecopy_data) { rev = EVMC_SHANGHAI; - const auto code = eof1_bytecode(bytecode{4} + 22 + 0 + OP_CODECOPY + ret(0, 4), "deadbeef"); + const auto code = eof1_bytecode(bytecode{4} + 31 + 0 + OP_CODECOPY + ret(0, 4), "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -204,19 +204,19 @@ TEST_P(evm, eof1_codecopy_out_of_bounds) { // 4 bytes out of container bounds - result is implicitly 0-padded rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(bytecode{23} + 0 + 0 + OP_CODECOPY + ret(0, 23)); + auto code = eof1_bytecode(bytecode{35} + 0 + 0 + OP_CODECOPY + ret(0, 35)); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "ef000101000c006017600060003960176000f300000000"_hex); + "ef0001010004020001000c03000000000000006023600060003960236000f300000000"_hex); - code = eof1_bytecode(bytecode{30} + 0 + 0 + OP_CODECOPY + ret(0, 30), "deadbeef"); + code = eof1_bytecode(bytecode{39} + 0 + 0 + OP_CODECOPY + ret(0, 39), "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "ef000101000c02000400601e6000600039601e6000f3deadbeef00000000"_hex); + "ef0001010004020001000c03000400000000006027600060003960276000f3deadbeef00000000"_hex); } TEST_P(evm, eof2_rjump) From 5c222d38a9c459f829a00b32b8a6ed5263ad4056 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 21 Dec 2022 15:19:44 +0100 Subject: [PATCH 49/72] Fix linter errors --- test/unittests/eof_test.cpp | 4 +- test/unittests/eof_validation_test.cpp | 124 ++++++++++++++----------- test/unittests/evm_eof_test.cpp | 6 +- 3 files changed, 79 insertions(+), 55 deletions(-) diff --git a/test/unittests/eof_test.cpp b/test/unittests/eof_test.cpp index e9ef27c080..01a76c958a 100644 --- a/test/unittests/eof_test.cpp +++ b/test/unittests/eof_test.cpp @@ -53,7 +53,9 @@ TEST(eof, read_valid_eof1_header) {"EF00 01 010004 0200010006 00 00000400 600160005500", 4, 6, 0}, {"EF00 01 010004 0200010001 030001 00 00000000 00 00 AA", 4, 1, 1}, {"EF00 01 010004 0200010006 030004 00 00000000 600160005500 AABBCCDD", 4, 6, 4}, - {"EF00 01 010004 0200010100 031000 00 00000000" + std::string(256, '0') + std::string(4096, 'F'), 4, 256, 4096}, + {"EF00 01 010004 0200010100 031000 00 00000000" + std::string(256, '0') + + std::string(4096, 'F'), + 4, 256, 4096}, }; for (const auto& test_case : test_cases) diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index a2692c4309..2186ea12ea 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -60,8 +60,8 @@ TEST(eof_validation, validate_EOF_version) TEST(eof_validation, valid_EOF1_code_pre_shanghai) { - EXPECT_EQ( - validate_eof("EF0001 010004 0200010001 00 00000000 FE", EVMC_PARIS), EOFValidationError::eof_version_unknown); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 00 00000000 FE", EVMC_PARIS), + EOFValidationError::eof_version_unknown); } TEST(eof_validation, minimal_valid_EOF1_code) @@ -71,11 +71,12 @@ TEST(eof_validation, minimal_valid_EOF1_code) TEST(eof_validation, minimal_valid_EOF1_code_with_data) { - EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 00 00000000 FE DA"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 00 00000000 FE DA"), + EOFValidationError::success); } // Types section is mandatory -//TEST(eof_validation, minimal_valid_EOF1_code_with_type) +// TEST(eof_validation, minimal_valid_EOF1_code_with_type) //{ // // no data section // EXPECT_EQ(validate_eof("EF0001 030002 01000100 0000 FE"), EOFValidationError::success); @@ -87,46 +88,52 @@ TEST(eof_validation, minimal_valid_EOF1_code_with_data) TEST(eof_validation, minimal_valid_EOF1_multiple_code_sections) { // no data section - EXPECT_EQ( - validate_eof("EF0001 010008 02000200010001 00 00000000 00000000 FE FE"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010008 02000200010001 00 00000000 00000000 FE FE"), + EOFValidationError::success); // with data section EXPECT_EQ(validate_eof("EF0001 010008 02000200010001 030001 00 00000000 00000000 FE FE DA"), EOFValidationError::success); // non-void input and output types - EXPECT_EQ( - validate_eof( - "EF0001 010010 0200040001000200020002 00 00000000 01000000 00010000 02030000 FE 5000 3000 8000"), + EXPECT_EQ(validate_eof("EF0001 010010 0200040001000200020002 00 00000000 01000000 00010000 " + "02030000 FE 5000 3000 8000"), EOFValidationError::success); } TEST(eof_validation, EOF1_types_section_missing) { - EXPECT_EQ(validate_eof("EF0001 0200010001 00 FE"), EOFValidationError::code_section_before_type_section); - EXPECT_EQ(validate_eof("EF0001 0200010001 030001 00 FE DA"), EOFValidationError::code_section_before_type_section); + EXPECT_EQ(validate_eof("EF0001 0200010001 00 FE"), + EOFValidationError::code_section_before_type_section); + EXPECT_EQ(validate_eof("EF0001 0200010001 030001 00 FE DA"), + EOFValidationError::code_section_before_type_section); } TEST(eof_validation, EOF1_types_section_0_size) { - EXPECT_EQ(validate_eof("EF0001 010000 0200010001 00 FE"), EOFValidationError::zero_section_size); - EXPECT_EQ(validate_eof("EF0001 010000 0200010001 030001 00 FE DA"), EOFValidationError::zero_section_size); + EXPECT_EQ( + validate_eof("EF0001 010000 0200010001 00 FE"), EOFValidationError::zero_section_size); + EXPECT_EQ(validate_eof("EF0001 010000 0200010001 030001 00 FE DA"), + EOFValidationError::zero_section_size); } TEST(eof_validation, EOF1_code_section_missing) { EXPECT_EQ(validate_eof("EF0001 010004 00"), EOFValidationError::code_section_missing); - EXPECT_EQ(validate_eof("EF0001 010004 030001 00 00000000 DA"), EOFValidationError::data_section_before_code_section); + EXPECT_EQ(validate_eof("EF0001 010004 030001 00 00000000 DA"), + EOFValidationError::data_section_before_code_section); } TEST(eof_validation, EOF1_code_section_0_size) { EXPECT_EQ(validate_eof("EF0001 010004 020000 00"), EOFValidationError::zero_section_size); - EXPECT_EQ(validate_eof("EF0001 010004 020000 030001 00 DA"), EOFValidationError::zero_section_size); + EXPECT_EQ( + validate_eof("EF0001 010004 020000 030001 00 DA"), EOFValidationError::zero_section_size); } TEST(eof_validation, EOF1_data_section_0_size) { - EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030000 00 00000000 FE"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030000 00 00000000 FE"), + EOFValidationError::success); } TEST(eof_validation, EOF1_data_section_before_code_section) @@ -151,10 +158,10 @@ TEST(eof_validation, EOF1_unknown_section) { EXPECT_EQ(validate_eof("EF0001 040001 00 FE"), EOFValidationError::unknown_section_id); EXPECT_EQ(validate_eof("EF0001 FF0001 00 FE"), EOFValidationError::unknown_section_id); - EXPECT_EQ( - validate_eof("EF0001 010004 0200010001 040001 00 00000000 FE 00"), EOFValidationError::unknown_section_id); - EXPECT_EQ( - validate_eof("EF0001 010004 0200010001 FF0001 00 00000000 FE 00"), EOFValidationError::unknown_section_id); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 040001 00 00000000 FE 00"), + EOFValidationError::unknown_section_id); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 FF0001 00 00000000 FE 00"), + EOFValidationError::unknown_section_id); EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 040001 00 00000000 FE AA 00"), EOFValidationError::unknown_section_id); EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 FF0001 00 00000000 FE AA 00"), @@ -166,7 +173,8 @@ TEST(eof_validation, EOF1_incomplete_section_size) EXPECT_EQ(validate_eof("EF0001 0100"), EOFValidationError::incomplete_section_size); EXPECT_EQ(validate_eof("EF0001 010004 0200"), EOFValidationError::incomplete_section_number); EXPECT_EQ(validate_eof("EF0001 010004 02000100"), EOFValidationError::incomplete_section_size); - EXPECT_EQ(validate_eof("EF0001 010004 0200010001 0300"), EOFValidationError::incomplete_section_size); + EXPECT_EQ( + validate_eof("EF0001 010004 0200010001 0300"), EOFValidationError::incomplete_section_size); } TEST(eof_validation, EOF1_header_not_terminated) @@ -175,16 +183,20 @@ TEST(eof_validation, EOF1_header_not_terminated) EXPECT_EQ(validate_eof("EF0001 010004"), EOFValidationError::section_headers_not_terminated); EXPECT_EQ(validate_eof("EF0001 010004 FE"), EOFValidationError::unknown_section_id); EXPECT_EQ(validate_eof("EF0001 010004 02"), EOFValidationError::incomplete_section_number); - EXPECT_EQ( - validate_eof("EF0001 010004 0200010001 030001"), EOFValidationError::section_headers_not_terminated); - EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 FE AA"), EOFValidationError::unknown_section_id); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001"), + EOFValidationError::section_headers_not_terminated); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030001 FE AA"), + EOFValidationError::unknown_section_id); } TEST(eof_validation, EOF1_truncated_section) { - EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00"), EOFValidationError::invalid_section_bodies_size); - EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00 000000"), EOFValidationError::invalid_section_bodies_size); - EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00 00000000 FE"), EOFValidationError::invalid_section_bodies_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00"), + EOFValidationError::invalid_section_bodies_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00 000000"), + EOFValidationError::invalid_section_bodies_size); + EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00 00000000 FE"), + EOFValidationError::invalid_section_bodies_size); EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030002 00 00000000 FE"), EOFValidationError::invalid_section_bodies_size); EXPECT_EQ(validate_eof("EF0001 010004 0200010001 030002 00 00000000 FE AA"), @@ -193,7 +205,8 @@ TEST(eof_validation, EOF1_truncated_section) TEST(eof_validation, EOF1_code_section_offset) { - const auto eof = "EF0001 010008 02000200020001 030004 00 0000000000000000 fefe fe 0000 0000"_hex; + const auto eof = + "EF0001 010008 02000200020001 030004 00 0000000000000000 fefe fe 0000 0000"_hex; ASSERT_EQ(validate_eof(EVMC_CANCUN, eof), EOFValidationError::success); const auto header = read_valid_eof1_header(eof); @@ -226,9 +239,9 @@ TEST(eof_validation, EOF1_multiple_type_sections) EXPECT_EQ(validate_eof("EF0001 010004 010004 02000200010001 00 00000000 00000000 FE FE"), EOFValidationError::multiple_type_sections); -// Section order is must be (Types, Code+, Data) -// EXPECT_EQ(validate_eof("EF0001 030002 010001 010001 030002 00 0000 FE FE 0000"), -// EOFValidationError::multiple_type_sections); + // Section order is must be (Types, Code+, Data) + // EXPECT_EQ(validate_eof("EF0001 030002 010001 010001 030002 00 0000 FE FE 0000"), + // EOFValidationError::multiple_type_sections); } TEST(eof_validation, EOF1_type_section_not_first) @@ -257,7 +270,8 @@ TEST(eof_validation, EOF1_invalid_type_section_size) EXPECT_EQ(validate_eof("EF0001 010008 020003000100010001 00 0000000000000000 FE FE FE"), EOFValidationError::invalid_type_section_size); - EXPECT_EQ(validate_eof("EF0001 010010 020003000100010001 00 00000000000000000000000000000000 FE FE FE"), + EXPECT_EQ(validate_eof( + "EF0001 010010 020003000100010001 00 00000000000000000000000000000000 FE FE FE"), EOFValidationError::invalid_type_section_size); } @@ -364,34 +378,40 @@ TEST(eof_validation, EOF1_terminating_instructions) TEST(eof_validation, EOF1_valid_rjump) { // offset = 0 - EXPECT_EQ(validate_eof("EF0001 010004 0200010004 00 00000000 5C000000"), EOFValidationError::success); + EXPECT_EQ( + validate_eof("EF0001 010004 0200010004 00 00000000 5C000000"), EOFValidationError::success); // offset = 3 - EXPECT_EQ(validate_eof("EF0001 010004 0200010007 00 00000000 5C000300000000"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010007 00 00000000 5C000300000000"), + EOFValidationError::success); // offset = -4 - EXPECT_EQ(validate_eof("EF0001 010004 0200010005 00 00000000 005CFFFC00"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010005 00 00000000 005CFFFC00"), + EOFValidationError::success); } TEST(eof_validation, EOF1_valid_rjumpi) { // offset = 0 - EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005D000000"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005D000000"), + EOFValidationError::success); // offset = 3 - EXPECT_EQ(validate_eof("EF0001 010004 0200010009 00 00000000 60005D000300000000"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010009 00 00000000 60005D000300000000"), + EOFValidationError::success); // offset = -5 - EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005DFFFB00"), EOFValidationError::success); + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005DFFFB00"), + EOFValidationError::success); } TEST(eof_validation, EOF1_rjump_truncated) { - EXPECT_EQ( - validate_eof("EF0001 010004 0200010001 00 00000000 5C"), EOFValidationError::missing_terminating_instruction); + EXPECT_EQ(validate_eof("EF0001 010004 0200010001 00 00000000 5C"), + EOFValidationError::missing_terminating_instruction); - EXPECT_EQ( - validate_eof("EF0001 010004 0200010002 00 00000000 5C00"), EOFValidationError::missing_terminating_instruction); + EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00 00000000 5C00"), + EOFValidationError::missing_terminating_instruction); } TEST(eof_validation, EOF1_rjumpi_truncated) @@ -406,24 +426,24 @@ TEST(eof_validation, EOF1_rjumpi_truncated) TEST(eof_validation, EOF1_rjump_invalid_destination) { // Into header (offset = -5) - EXPECT_EQ( - validate_eof("EF0001 010004 0200010004 00 00000000 5CFFFB00"), EOFValidationError::invalid_rjump_destination); + EXPECT_EQ(validate_eof("EF0001 010004 0200010004 00 00000000 5CFFFB00"), + EOFValidationError::invalid_rjump_destination); // To before code begin (offset = -13) - EXPECT_EQ( - validate_eof("EF0001 010004 0200010004 00 00000000 5CFFF300"), EOFValidationError::invalid_rjump_destination); + EXPECT_EQ(validate_eof("EF0001 010004 0200010004 00 00000000 5CFFF300"), + EOFValidationError::invalid_rjump_destination); // To after code end (offset = 2) - EXPECT_EQ( - validate_eof("EF0001 010004 0200010004 00 00000000 5C000200"), EOFValidationError::invalid_rjump_destination); + EXPECT_EQ(validate_eof("EF0001 010004 0200010004 00 00000000 5C000200"), + EOFValidationError::invalid_rjump_destination); // To code end (offset = 1) - EXPECT_EQ( - validate_eof("EF0001 010004 0200010004 00 00000000 5C000100"), EOFValidationError::invalid_rjump_destination); + EXPECT_EQ(validate_eof("EF0001 010004 0200010004 00 00000000 5C000100"), + EOFValidationError::invalid_rjump_destination); // To the same RJUMP immediate (offset = -1) - EXPECT_EQ( - validate_eof("EF0001 010004 0200010004 00 00000000 5CFFFF00"), EOFValidationError::invalid_rjump_destination); + EXPECT_EQ(validate_eof("EF0001 010004 0200010004 00 00000000 5CFFFF00"), + EOFValidationError::invalid_rjump_destination); // To PUSH immediate (offset = -4) EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005CFFFC00"), diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 509f917f8d..18d8b6a6f8 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -164,13 +164,15 @@ TEST_P(evm, eof1_codecopy_header) execute(code); EXPECT_STATUS(EVMC_SUCCESS); - EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef0001010004020001000c03000000"_hex); + EXPECT_EQ( + bytes_view(result.output_data, result.output_size), "ef0001010004020001000c03000000"_hex); code = eof1_bytecode(bytecode{15} + 0 + 0 + OP_CODECOPY + ret(0, 15), "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); - EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef0001010004020001000c03000400"_hex); + EXPECT_EQ( + bytes_view(result.output_data, result.output_size), "ef0001010004020001000c03000400"_hex); } TEST_P(evm, eof1_codecopy_code) From 4c5f27a2ab0a28e636b01d7d59a27768c5c7ea7e Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 21 Dec 2022 16:43:27 +0100 Subject: [PATCH 50/72] Make types section mandatory --- lib/evmone/eof.cpp | 7 ++++--- lib/evmone/eof.hpp | 1 - test/unittests/eof_validation_test.cpp | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index c9323a2472..d3e049f070 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -54,6 +54,8 @@ std::pair validate_eof_headers(bytes_view EOFSectionHeaders section_headers{}; const auto container_end = container.end(); auto it = container.begin() + std::size(MAGIC) + 1; // MAGIC + VERSION + // TODO: Since all sections are mandatory and they have to be ordered (Types, Code+, Data) + // TODO: this fragment of code can be much simpler. Rewriting needed. while (it != container_end && state != State::terminated) { switch (state) @@ -64,11 +66,10 @@ std::pair validate_eof_headers(bytes_view switch (section_id) { case TERMINATOR: + if (section_headers[TYPE_SECTION].empty()) + return {{}, EOFValidationError::type_section_missing}; if (section_headers[CODE_SECTION].empty()) return {{}, EOFValidationError::code_section_missing}; - if (section_headers[CODE_SECTION].size() > 1 && - section_headers[TYPE_SECTION].empty()) - return {{}, EOFValidationError::mandatory_type_section_missing}; state = State::terminated; break; case TYPE_SECTION: diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index c646a2beed..26d9add786 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -69,7 +69,6 @@ enum class EOFValidationError invalid_rjump_destination, code_section_before_type_section, multiple_type_sections, - mandatory_type_section_missing, too_many_code_sections, data_section_before_code_section, data_section_before_types_section, diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 2186ea12ea..d705174ad2 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -116,6 +116,11 @@ TEST(eof_validation, EOF1_types_section_0_size) EOFValidationError::zero_section_size); } +TEST(eof_validation, EOF1_type_section_missing) +{ + EXPECT_EQ(validate_eof("EF0001 00"), EOFValidationError::type_section_missing); +} + TEST(eof_validation, EOF1_code_section_missing) { EXPECT_EQ(validate_eof("EF0001 010004 00"), EOFValidationError::code_section_missing); From d0a9c206bfcdb3402676f847e8136e7fcaaf2c19 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 21 Dec 2022 18:42:27 +0100 Subject: [PATCH 51/72] Remove terminating instruction requirement --- lib/evmone/eof.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index d3e049f070..7af063b4bb 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -202,9 +202,6 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe ++i; } - if (!instr::traits[op].is_terminating) - return EOFValidationError::missing_terminating_instruction; - return EOFValidationError::success; } From 2a1219c2c8b111c79493eb57541c56fd148b9e66 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 21 Dec 2022 18:57:57 +0100 Subject: [PATCH 52/72] Update unit tests after removing terminating instruction requirement --- lib/evmone/eof.cpp | 3 ++ lib/evmone/eof.hpp | 2 +- test/unittests/eof_validation_test.cpp | 38 ++++---------------------- 3 files changed, 9 insertions(+), 34 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 7af063b4bb..f55c03ae31 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -199,6 +199,9 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe return EOFValidationError::undefined_instruction; i += instr::traits[op].immediate_size; + if (i >= code.size()) + return EOFValidationError::truncated_instruction; + ++i; } diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index 26d9add786..aeb13a3d92 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -65,7 +65,7 @@ enum class EOFValidationError section_headers_not_terminated, invalid_section_bodies_size, undefined_instruction, - missing_terminating_instruction, + truncated_instruction, invalid_rjump_destination, code_section_before_type_section, multiple_type_sections, diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index d705174ad2..67e59691d6 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -340,7 +340,7 @@ TEST(eof_validation, EOF1_truncated_push) code_size_byte = static_cast(code.size()); const auto container = eof_header + code; - EXPECT_EQ(validate_eof(container), EOFValidationError::missing_terminating_instruction) + EXPECT_EQ(validate_eof(container), EOFValidationError::truncated_instruction) << hex(container); } @@ -352,34 +352,6 @@ TEST(eof_validation, EOF1_truncated_push) } } -TEST(eof_validation, EOF1_terminating_instructions) -{ - auto eof_header = "EF0001 010004 0200010001 00 00000000"_hex; - auto& code_size_byte = eof_header[10]; - - const auto& traits = evmone::instr::traits; - - for (uint16_t opcode = 0; opcode <= 0xff; ++opcode) - { - const auto& op_traits = traits[opcode]; - // Skip undefined opcodes. - // TODO: iterate over 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)}; - code_size_byte = static_cast(code.size()); - const auto container = eof_header + code; - - const auto expected = - ((opcode == OP_STOP || opcode == OP_RETURN || opcode == OP_RETF || - opcode == OP_REVERT || opcode == OP_INVALID || opcode == OP_SELFDESTRUCT) ? - EOFValidationError::success : - EOFValidationError::missing_terminating_instruction); - EXPECT_EQ(validate_eof(container), expected) << hex(code); - } -} - TEST(eof_validation, EOF1_valid_rjump) { // offset = 0 @@ -413,19 +385,19 @@ TEST(eof_validation, EOF1_valid_rjumpi) TEST(eof_validation, EOF1_rjump_truncated) { EXPECT_EQ(validate_eof("EF0001 010004 0200010001 00 00000000 5C"), - EOFValidationError::missing_terminating_instruction); + EOFValidationError::truncated_instruction); EXPECT_EQ(validate_eof("EF0001 010004 0200010002 00 00000000 5C00"), - EOFValidationError::missing_terminating_instruction); + EOFValidationError::truncated_instruction); } TEST(eof_validation, EOF1_rjumpi_truncated) { EXPECT_EQ(validate_eof("EF0001 010004 0200010003 00 00000000 60005D"), - EOFValidationError::missing_terminating_instruction); + EOFValidationError::truncated_instruction); EXPECT_EQ(validate_eof("EF0001 010004 0200010004 00 00000000 60005D00"), - EOFValidationError::missing_terminating_instruction); + EOFValidationError::truncated_instruction); } TEST(eof_validation, EOF1_rjump_invalid_destination) From bdcc8d47a89530f264ce3c4086291164dd510737 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 22 Dec 2022 15:56:45 +0100 Subject: [PATCH 53/72] Implement RJUMPV --- lib/evmone/advanced_instructions.cpp | 1 + lib/evmone/eof.cpp | 41 ++++++++++++- lib/evmone/instructions.hpp | 22 +++++++ lib/evmone/instructions_opcodes.hpp | 1 + lib/evmone/instructions_traits.hpp | 3 + lib/evmone/instructions_xmacro.hpp | 2 +- test/unittests/eof_validation_test.cpp | 82 ++++++++++++++++++++++++++ test/unittests/instructions_test.cpp | 10 ++-- 8 files changed, 155 insertions(+), 7 deletions(-) diff --git a/lib/evmone/advanced_instructions.cpp b/lib/evmone/advanced_instructions.cpp index 1a942b964f..a745ba6bd8 100644 --- a/lib/evmone/advanced_instructions.cpp +++ b/lib/evmone/advanced_instructions.cpp @@ -247,6 +247,7 @@ constexpr std::array instruction_implementations = []( table[OP_RJUMP] = op_undefined; table[OP_RJUMPI] = op_undefined; + table[OP_RJUMPV] = op_undefined; table[OP_CALLF] = op_undefined; table[OP_RETF] = op_undefined; diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index f55c03ae31..d0ba690427 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -198,7 +198,16 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe if (!since.has_value() || *since > rev) return EOFValidationError::undefined_instruction; - i += instr::traits[op].immediate_size; + if (op == OP_RJUMPV) + { + if (i + 1 < code.size()) + i += 1 /* count */ + code[i + 1] * 2 /* tbl */; + else + return EOFValidationError::truncated_instruction; + } + else + i += instr::traits[op].immediate_size; + if (i >= code.size()) return EOFValidationError::truncated_instruction; @@ -230,6 +239,36 @@ bool validate_rjump_destinations( return false; rjumpdests.push_back(static_cast(jumpdest)); } + else if (op == OP_RJUMPV) + { + constexpr auto REL_OFFSET_SIZE = sizeof(int16_t); + + const auto count = container[op_pos + 1]; + + const int32_t post_offset = 1 + 1 /* count */ + count * REL_OFFSET_SIZE /* tbl */; + + for (size_t k = 0; k < count; ++k) + { + const auto rel_offset_hi = + container[op_pos + 1 + 1 + static_cast(k) * REL_OFFSET_SIZE]; + const auto rel_offset_lo = + container[op_pos + 1 + 2 + static_cast(k) * REL_OFFSET_SIZE]; + const auto rel_offset = static_cast((rel_offset_hi << 8) + rel_offset_lo); + + const auto jumpdest = static_cast(i) + post_offset + rel_offset; + + if (jumpdest < 0 || jumpdest >= code_size) + return false; + + rjumpdests.push_back(static_cast(jumpdest)); + } + + const auto rjumpv_imm_size = size_t{1} + count * REL_OFFSET_SIZE; + std::fill_n( + immediate_map.begin() + static_cast(i) + 1, rjumpv_imm_size, true); + i += rjumpv_imm_size; + continue; + } const auto imm_size = instr::traits[op].immediate_size; std::fill_n(immediate_map.begin() + static_cast(i) + 1, imm_size, true); diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index 4afc632b57..fb778fb240 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -716,6 +716,28 @@ inline code_iterator rjumpi(StackTop stack, ExecutionState& state, code_iterator return cond ? rjump(stack, state, pc) : pc + 3; } +inline code_iterator rjumpv(StackTop stack, ExecutionState& /*state*/, code_iterator pc) noexcept +{ + constexpr auto REL_OFFSET_SIZE = sizeof(int16_t); + const auto case_ = stack.pop(); + + const auto count = pc[1]; + const auto pc_post = pc + 1 + 1 /* count */ + count * REL_OFFSET_SIZE /* tbl */; + + if (case_ >= count) + { + return pc_post; + } + else + { + const auto rel_offset_hi = pc[1 + static_cast(case_) * REL_OFFSET_SIZE]; + const auto rel_offset_lo = pc[2 + static_cast(case_) * REL_OFFSET_SIZE]; + const auto rel_offset = static_cast((rel_offset_hi << 8) + rel_offset_lo); + + return pc_post + rel_offset; + } +} + inline code_iterator pc(StackTop stack, ExecutionState& state, code_iterator pos) noexcept { stack.push(static_cast(pos - state.analysis.baseline->executable_code.data())); diff --git a/lib/evmone/instructions_opcodes.hpp b/lib/evmone/instructions_opcodes.hpp index 1b7409cbf2..9b430ce47a 100644 --- a/lib/evmone/instructions_opcodes.hpp +++ b/lib/evmone/instructions_opcodes.hpp @@ -84,6 +84,7 @@ enum Opcode : uint8_t OP_JUMPDEST = 0x5b, OP_RJUMP = 0x5c, OP_RJUMPI = 0x5d, + OP_RJUMPV = 0x5e, OP_PUSH0 = 0x5f, OP_PUSH1 = 0x60, diff --git a/lib/evmone/instructions_traits.hpp b/lib/evmone/instructions_traits.hpp index 196493e670..87752a8949 100644 --- a/lib/evmone/instructions_traits.hpp +++ b/lib/evmone/instructions_traits.hpp @@ -164,6 +164,7 @@ constexpr inline GasCostTable gas_costs = []() noexcept { table[EVMC_SHANGHAI][OP_PUSH0] = 2; table[EVMC_SHANGHAI][OP_RJUMP] = 2; table[EVMC_SHANGHAI][OP_RJUMPI] = 4; + table[EVMC_SHANGHAI][OP_RJUMPV] = 4; table[EVMC_SHANGHAI][OP_CALLF] = 5; table[EVMC_SHANGHAI][OP_RETF] = 3; @@ -292,6 +293,8 @@ constexpr inline std::array traits = []() noexcept { table[OP_JUMPDEST] = {"JUMPDEST", 0, false, 0, 0, EVMC_FRONTIER}; table[OP_RJUMP] = {"RJUMP", 2, false, 0, 0, EVMC_SHANGHAI}; table[OP_RJUMPI] = {"RJUMPI", 2, false, 1, -1, EVMC_SHANGHAI}; + table[OP_RJUMPV] = { + "RJUMPV", 0 /* WARNING: immediate_size is dynamic */, false, 1, -1, EVMC_SHANGHAI}; table[OP_PUSH0] = {"PUSH0", 0, false, 0, 1, EVMC_SHANGHAI}; diff --git a/lib/evmone/instructions_xmacro.hpp b/lib/evmone/instructions_xmacro.hpp index b411206497..7c81d7f135 100644 --- a/lib/evmone/instructions_xmacro.hpp +++ b/lib/evmone/instructions_xmacro.hpp @@ -131,7 +131,7 @@ ON_OPCODE_IDENTIFIER(OP_JUMPDEST, jumpdest) \ ON_OPCODE_IDENTIFIER(OP_RJUMP, rjump) \ ON_OPCODE_IDENTIFIER(OP_RJUMPI, rjumpi) \ - ON_OPCODE_UNDEFINED(0x5e) \ + ON_OPCODE_IDENTIFIER(OP_RJUMPV, rjumpv) \ ON_OPCODE_IDENTIFIER(OP_PUSH0, push0) \ \ ON_OPCODE_IDENTIFIER(OP_PUSH1, push<1>) \ diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 67e59691d6..493ee5f8be 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -382,6 +382,25 @@ TEST(eof_validation, EOF1_valid_rjumpi) EOFValidationError::success); } +TEST(eof_validation, EOF1_valid_rjumpv) +{ + // table = [0] case = 0 + EXPECT_EQ(validate_eof("EF0001 010004 0200010008 00 00000000 60005E0100006001"), + EOFValidationError::success); + + // table = [0,3] case = 0 + EXPECT_EQ(validate_eof("EF0001 010004 020001000D 00 00000000 60005E02000000036001006002"), + EOFValidationError::success); + + // table = [0,3] case = 2 + EXPECT_EQ(validate_eof("EF0001 010004 020001000D 00 00000000 60025E02000000036001006002"), + EOFValidationError::success); + + // table = [0,3,-10] case = 2 + EXPECT_EQ(validate_eof("EF0001 010004 020001000F 00 00000000 60025E0300000003FFF66001006002"), + EOFValidationError::success); +} + TEST(eof_validation, EOF1_rjump_truncated) { EXPECT_EQ(validate_eof("EF0001 010004 0200010001 00 00000000 5C"), @@ -400,6 +419,25 @@ TEST(eof_validation, EOF1_rjumpi_truncated) EOFValidationError::truncated_instruction); } +TEST(eof_validation, EOF1_rjumpv_truncated) +{ + // table = [0] case = 0 + EXPECT_EQ(validate_eof("EF0001 010004 0200010005 00 00000000 60005E0100"), + EOFValidationError::truncated_instruction); + + // table = [0,3] case = 0 + EXPECT_EQ(validate_eof("EF0001 010004 0200010007 00 00000000 60005E02000000"), + EOFValidationError::truncated_instruction); + + // table = [0,3] case = 2 + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60025E020000"), + EOFValidationError::truncated_instruction); + + // table = [0,3,-10] case = 2 + EXPECT_EQ(validate_eof("EF0001 010004 0200010009 00 00000000 60025E0300000003FF"), + EOFValidationError::truncated_instruction); +} + TEST(eof_validation, EOF1_rjump_invalid_destination) { // Into header (offset = -5) @@ -454,6 +492,50 @@ TEST(eof_validation, EOF1_rjumpi_invalid_destination) EOFValidationError::invalid_rjump_destination); } +TEST(eof_validation, EOF1_rjumpv_invalid_destination) +{ + // table = [-23] case = 0 + EXPECT_EQ(validate_eof("EF0001 010004 0200010008 00 00000000 60005E01FFE96001"), + EOFValidationError::invalid_rjump_destination); + + // table = [-8] case = 0 + EXPECT_EQ(validate_eof("EF0001 010004 0200010008 00 00000000 60005E01FFF86001"), + EOFValidationError::invalid_rjump_destination); + + // table = [-1] case = 0 + EXPECT_EQ(validate_eof("EF0001 010004 0200010008 00 00000000 60005E01FFFF6001"), + EOFValidationError::invalid_rjump_destination); + + // table = [2] case = 0 + EXPECT_EQ(validate_eof("EF0001 010004 0200010008 00 00000000 60005E0100026001"), + EOFValidationError::invalid_rjump_destination); + + // table = [3] case = 0 + EXPECT_EQ(validate_eof("EF0001 010004 0200010008 00 00000000 60005E0100036001"), + EOFValidationError::invalid_rjump_destination); + + + // table = [0,3,-27] case = 2 + EXPECT_EQ(validate_eof("EF0001 010004 020001000F 00 00000000 60025E0300000003FFE56001006002"), + EOFValidationError::invalid_rjump_destination); + + // table = [0,3,-12] case = 2 + EXPECT_EQ(validate_eof("EF0001 010004 020001000F 00 00000000 60025E0300000003FFF46001006002"), + EOFValidationError::invalid_rjump_destination); + + // table = [0,3,-1] case = 2 + EXPECT_EQ(validate_eof("EF0001 010004 020001000F 00 00000000 60025E0300000003FFFF6001006002"), + EOFValidationError::invalid_rjump_destination); + + // table = [0,3,5] case = 2 + EXPECT_EQ(validate_eof("EF0001 010004 020001000F 00 00000000 60025E030000000300056001006002"), + EOFValidationError::invalid_rjump_destination); + + // table = [0,3,6] case = 2 + EXPECT_EQ(validate_eof("EF0001 010004 020001000F 00 00000000 60025E030000000300066001006002"), + EOFValidationError::invalid_rjump_destination); +} + TEST(oef_validation, EOF1_section_order) { // 01 02 03 diff --git a/test/unittests/instructions_test.cpp b/test/unittests/instructions_test.cpp index 726135e828..a0bbf2c672 100644 --- a/test/unittests/instructions_test.cpp +++ b/test/unittests/instructions_test.cpp @@ -107,8 +107,8 @@ TEST(instructions, compare_with_evmc_instruction_tables) for (size_t i = 0; i < evmone_tbl.size(); ++i) { // TODO pending update in EVMC - if (r >= EVMC_SHANGHAI && - (i == OP_RJUMP || i == OP_RJUMPI || i == OP_CALLF || i == OP_RETF)) + if (r >= EVMC_SHANGHAI && (i == OP_RJUMP || i == OP_RJUMPI || i == OP_RJUMPV || + i == OP_CALLF || i == OP_RETF)) continue; // Skip DUPN and SWAPN for Cancun. They are not defined in evmc @@ -145,8 +145,8 @@ TEST(instructions, compare_undefined_instructions) for (size_t i = 0; i < instr_tbl.size(); ++i) { // TODO pending update in EVMC - if (r >= EVMC_SHANGHAI && - (i == OP_RJUMP || i == OP_RJUMPI || i == OP_CALLF || i == OP_RETF)) + if (r >= EVMC_SHANGHAI && (i == OP_RJUMP || i == OP_RJUMPI || i == OP_RJUMPV || + i == OP_CALLF || i == OP_RETF)) continue; // Skip DUPN and SWAPN. They are not defined in evmc @@ -164,7 +164,7 @@ TEST(instructions, compare_with_evmc_instruction_names) for (size_t i = 0; i < instr::traits.size(); ++i) { // TODO pending update in EVMC - if (i == OP_RJUMP || i == OP_RJUMPI || i == OP_CALLF || i == OP_RETF) + if (i == OP_RJUMP || i == OP_RJUMPI || i == OP_RJUMPV || i == OP_CALLF || i == OP_RETF) continue; // Skip DUPN and SWAPN. They are not defined in evmc From f023c377785d4bd4100645b2e27549d213bc05a4 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Fri, 23 Dec 2022 10:52:44 +0100 Subject: [PATCH 54/72] Fix sanitizers error --- lib/evmone/eof.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index d0ba690427..779684ce6d 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -190,7 +190,7 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe assert(!code.empty()); // guaranteed by EOF headers validation size_t i = 0; - uint8_t op = code[0]; + uint8_t op = 0; while (i < code.size()) { op = code[i]; @@ -201,7 +201,7 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe if (op == OP_RJUMPV) { if (i + 1 < code.size()) - i += 1 /* count */ + code[i + 1] * 2 /* tbl */; + i += static_cast(1 /* count */ + code[i + 1] * 2 /* tbl */); else return EOFValidationError::truncated_instruction; } @@ -245,7 +245,8 @@ bool validate_rjump_destinations( const auto count = container[op_pos + 1]; - const int32_t post_offset = 1 + 1 /* count */ + count * REL_OFFSET_SIZE /* tbl */; + const auto post_offset = + static_cast(1 + 1 /* count */ + count * REL_OFFSET_SIZE /* tbl */); for (size_t k = 0; k < count; ++k) { From b33a74eb6ce84c0a68469577c740344928f0c462 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Tue, 27 Dec 2022 16:07:55 +0100 Subject: [PATCH 55/72] Implement max stack height validation --- lib/evmone/eof.cpp | 133 +++++++++++++++++++++++++ lib/evmone/eof.hpp | 6 ++ test/unittests/analysis_test.cpp | 2 +- test/unittests/eof_validation_test.cpp | 62 ++++++++---- test/unittests/evm_eof_test.cpp | 41 ++++---- test/utils/bytecode.hpp | 14 +-- 6 files changed, 209 insertions(+), 49 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 779684ce6d..bfe945393d 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -5,10 +5,12 @@ #include "eof.hpp" #include "instructions_traits.hpp" +#include #include #include #include #include +#include #include namespace evmone @@ -284,6 +286,129 @@ bool validate_rjump_destinations( return true; } +std::pair validate_max_stack_height( + bytes_view code, size_t func_index, const std::vector& funcs_in_outs) +{ + assert(code.size() > 0); + std::vector stack_heights = std::vector(code.size(), -1); + std::stack worklist; + + int32_t stack_height = 0; + stack_heights[0] = funcs_in_outs[func_index].inputs_num; + worklist.push(0); + + size_t i = 0; + Opcode opcode = {}; + std::vector successors; + while (!worklist.empty()) + { + i = worklist.top(); + opcode = static_cast(code[i]); + worklist.pop(); + + auto stack_height_required = instr::traits[opcode].stack_height_required; + auto stack_height_change = instr::traits[opcode].stack_height_change; + + if (opcode == OP_CALLF) + { + auto fid_hi = code[i + 1]; + auto fid_lo = code[i + 2]; + auto fid = static_cast((fid_hi << 8) | fid_lo); + + stack_height_required = static_cast(funcs_in_outs[fid].inputs_num); + auto d = funcs_in_outs[fid].outputs_num - stack_height_required; + stack_height_change = static_cast(d); + } + + stack_height = stack_heights[i]; + assert(stack_height != -1); + + if (stack_height < stack_height_required) + return {EOFValidationError::stack_underflow, -1}; + + successors.clear(); + + // immediate_size for RJUMPV depends on the code. It's calculater below. + if (opcode != OP_RJUMP && !instr::traits[opcode].is_terminating && opcode != OP_RJUMPV) + { + auto next = i + instr::traits[opcode].immediate_size + 1; + if (next >= code.size()) + return {EOFValidationError::no_terminating_instruction, -1}; + + successors.push_back(next); + } + + if (opcode == OP_RJUMP || opcode == OP_RJUMPI) + { + auto target_rel_offset_hi = code[i + 1]; + auto target_rel_offset_lo = code[i + 2]; + auto target_rel_offset = + static_cast((target_rel_offset_hi << 8) | target_rel_offset_lo); + successors.push_back( + static_cast(target_rel_offset + 3 + static_cast(i))); + } + + if (opcode == OP_RJUMPV) + { + auto count = code[i + 1]; + + auto next = i + count * 2 + 2; + if (next >= code.size()) + return {EOFValidationError::no_terminating_instruction, -1}; + + auto beg = stack_heights.begin() + static_cast(i) + 1; + auto end = beg + count * 2 + 1; + for (auto it = beg; it < end; ++it) + *it = -2; + + successors.push_back(next); + + for (uint16_t k = 0; k < count; ++k) + { + auto target_rel_offset_hi = code[i + k * 2 + 2]; + auto target_rel_offset_lo = code[i + k * 2 + 3]; + auto target_rel_offset = + static_cast((target_rel_offset_hi << 8) | target_rel_offset_lo); + if (target_rel_offset != 0) // Already added before the loop + successors.push_back(i + 2 * count + target_rel_offset + 2); + } + } + else + { + auto beg = stack_heights.begin() + static_cast(i) + 1; + auto end = beg + instr::traits[opcode].immediate_size; + for (auto it = beg; it < end; ++it) + *it = -2; + } + + stack_height += stack_height_change; + + for (auto& s : successors) + { + if (stack_heights[s] == -1) + { + stack_heights[s] = stack_height; + worklist.push(s); + } + else if (stack_heights[s] != stack_height) + return {EOFValidationError::stack_height_mismatch, -1}; + } + + if (opcode == OP_RETF && stack_height != funcs_in_outs[func_index].outputs_num) + return {EOFValidationError::non_empty_stack_on_terminating_instruction, -1}; + } + + auto msh_it = std::max_element(stack_heights.begin(), stack_heights.end()); + + if (*msh_it > 1023) + return {EOFValidationError::max_stack_height_above_limit, -1}; + + if (std::find(stack_heights.begin(), stack_heights.end(), -1) != stack_heights.end()) + return {EOFValidationError::unreachable_instructions, -1}; + + return {EOFValidationError::success, *msh_it}; +} + std::pair validate_eof1( evmc_revision rev, bytes_view container) noexcept { @@ -323,6 +448,14 @@ std::pair validate_eof1( if (!validate_rjump_destinations(header, code_idx, container.begin())) return {{}, EOFValidationError::invalid_rjump_destination}; + + auto msh_validation_result = validate_max_stack_height( + {&container[header.code_begin(code_idx)], header.code_sizes[code_idx]}, code_idx, + header.types); + if (msh_validation_result.first != EOFValidationError::success) + return {{}, msh_validation_result.first}; + if (msh_validation_result.second != header.types[code_idx].max_stack_height) + return {{}, EOFValidationError::invalid_max_stack_height}; } return {header, EOFValidationError::success}; diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index aeb13a3d92..919be5ab94 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -75,6 +75,12 @@ enum class EOFValidationError invalid_type_section_size, invalid_first_section_type, invalid_max_stack_height, + no_terminating_instruction, + stack_height_mismatch, + non_empty_stack_on_terminating_instruction, + max_stack_height_above_limit, + unreachable_instructions, + stack_underflow, impossible, }; diff --git a/test/unittests/analysis_test.cpp b/test/unittests/analysis_test.cpp index ab39482819..9826e633af 100644 --- a/test/unittests/analysis_test.cpp +++ b/test/unittests/analysis_test.cpp @@ -259,7 +259,7 @@ TEST(analysis, jumpdests_groups) TEST(analysis, example1_eof1) { const auto code = eof1_bytecode( - push(0x2a) + push(0x1e) + OP_MSTORE8 + OP_MSIZE + push(0) + OP_SSTORE, "deadbeef"); + push(0x2a) + push(0x1e) + OP_MSTORE8 + OP_MSIZE + push(0) + OP_SSTORE, 2, "deadbeef"); const auto header = evmone::read_valid_eof1_header(bytes_view(code)); const auto analysis = analyze(EVMC_SHANGHAI, {&code[header.code_begin(0)], header.code_sizes[0]}); diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 493ee5f8be..51bab0d5a7 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -95,8 +95,9 @@ TEST(eof_validation, minimal_valid_EOF1_multiple_code_sections) EOFValidationError::success); // non-void input and output types - EXPECT_EQ(validate_eof("EF0001 010010 0200040001000200020002 00 00000000 01000000 00010000 " - "02030000 FE 5000 3000 8000"), + EXPECT_EQ(validate_eof("EF0001 010010 0200040001000200020002 00 " + "00000000 01000001 00010001 02030003" + "FE 5000 3000 8000"), EOFValidationError::success); } @@ -211,16 +212,16 @@ TEST(eof_validation, EOF1_truncated_section) TEST(eof_validation, EOF1_code_section_offset) { const auto eof = - "EF0001 010008 02000200020001 030004 00 0000000000000000 fefe fe 0000 0000"_hex; + "EF0001 010008 02000200030001 030004 00 00000001 00000000 6001fe fe 0000 0000"_hex; ASSERT_EQ(validate_eof(EVMC_CANCUN, eof), EOFValidationError::success); const auto header = read_valid_eof1_header(eof); ASSERT_EQ(header.code_sizes.size(), 2); - EXPECT_EQ(header.code_sizes[0], 2); + EXPECT_EQ(header.code_sizes[0], 3); EXPECT_EQ(header.code_sizes[1], 1); ASSERT_EQ(header.code_offsets.size(), 2); EXPECT_EQ(header.code_offsets[0], 25); - EXPECT_EQ(header.code_offsets[1], 27); + EXPECT_EQ(header.code_offsets[1], 28); } TEST(eof_validation, EOF1_trailing_bytes) @@ -303,25 +304,39 @@ TEST(eof_validation, EOF1_too_many_code_sections) TEST(eof_validation, EOF1_undefined_opcodes) { - auto cont = "EF0001 010004 0200010002 00 00000000 0000"_hex; - const auto& gas_table = evmone::instr::gas_costs[EVMC_SHANGHAI]; for (uint16_t opcode = 0; opcode <= 0xff; ++opcode) { + auto cont = + "EF0001 010004 0200010014 00 00000000 6001" + "80808080808080808080808080808080 " + ""_hex; + // Skip opcodes requiring immediate arguments. // They're all valid in Shanghai and checked in other tests below. if (opcode >= OP_PUSH1 && opcode <= OP_PUSH32) continue; - if (opcode == OP_RJUMP || opcode == OP_RJUMPI || opcode == OP_CALLF) + if (opcode == OP_RJUMP || opcode == OP_RJUMPI || opcode == OP_RJUMPV || + opcode == OP_CALLF || opcode == OP_RETF || opcode == OP_INVALID || opcode == OP_STOP || + opcode == OP_RETURN || opcode == OP_REVERT || opcode == OP_SELFDESTRUCT) continue; - cont[cont.size() - 2] = static_cast(opcode); + cont += static_cast(opcode); + if (!instr::traits[opcode].is_terminating) + cont += "00"_hex; + else + cont[10] = 0x13; + + + auto op_stack_change = instr::traits[opcode].stack_height_change; + cont[15] = static_cast(op_stack_change <= 0 ? 17 : 17 + op_stack_change); const auto expected = (gas_table[opcode] == evmone::instr::undefined ? EOFValidationError::undefined_instruction : EOFValidationError::success); - EXPECT_EQ(validate_eof(cont), expected) << hex(cont); + auto result = validate_eof(cont); + EXPECT_EQ(result, expected) << hex(cont); } EXPECT_EQ(validate_eof("EF0001 010004 0200010001 00 00000000 FE"), EOFValidationError::success); @@ -346,6 +361,9 @@ TEST(eof_validation, EOF1_truncated_push) const bytes code{opcode + bytes(required_bytes, 0) + uint8_t{OP_STOP}}; code_size_byte = static_cast(code.size()); + + eof_header[15] = static_cast(instr::traits[opcode].stack_height_change); + const auto container = eof_header + code; EXPECT_EQ(validate_eof(container), EOFValidationError::success) << hex(container); @@ -359,45 +377,45 @@ TEST(eof_validation, EOF1_valid_rjump) validate_eof("EF0001 010004 0200010004 00 00000000 5C000000"), EOFValidationError::success); // offset = 3 - EXPECT_EQ(validate_eof("EF0001 010004 0200010007 00 00000000 5C000300000000"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010009 00 00000001 5C00036001005CFFFA"), EOFValidationError::success); // offset = -4 - EXPECT_EQ(validate_eof("EF0001 010004 0200010005 00 00000000 005CFFFC00"), - EOFValidationError::success); + EXPECT_EQ( + validate_eof("EF0001 010004 0200010004 00 00000000 5B5CFFFC"), EOFValidationError::success); } TEST(eof_validation, EOF1_valid_rjumpi) { // offset = 0 - EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005D000000"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000001 60005D000000"), EOFValidationError::success); // offset = 3 - EXPECT_EQ(validate_eof("EF0001 010004 0200010009 00 00000000 60005D000300000000"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010009 00 00000001 60005D00035B5B5B00"), EOFValidationError::success); // offset = -5 - EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000000 60005DFFFB00"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 00 00000001 60005DFFFB00"), EOFValidationError::success); } TEST(eof_validation, EOF1_valid_rjumpv) { // table = [0] case = 0 - EXPECT_EQ(validate_eof("EF0001 010004 0200010008 00 00000000 60005E0100006001"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010009 00 00000001 60005E010000600100"), EOFValidationError::success); // table = [0,3] case = 0 - EXPECT_EQ(validate_eof("EF0001 010004 020001000D 00 00000000 60005E02000000036001006002"), + EXPECT_EQ(validate_eof("EF0001 010004 020001000E 00 00000001 60005E0200000003600100600200"), EOFValidationError::success); // table = [0,3] case = 2 - EXPECT_EQ(validate_eof("EF0001 010004 020001000D 00 00000000 60025E02000000036001006002"), + EXPECT_EQ(validate_eof("EF0001 010004 020001000E 00 00000001 60025E0200000003600100600200"), EOFValidationError::success); // table = [0,3,-10] case = 2 - EXPECT_EQ(validate_eof("EF0001 010004 020001000F 00 00000000 60025E0300000003FFF66001006002"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010010 00 00000001 60025E0300000003FFF6600100600200"), EOFValidationError::success); } @@ -536,10 +554,10 @@ TEST(eof_validation, EOF1_rjumpv_invalid_destination) EOFValidationError::invalid_rjump_destination); } -TEST(oef_validation, EOF1_section_order) +TEST(eof_validation, EOF1_section_order) { // 01 02 03 - EXPECT_EQ(validate_eof("EF0001 010004 0200010006 030002 00 00000000 60005D000000 AABB"), + EXPECT_EQ(validate_eof("EF0001 010004 0200010006 030002 00 00000001 60005D000000 AABB"), EOFValidationError::success); // 01 03 02 diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 18d8b6a6f8..1fbe5288ec 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -24,7 +24,7 @@ TEST_P(evm, eof1_execution_with_data_section) { rev = EVMC_SHANGHAI; // data section contains ret(0, 1) - const auto code = eof1_bytecode(mstore8(0, 1) + OP_STOP, ret(0, 1)); + const auto code = eof1_bytecode(mstore8(0, 1) + OP_STOP, 2, ret(0, 1)); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -34,14 +34,14 @@ TEST_P(evm, eof1_execution_with_data_section) TEST_P(evm, eof1_pc) { rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(OP_PC + mstore8(0) + ret(0, 1)); + auto code = eof1_bytecode(OP_PC + mstore8(0) + ret(0, 1), 2); execute(code); EXPECT_STATUS(EVMC_SUCCESS); ASSERT_EQ(result.output_size, 1); EXPECT_EQ(result.output_data[0], 0); - code = eof1_bytecode(4 * bytecode{OP_JUMPDEST} + OP_PC + mstore8(0) + ret(0, 1)); + code = eof1_bytecode(4 * bytecode{OP_JUMPDEST} + OP_PC + mstore8(0) + ret(0, 1), 2); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -52,15 +52,15 @@ TEST_P(evm, eof1_pc) TEST_P(evm, eof1_jump_inside_code_section) { rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(jump(4) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1)); + auto code = eof1_bytecode(jump(4) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1), 2); execute(code); EXPECT_STATUS(EVMC_SUCCESS); ASSERT_EQ(result.output_size, 1); EXPECT_EQ(result.output_data[0], 1); - code = - eof1_bytecode(jump(4) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1), "deadbeef"); + code = eof1_bytecode( + jump(4) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1), 3, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -79,7 +79,7 @@ TEST_P(evm, eof1_jumpi_inside_code_section) EXPECT_EQ(result.output_data[0], 1); code = eof1_bytecode( - jumpi(6, 1) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1), "deadbeef"); + jumpi(6, 1) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1), 2, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -91,7 +91,7 @@ TEST_P(evm, eof1_jump_into_data_section) { rev = EVMC_SHANGHAI; // data section contains OP_JUMPDEST + mstore8(0, 1) + ret(0, 1) - const auto code = eof1_bytecode(jump(4) + OP_STOP, OP_JUMPDEST + mstore8(0, 1) + ret(0, 1)); + const auto code = eof1_bytecode(jump(4) + OP_STOP, 1, OP_JUMPDEST + mstore8(0, 1) + ret(0, 1)); execute(code); EXPECT_STATUS(EVMC_BAD_JUMP_DESTINATION); @@ -101,7 +101,8 @@ TEST_P(evm, eof1_jumpi_into_data_section) { rev = EVMC_SHANGHAI; // data section contains OP_JUMPDEST + mstore8(0, 1) + ret(0, 1) - const auto code = eof1_bytecode(jumpi(6, 1) + OP_STOP, OP_JUMPDEST + mstore8(0, 1) + ret(0, 1)); + const auto code = + eof1_bytecode(jumpi(6, 1) + OP_STOP, 2, OP_JUMPDEST + mstore8(0, 1) + ret(0, 1)); execute(code); EXPECT_STATUS(EVMC_BAD_JUMP_DESTINATION); @@ -113,7 +114,7 @@ TEST_P(evm, eof1_push_byte_in_header) // data section is 0x65 bytes long, so header contains 0x65 (PUSH6) byte, // but it must not affect jumpdest analysis (OP_JUMPDEST stays valid) auto code = eof1_bytecode( - jump(4) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1), bytes(0x65, '\0')); + jump(4) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1), 2, bytes(0x65, '\0')); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -131,7 +132,7 @@ TEST_P(evm, eof1_codesize) ASSERT_EQ(result.output_size, 1); EXPECT_EQ(result.output_data[0], 28); - code = eof1_bytecode(mstore8(0, OP_CODESIZE) + ret(0, 1), "deadbeef"); + code = eof1_bytecode(mstore8(0, OP_CODESIZE) + ret(0, 1), 2, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -149,7 +150,7 @@ TEST_P(evm, eof1_codecopy_full) EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef0001010004020001000c0300000000000000601f6000600039601f6000f3"_hex); - code = eof1_bytecode(bytecode{35} + 0 + 0 + OP_CODECOPY + ret(0, 35), "deadbeef"); + code = eof1_bytecode(bytecode{35} + 0 + 0 + OP_CODECOPY + ret(0, 35), 3, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -160,14 +161,14 @@ TEST_P(evm, eof1_codecopy_full) TEST_P(evm, eof1_codecopy_header) { rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(bytecode{15} + 0 + 0 + OP_CODECOPY + ret(0, 15)); + auto code = eof1_bytecode(bytecode{15} + 0 + 0 + OP_CODECOPY + ret(0, 15), 3); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ( bytes_view(result.output_data, result.output_size), "ef0001010004020001000c03000000"_hex); - code = eof1_bytecode(bytecode{15} + 0 + 0 + OP_CODECOPY + ret(0, 15), "deadbeef"); + code = eof1_bytecode(bytecode{15} + 0 + 0 + OP_CODECOPY + ret(0, 15), 3, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -178,13 +179,13 @@ TEST_P(evm, eof1_codecopy_header) TEST_P(evm, eof1_codecopy_code) { rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(bytecode{12} + 19 + 0 + OP_CODECOPY + ret(0, 12)); + auto code = eof1_bytecode(bytecode{12} + 19 + 0 + OP_CODECOPY + ret(0, 12), 3); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ(bytes_view(result.output_data, result.output_size), "600c6013600039600c6000f3"_hex); - code = eof1_bytecode(bytecode{12} + 19 + 0 + OP_CODECOPY + ret(0, 12), "deadbeef"); + code = eof1_bytecode(bytecode{12} + 19 + 0 + OP_CODECOPY + ret(0, 12), 3, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -195,7 +196,7 @@ TEST_P(evm, eof1_codecopy_data) { rev = EVMC_SHANGHAI; - const auto code = eof1_bytecode(bytecode{4} + 31 + 0 + OP_CODECOPY + ret(0, 4), "deadbeef"); + const auto code = eof1_bytecode(bytecode{4} + 31 + 0 + OP_CODECOPY + ret(0, 4), 3, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -213,7 +214,7 @@ TEST_P(evm, eof1_codecopy_out_of_bounds) EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef0001010004020001000c03000000000000006023600060003960236000f300000000"_hex); - code = eof1_bytecode(bytecode{39} + 0 + 0 + OP_CODECOPY + ret(0, 39), "deadbeef"); + code = eof1_bytecode(bytecode{39} + 0 + 0 + OP_CODECOPY + ret(0, 39), 3, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -235,7 +236,7 @@ TEST_P(evm, eof2_rjump) ASSERT_EQ(result.output_size, 1); EXPECT_EQ(result.output_data[0], 1); - code = eof1_bytecode(rjump(1) + OP_INVALID + mstore8(0, 1) + ret(0, 1), "deadbeef"); + code = eof1_bytecode(rjump(1) + OP_INVALID + mstore8(0, 1) + ret(0, 1), 2, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -259,7 +260,7 @@ TEST_P(evm, eof2_rjump_backward) EXPECT_EQ(result.output_data[0], 1); code = eof1_bytecode( - rjump(11) + OP_INVALID + mstore8(0, 1) + ret(0, 1) + rjump(-13) + OP_STOP, "deadbeef"); + rjump(11) + OP_INVALID + mstore8(0, 1) + ret(0, 1) + rjump(-13) + OP_STOP, 2, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); diff --git a/test/utils/bytecode.hpp b/test/utils/bytecode.hpp index e676a6688d..c0d212d066 100644 --- a/test/utils/bytecode.hpp +++ b/test/utils/bytecode.hpp @@ -90,27 +90,29 @@ big_endian(T value) return {static_cast(value >> 8), static_cast(value)}; } -inline bytecode eof_header(uint8_t version, uint16_t code_size, uint16_t data_size) +inline bytecode eof_header( + uint8_t version, uint16_t code_size, uint16_t max_stack_height, uint16_t data_size) { bytecode out{bytes{0xEF, 0x00, version}}; out += "01" + big_endian(uint16_t{4}); // type header out += "02"_hex + big_endian(uint16_t{1}) + big_endian(code_size); out += "03" + big_endian(data_size); out += "00"; - out += "00000000"; // type section + out += "0000"_hex + big_endian(max_stack_height); // type section return out; } -inline bytecode eof1_header(uint16_t code_size, uint16_t data_size = 0) +inline bytecode eof1_header(uint16_t code_size, uint16_t max_stack_height, uint16_t data_size = 0) { - return eof_header(1, code_size, data_size); + return eof_header(1, code_size, max_stack_height, data_size); } -inline bytecode eof1_bytecode(bytecode code, bytecode data = {}) +inline bytecode eof1_bytecode(bytecode code, uint16_t max_stack_height = 0, bytecode data = {}) { assert(code.size() <= std::numeric_limits::max()); assert(data.size() <= std::numeric_limits::max()); - return eof1_header(static_cast(code.size()), static_cast(data.size())) + + return eof1_header(static_cast(code.size()), max_stack_height, + static_cast(data.size())) + code + data; } From a5f2c4f3eeb483eb1189d8f52de43c90aaa9f362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Dec 2022 13:21:34 +0100 Subject: [PATCH 56/72] eof: Switch instruction validation to baseline cost table --- lib/evmone/eof.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index bfe945393d..bef4334dbb 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -4,6 +4,7 @@ #include "eof.hpp" #include "instructions_traits.hpp" +#include "baseline_instruction_table.hpp" #include #include @@ -191,13 +192,14 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe { assert(!code.empty()); // guaranteed by EOF headers validation + const auto& cost_table = baseline::get_baseline_cost_table(rev, 1); + size_t i = 0; uint8_t op = 0; while (i < code.size()) { op = code[i]; - const auto& since = instr::traits[op].since; - if (!since.has_value() || *since > rev) + if (cost_table[op] == instr::undefined) return EOFValidationError::undefined_instruction; if (op == OP_RJUMPV) From bcc15ac791be10b39c4f04518166192d5fd08cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Dec 2022 13:32:01 +0100 Subject: [PATCH 57/72] eof: Reject deprecated instructions --- lib/evmone/baseline_instruction_table.cpp | 14 ++++++++++++-- test/unittests/eof_validation_test.cpp | 8 ++++++++ test/unittests/evm_eof_test.cpp | 12 ++++++------ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/evmone/baseline_instruction_table.cpp b/lib/evmone/baseline_instruction_table.cpp index ed9b2c0c94..6de7449fb5 100644 --- a/lib/evmone/baseline_instruction_table.cpp +++ b/lib/evmone/baseline_instruction_table.cpp @@ -10,7 +10,7 @@ namespace evmone::baseline { namespace { -constexpr auto eof_cost_tables = []() noexcept { +constexpr auto common_cost_tables = []() noexcept { std::array tables{}; for (size_t r = EVMC_FRONTIER; r <= EVMC_MAX_REVISION; ++r) { @@ -24,12 +24,22 @@ constexpr auto eof_cost_tables = []() noexcept { }(); constexpr auto legacy_cost_tables = []() noexcept { - auto tables = eof_cost_tables; + auto tables = common_cost_tables; tables[EVMC_SHANGHAI][OP_RJUMP] = instr::undefined; tables[EVMC_SHANGHAI][OP_RJUMPI] = instr::undefined; return tables; }(); +constexpr auto eof_cost_tables = []() noexcept { + auto tables = common_cost_tables; + tables[EVMC_SHANGHAI][OP_JUMP] = instr::undefined; + tables[EVMC_SHANGHAI][OP_JUMPI] = instr::undefined; + tables[EVMC_SHANGHAI][OP_PC] = instr::undefined; + tables[EVMC_SHANGHAI][OP_CALLCODE] = instr::undefined; + tables[EVMC_SHANGHAI][OP_SELFDESTRUCT] = instr::undefined; + return tables; +}(); + } // namespace const CostTable& get_baseline_cost_table(evmc_revision rev, uint8_t eof_version) noexcept diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index 51bab0d5a7..ad2860dd88 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -580,3 +580,11 @@ TEST(eof_validation, EOF1_section_order) EXPECT_EQ(validate_eof("EF0001 030002 0200010006 010004 00 AABB 60005D000000 00000000"), EOFValidationError::data_section_before_types_section); } + +TEST(eof_validation, deprecated_instructions) +{ + for (auto op : {OP_CALLCODE, OP_SELFDESTRUCT, OP_JUMP, OP_JUMPI, OP_PC}) + { + EXPECT_EQ(validate_eof(eof1_bytecode(op)), EOFValidationError::undefined_instruction); + } +} diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 1fbe5288ec..a338061135 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -31,7 +31,7 @@ TEST_P(evm, eof1_execution_with_data_section) EXPECT_EQ(result.output_size, 0); } -TEST_P(evm, eof1_pc) +TEST_P(evm, DISABLED_eof1_pc) { rev = EVMC_SHANGHAI; auto code = eof1_bytecode(OP_PC + mstore8(0) + ret(0, 1), 2); @@ -49,7 +49,7 @@ TEST_P(evm, eof1_pc) EXPECT_EQ(result.output_data[0], 4); } -TEST_P(evm, eof1_jump_inside_code_section) +TEST_P(evm, DISABLED_eof1_jump_inside_code_section) { rev = EVMC_SHANGHAI; auto code = eof1_bytecode(jump(4) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1), 2); @@ -68,7 +68,7 @@ TEST_P(evm, eof1_jump_inside_code_section) EXPECT_EQ(result.output_data[0], 1); } -TEST_P(evm, eof1_jumpi_inside_code_section) +TEST_P(evm, DISABLED_eof1_jumpi_inside_code_section) { rev = EVMC_SHANGHAI; auto code = eof1_bytecode(jumpi(6, 1) + OP_INVALID + OP_JUMPDEST + mstore8(0, 1) + ret(0, 1)); @@ -87,7 +87,7 @@ TEST_P(evm, eof1_jumpi_inside_code_section) EXPECT_EQ(result.output_data[0], 1); } -TEST_P(evm, eof1_jump_into_data_section) +TEST_P(evm, DISABLED_eof1_jump_into_data_section) { rev = EVMC_SHANGHAI; // data section contains OP_JUMPDEST + mstore8(0, 1) + ret(0, 1) @@ -97,7 +97,7 @@ TEST_P(evm, eof1_jump_into_data_section) EXPECT_STATUS(EVMC_BAD_JUMP_DESTINATION); } -TEST_P(evm, eof1_jumpi_into_data_section) +TEST_P(evm, DISABLED_eof1_jumpi_into_data_section) { rev = EVMC_SHANGHAI; // data section contains OP_JUMPDEST + mstore8(0, 1) + ret(0, 1) @@ -108,7 +108,7 @@ TEST_P(evm, eof1_jumpi_into_data_section) EXPECT_STATUS(EVMC_BAD_JUMP_DESTINATION); } -TEST_P(evm, eof1_push_byte_in_header) +TEST_P(evm, DISABLED_eof1_push_byte_in_header) { rev = EVMC_SHANGHAI; // data section is 0x65 bytes long, so header contains 0x65 (PUSH6) byte, From f4ea517aad7255497f394d5102cad0663ccaa93a Mon Sep 17 00:00:00 2001 From: rodiazet Date: Tue, 27 Dec 2022 17:42:21 +0100 Subject: [PATCH 58/72] eof: Fix unit tests --- lib/evmone/eof.cpp | 12 +++----- test/unittests/eof_validation_test.cpp | 25 ++++++++++------ test/unittests/evm_eof_test.cpp | 40 +++++++++++++------------- test/unittests/tracing_test.cpp | 2 +- 4 files changed, 42 insertions(+), 37 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index bef4334dbb..5bf0bffea8 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -3,8 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 #include "eof.hpp" -#include "instructions_traits.hpp" #include "baseline_instruction_table.hpp" +#include "instructions_traits.hpp" #include #include @@ -330,7 +330,7 @@ std::pair validate_max_stack_height( successors.clear(); - // immediate_size for RJUMPV depends on the code. It's calculater below. + // immediate_size for RJUMPV depends on the code. It's calculated below. if (opcode != OP_RJUMP && !instr::traits[opcode].is_terminating && opcode != OP_RJUMPV) { auto next = i + instr::traits[opcode].immediate_size + 1; @@ -359,9 +359,7 @@ std::pair validate_max_stack_height( return {EOFValidationError::no_terminating_instruction, -1}; auto beg = stack_heights.begin() + static_cast(i) + 1; - auto end = beg + count * 2 + 1; - for (auto it = beg; it < end; ++it) - *it = -2; + std::fill_n(beg, count * 2 + 1, -2); successors.push_back(next); @@ -378,9 +376,7 @@ std::pair validate_max_stack_height( else { auto beg = stack_heights.begin() + static_cast(i) + 1; - auto end = beg + instr::traits[opcode].immediate_size; - for (auto it = beg; it < end; ++it) - *it = -2; + std::fill_n(beg, instr::traits[opcode].immediate_size, -2); } stack_height += stack_height_change; diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index ad2860dd88..d8c03b5b5a 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -317,17 +317,26 @@ TEST(eof_validation, EOF1_undefined_opcodes) // They're all valid in Shanghai and checked in other tests below. if (opcode >= OP_PUSH1 && opcode <= OP_PUSH32) continue; - if (opcode == OP_RJUMP || opcode == OP_RJUMPI || opcode == OP_RJUMPV || - opcode == OP_CALLF || opcode == OP_RETF || opcode == OP_INVALID || opcode == OP_STOP || - opcode == OP_RETURN || opcode == OP_REVERT || opcode == OP_SELFDESTRUCT) + if (opcode == OP_RJUMP || opcode == OP_RJUMPI || opcode == OP_RJUMPV || opcode == OP_CALLF) + continue; + if (opcode == OP_JUMP || opcode == OP_JUMPI || opcode == OP_PC || opcode == OP_CALLCODE || + opcode == OP_SELFDESTRUCT) continue; - cont += static_cast(opcode); - if (!instr::traits[opcode].is_terminating) - cont += "00"_hex; + if (opcode == OP_RETF) + { + cont += "5050505050505050505050505050505050"_hex; + cont += static_cast(opcode); + cont[10] = 0x24; + } else - cont[10] = 0x13; - + { + cont += static_cast(opcode); + if (!instr::traits[opcode].is_terminating) + cont += "00"_hex; + else + cont[10] = 0x13; + } auto op_stack_change = instr::traits[opcode].stack_height_change; cont[15] = static_cast(op_stack_change <= 0 ? 17 : 17 + op_stack_change); diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index a338061135..f68e5a1a85 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -125,7 +125,7 @@ TEST_P(evm, DISABLED_eof1_push_byte_in_header) TEST_P(evm, eof1_codesize) { rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(mstore8(0, OP_CODESIZE) + ret(0, 1)); + auto code = eof1_bytecode(mstore8(0, OP_CODESIZE) + ret(0, 1), 2); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -143,19 +143,19 @@ TEST_P(evm, eof1_codesize) TEST_P(evm, eof1_codecopy_full) { rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(bytecode{31} + 0 + 0 + OP_CODECOPY + ret(0, 31)); + auto code = eof1_bytecode(bytecode{31} + 0 + 0 + OP_CODECOPY + ret(0, 31), 3); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "ef0001010004020001000c0300000000000000601f6000600039601f6000f3"_hex); + "ef0001010004020001000c0300000000000003601f6000600039601f6000f3"_hex); code = eof1_bytecode(bytecode{35} + 0 + 0 + OP_CODECOPY + ret(0, 35), 3, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "ef0001010004020001000c03000400000000006023600060003960236000f3deadbeef"_hex); + "ef0001010004020001000c03000400000000036023600060003960236000f3deadbeef"_hex); } TEST_P(evm, eof1_codecopy_header) @@ -207,19 +207,19 @@ TEST_P(evm, eof1_codecopy_out_of_bounds) { // 4 bytes out of container bounds - result is implicitly 0-padded rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(bytecode{35} + 0 + 0 + OP_CODECOPY + ret(0, 35)); + auto code = eof1_bytecode(bytecode{35} + 0 + 0 + OP_CODECOPY + ret(0, 35), 3); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "ef0001010004020001000c03000000000000006023600060003960236000f300000000"_hex); + "ef0001010004020001000c03000000000000036023600060003960236000f300000000"_hex); code = eof1_bytecode(bytecode{39} + 0 + 0 + OP_CODECOPY + ret(0, 39), 3, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "ef0001010004020001000c03000400000000006027600060003960276000f3deadbeef00000000"_hex); + "ef0001010004020001000c03000400000000036027600060003960276000f3deadbeef00000000"_hex); } TEST_P(evm, eof2_rjump) @@ -229,14 +229,15 @@ TEST_P(evm, eof2_rjump) return; rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(rjump(1) + OP_INVALID + mstore8(0, 1) + ret(0, 1)); + auto code = eof1_bytecode(rjumpi(3, 0) + rjump(1) + OP_INVALID + mstore8(0, 1) + ret(0, 1), 2); execute(code); EXPECT_STATUS(EVMC_SUCCESS); ASSERT_EQ(result.output_size, 1); EXPECT_EQ(result.output_data[0], 1); - code = eof1_bytecode(rjump(1) + OP_INVALID + mstore8(0, 1) + ret(0, 1), 2, "deadbeef"); + code = eof1_bytecode( + rjumpi(3, 0) + rjump(1) + OP_INVALID + mstore8(0, 1) + ret(0, 1), 2, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -251,16 +252,14 @@ TEST_P(evm, eof2_rjump_backward) return; rev = EVMC_SHANGHAI; - auto code = - eof1_bytecode(rjump(11) + OP_INVALID + mstore8(0, 1) + ret(0, 1) + rjump(-13) + OP_STOP); + auto code = eof1_bytecode(rjump(10) + mstore8(0, 1) + ret(0, 1) + rjump(-13), 2); execute(code); EXPECT_STATUS(EVMC_SUCCESS); ASSERT_EQ(result.output_size, 1); EXPECT_EQ(result.output_data[0], 1); - code = eof1_bytecode( - rjump(11) + OP_INVALID + mstore8(0, 1) + ret(0, 1) + rjump(-13) + OP_STOP, 2, "deadbeef"); + code = eof1_bytecode(rjump(10) + mstore8(0, 1) + ret(0, 1) + rjump(-13), 2, "deadbeef"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -275,7 +274,7 @@ TEST_P(evm, eof2_rjump_0_offset) return; rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(rjump(0) + mstore8(0, 1) + ret(0, 1)); + auto code = eof1_bytecode(rjump(0) + mstore8(0, 1) + ret(0, 1), 2); execute(code); EXPECT_STATUS(EVMC_SUCCESS); @@ -291,7 +290,7 @@ TEST_P(evm, eof2_rjumpi) rev = EVMC_SHANGHAI; auto code = eof1_bytecode( - rjumpi(10, calldataload(0)) + mstore8(0, 2) + ret(0, 1) + mstore8(0, 1) + ret(0, 1)); + rjumpi(10, calldataload(0)) + mstore8(0, 2) + ret(0, 1) + mstore8(0, 1) + ret(0, 1), 2); // RJUMPI condition is true execute(code, "01"_hex); @@ -313,8 +312,9 @@ TEST_P(evm, eof2_rjumpi_backwards) return; rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(rjump(11) + OP_INVALID + mstore8(0, 1) + ret(0, 1) + - rjumpi(-16, calldataload(0)) + mstore8(0, 2) + ret(0, 1)); + auto code = eof1_bytecode(rjump(10) + mstore8(0, 1) + ret(0, 1) + rjumpi(-16, calldataload(0)) + + mstore8(0, 2) + ret(0, 1), + 2); // RJUMPI condition is true execute(code, "01"_hex); @@ -336,7 +336,7 @@ TEST_P(evm, eof2_rjumpi_0_offset) return; rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(rjumpi(0, calldataload(0)) + mstore8(0, 1) + ret(0, 1)); + auto code = eof1_bytecode(rjumpi(0, calldataload(0)) + mstore8(0, 1) + ret(0, 1), 2); // RJUMPI condition is true execute(code, "01"_hex); @@ -375,7 +375,7 @@ TEST_P(evm, eof_function_example1) rev = EVMC_SHANGHAI; const auto code = "EF00 01 010008 020002 000f 0002 00" - "00000005 02010000" + "00000002 02010002" "6001 6008 b00001 " + ret_top() + "03b1"; @@ -394,7 +394,7 @@ TEST_P(evm, eof_function_example2) rev = EVMC_SHANGHAI; const auto code = - "ef0001 01000c 020003 003b 0017 001d 00 00000400 01010400 01010400" + "ef0001 01000c 020003 003b 0017 001d 00 00000004 01010003 01010004" "60043560003560e01c63c766526781145d001c63c6c2ea1781145d00065050600080fd50b00002600052602060" "00f350b0000160005260206000f3" "600181115d0004506001b160018103b0000181029050b1" diff --git a/test/unittests/tracing_test.cpp b/test/unittests/tracing_test.cpp index e08a7a020c..2995ed58b7 100644 --- a/test/unittests/tracing_test.cpp +++ b/test/unittests/tracing_test.cpp @@ -297,7 +297,7 @@ TEST_F(tracing, trace_eof) vm.add_tracer(evmone::create_instruction_tracer(trace_stream)); trace_stream << '\n'; - EXPECT_EQ(trace(eof1_bytecode(add(2, 3) + OP_STOP), 0, 0, EVMC_SHANGHAI), R"( + EXPECT_EQ(trace(eof1_bytecode(add(2, 3) + OP_STOP, 2), 0, 0, EVMC_SHANGHAI), R"( {"depth":0,"rev":"Shanghai","static":false} {"pc":0,"op":96,"opName":"PUSH1","gas":1000000,"stack":[],"memorySize":0} {"pc":2,"op":96,"opName":"PUSH1","gas":999997,"stack":["0x3"],"memorySize":0} From 8c041edc20e040e341a2f03821026ac3124258b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Dec 2022 09:17:09 +0100 Subject: [PATCH 59/72] test: Add EOF data only contract test --- test/unittests/evm_eof_test.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index f68e5a1a85..80592a6ec4 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -416,3 +416,26 @@ TEST_P(evm, eof_function_example2) EXPECT_GAS_USED(EVMC_SUCCESS, 44544); EXPECT_EQ(output, "0000000000000000000000000000000000000000000000000000000000000262"_hex); } + + +TEST_P(evm, eof_data_only_contract) +{ + if (is_advanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = "EF0001 010004 020001 0001 03daaa 00 00000000 FE"_hex; + const auto data_size_ptr = &code[code.find(0xda)]; + + intx::be::unsafe::store(data_size_ptr, uint16_t{0}); + execute(code); + EXPECT_STATUS(EVMC_INVALID_INSTRUCTION); + + intx::be::unsafe::store(data_size_ptr, uint16_t{1}); + execute(code + "aa"_hex); + EXPECT_STATUS(EVMC_INVALID_INSTRUCTION); + + intx::be::unsafe::store(data_size_ptr, uint16_t{256}); + execute(code + bytes(256, 0x01)); + EXPECT_STATUS(EVMC_INVALID_INSTRUCTION); +} From 1c91f929e34b36a2d26f0df2d18f62f639d24259 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 28 Dec 2022 12:51:22 +0100 Subject: [PATCH 60/72] Fix sanitizers testing error --- lib/evmone/eof.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 5bf0bffea8..1bb9909f9a 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -368,9 +368,9 @@ std::pair validate_max_stack_height( auto target_rel_offset_hi = code[i + k * 2 + 2]; auto target_rel_offset_lo = code[i + k * 2 + 3]; auto target_rel_offset = - static_cast((target_rel_offset_hi << 8) | target_rel_offset_lo); - if (target_rel_offset != 0) // Already added before the loop - successors.push_back(i + 2 * count + target_rel_offset + 2); + static_cast((target_rel_offset_hi << 8) | target_rel_offset_lo); + successors.push_back(static_cast( + static_cast(i) + 2 * count + target_rel_offset + 2)); } } else From 4667b64febf65367050138a09e297c36b2ef7bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 28 Dec 2022 15:53:36 +0100 Subject: [PATCH 61/72] host: Enforce EOF code from EOF initcode --- test/state/host.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/state/host.cpp b/test/state/host.cpp index 3803e08e7d..13ce92f0a5 100644 --- a/test/state/host.cpp +++ b/test/state/host.cpp @@ -194,6 +194,7 @@ evmc::Result Host::create(const evmc_message& msg) noexcept new_acc.balance += value; // The new account may be prefunded. auto create_msg = msg; + const bytes_view initcode{msg.input_data, msg.input_size}; create_msg.input_data = nullptr; create_msg.input_size = 0; @@ -220,7 +221,7 @@ evmc::Result Host::create(const evmc_message& msg) noexcept evmc::Result{EVMC_FAILURE}; } - if (m_rev >= EVMC_SHANGHAI && is_eof_code(code)) + if (m_rev >= EVMC_SHANGHAI && (is_eof_code(initcode) || is_eof_code(code))) { if (validate_eof(m_rev, code) != EOFValidationError::success) return evmc::Result{EVMC_CONTRACT_VALIDATION_FAILURE}; From 79baead8fb6e020d983a3914ec2053b5d0e68020 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 28 Dec 2022 17:19:02 +0100 Subject: [PATCH 62/72] eof: Ensure that eof contract creates only valid eof contract --- lib/evmone/baseline.cpp | 12 ++----- lib/evmone/instructions_calls.cpp | 7 +++++ test/unittests/evm_eof_test.cpp | 52 +++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/lib/evmone/baseline.cpp b/lib/evmone/baseline.cpp index e4d0cd244d..32c1d8bec2 100644 --- a/lib/evmone/baseline.cpp +++ b/lib/evmone/baseline.cpp @@ -374,16 +374,8 @@ evmc_result execute(evmc_vm* c_vm, const evmc_host_interface* host, evmc_host_co // other places like create instructions. if (validate_eof(rev, {code, code_size}) != EOFValidationError::success) { - if ((msg->kind == EVMC_CREATE || msg->kind == EVMC_CREATE2)) - { - // TODO(EOF): Should this be light error (gas is returned)? - return evmc::Result{EVMC_CONTRACT_VALIDATION_FAILURE, msg->gas}.release_raw(); - } - else - { - // TODO(EOF): This should never happen but protects against invalid tests for now. - return evmc::Result{EVMC_INTERNAL_ERROR}.release_raw(); - } + // TODO(EOF): This should never happen but protects against invalid tests for now. + return evmc::Result{EVMC_INTERNAL_ERROR}.release_raw(); } } diff --git a/lib/evmone/instructions_calls.cpp b/lib/evmone/instructions_calls.cpp index c75bd14fbf..54ae5d7dfc 100644 --- a/lib/evmone/instructions_calls.cpp +++ b/lib/evmone/instructions_calls.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "eips.hpp" +#include "eof.hpp" #include "instructions.hpp" namespace evmone::instr::core @@ -168,6 +169,12 @@ evmc_status_code create_impl(StackTop stack, ExecutionState& state) noexcept msg.input_data = &state.memory[size_t(init_code_offset)]; msg.input_size = size_t(init_code_size); } + + if (is_eof_code(state.original_code)) + if (validate_eof(state.rev, {msg.input_data, msg.input_size}) != + EOFValidationError::success) + return EVMC_SUCCESS; + msg.sender = state.msg->recipient; msg.depth = state.msg->depth + 1; msg.create2_salt = intx::be::store(salt); diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 80592a6ec4..599ba4105f 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -6,6 +6,7 @@ #include "evmone/eof.hpp" using evmone::test::evm; +using namespace evmc::literals; TEST_P(evm, eof1_execution) { @@ -439,3 +440,54 @@ TEST_P(evm, eof_data_only_contract) execute(code + bytes(256, 0x01)); EXPECT_STATUS(EVMC_INVALID_INSTRUCTION); } + +TEST_P(evm, eof_creates_valid_eof_contract_only) +{ + rev = EVMC_SHANGHAI; + host.call_result.create_address = 0x02_address; + { + // invalid eof contract (push1 truncated) + auto new_contract = "EF0001 010004 0200010001 030000 00 00000000 60"; + auto code = + eof1_bytecode(bytecode{20} + 41 + 0 + OP_CODECOPY + 20 + 0 + 0 + OP_CREATE + ret_top(), + 3, new_contract); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(0); + } + + { + // valid eof contract + auto new_contract = "EF0001 010004 0200010001 030000 00 00000000 FE"; + auto code = + eof1_bytecode(bytecode{20} + 41 + 0 + OP_CODECOPY + 20 + 0 + 0 + OP_CREATE + ret_top(), + 3, new_contract); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(2); + } + + { + // non-eof contract + auto new_contract = "FE"; + auto code = + eof1_bytecode(bytecode{1} + 34 + 0 + OP_CODECOPY + 1 + 0 + 0 + OP_CREATE + ret_top(), 3, + new_contract); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(0); + } + + { + // empty contract + auto code = eof1_bytecode( + bytecode{0} + 34 + 0 + OP_CODECOPY + 0 + 0 + 0 + OP_CREATE + ret_top(), 3); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(0); + } +} From 403e9701fe0fdb3ee2de90b0361583952e071517 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Wed, 28 Dec 2022 21:17:41 +0100 Subject: [PATCH 63/72] test: Add basic test for RJUMPV --- test/unittests/evm_eof_test.cpp | 18 ++++++++++++++++++ test/utils/bytecode.hpp | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 599ba4105f..f733fc5123 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -352,6 +352,24 @@ TEST_P(evm, eof2_rjumpi_0_offset) EXPECT_EQ(result.output_data[0], 1); } +TEST_P(evm, eof1_rjumpv_single_offset) +{ + // Relative jumps are not implemented in Advanced. + if (is_advanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = eof1_bytecode(rjumpv({3}, 0) + OP_JUMPDEST + OP_JUMPDEST + OP_STOP + 20 + 40 + 0 + + OP_CODECOPY + ret(0, 20), + 3, "ef000101000402000100010300000000000000fe"); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 20); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), + "ef000101000402000100010300000000000000fe"_hex); +} + TEST_P(evm, relative_jumps_undefined_in_legacy) { diff --git a/test/utils/bytecode.hpp b/test/utils/bytecode.hpp index c0d212d066..2a6cc441bd 100644 --- a/test/utils/bytecode.hpp +++ b/test/utils/bytecode.hpp @@ -254,6 +254,14 @@ inline bytecode rjumpi(int16_t offset, bytecode condition) return condition + OP_RJUMPI + bytecode{big_endian(offset)}; } +inline bytecode rjumpv(const std::initializer_list offsets, bytecode condition) +{ + bytecode ret = condition + OP_RJUMPV + static_cast(offsets.size()); + for (const auto offset : offsets) + ret += bytecode{big_endian(offset)}; + return ret; +} + inline bytecode ret(bytecode index, bytecode size) { return size + index + OP_RETURN; From 21c646692b0aead9e3ed00f9ad3ed29c8e8418cd Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Wed, 28 Dec 2022 21:21:30 +0100 Subject: [PATCH 64/72] Fix off-by-one error in RJUMPV implementation --- lib/evmone/instructions.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/evmone/instructions.hpp b/lib/evmone/instructions.hpp index fb778fb240..f9169e35b4 100644 --- a/lib/evmone/instructions.hpp +++ b/lib/evmone/instructions.hpp @@ -730,8 +730,8 @@ inline code_iterator rjumpv(StackTop stack, ExecutionState& /*state*/, code_iter } else { - const auto rel_offset_hi = pc[1 + static_cast(case_) * REL_OFFSET_SIZE]; - const auto rel_offset_lo = pc[2 + static_cast(case_) * REL_OFFSET_SIZE]; + const auto rel_offset_hi = pc[2 + static_cast(case_) * REL_OFFSET_SIZE]; + const auto rel_offset_lo = pc[3 + static_cast(case_) * REL_OFFSET_SIZE]; const auto rel_offset = static_cast((rel_offset_hi << 8) + rel_offset_lo); return pc_post + rel_offset; From f6e6b4371d5aa2362eb6679e567503fd78e25f30 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 29 Dec 2022 16:54:06 +0100 Subject: [PATCH 65/72] eof: Add more RJUMPV tests --- test/unittests/eof_validation_test.cpp | 7 +++++ test/unittests/evm_eof_test.cpp | 40 ++++++++++++++++++++++++++ test/utils/bytecode.hpp | 4 +-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index d8c03b5b5a..ffece2d415 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -465,6 +465,13 @@ TEST(eof_validation, EOF1_rjumpv_truncated) EOFValidationError::truncated_instruction); } +TEST(eof_validation, EOF1_rjumpv_0_count) +{ + auto code = eof1_bytecode(rjumpv({}, 0) + OP_STOP, 1); + + EXPECT_EQ(validate_eof(code), EOFValidationError::invalid_rjumpv_count); +} + TEST(eof_validation, EOF1_rjump_invalid_destination) { // Into header (offset = -5) diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index f733fc5123..12b9b84a02 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -370,6 +370,46 @@ TEST_P(evm, eof1_rjumpv_single_offset) "ef000101000402000100010300000000000000fe"_hex); } +TEST_P(evm, eof1_rjumpv_multiple_offsets) +{ + // Relative jumps are not implemented in Advanced. + if (is_advanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = eof1_bytecode(rjump(12) + 10 + 68 + 0 + OP_CODECOPY + ret(0, 10) + rjumpv({12, -22, 0}, 1) + 10 + 78 + 0 + OP_CODECOPY + ret(0, 10) + 20 + 68 + 0 + + OP_CODECOPY + ret(0, 20), + 3, "ef000101000402000100010300000000000000fe"); + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 10); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), + "ef000101000402000100"_hex); + + auto& rjumpv_cond = code[35]; + + rjumpv_cond = 2; + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 10); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), + "010300000000000000fe"_hex); + + rjumpv_cond = 0; + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 20); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), + "ef000101000402000100010300000000000000fe"_hex); + + rjumpv_cond = 12; // case >= count, same behaviour as for case == 2 + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + ASSERT_EQ(result.output_size, 10); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), + "010300000000000000fe"_hex); +} TEST_P(evm, relative_jumps_undefined_in_legacy) { diff --git a/test/utils/bytecode.hpp b/test/utils/bytecode.hpp index 2a6cc441bd..72812dd506 100644 --- a/test/utils/bytecode.hpp +++ b/test/utils/bytecode.hpp @@ -254,11 +254,11 @@ inline bytecode rjumpi(int16_t offset, bytecode condition) return condition + OP_RJUMPI + bytecode{big_endian(offset)}; } -inline bytecode rjumpv(const std::initializer_list offsets, bytecode condition) +inline bytecode rjumpv(const std::initializer_list offsets, bytecode condition) { bytecode ret = condition + OP_RJUMPV + static_cast(offsets.size()); for (const auto offset : offsets) - ret += bytecode{big_endian(offset)}; + ret += bytecode{big_endian(offset)}; // TODO: Make sure that big_endian works fine for signed type return ret; } From 4e0e7d4297082077b2ab46051fe3e8ba82dbdfd7 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 29 Dec 2022 16:54:52 +0100 Subject: [PATCH 66/72] eof: Fix 0 count RJUMPV test --- lib/evmone/eof.cpp | 7 ++++++- lib/evmone/eof.hpp | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 1bb9909f9a..29ba99338e 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -205,7 +205,12 @@ EOFValidationError validate_instructions(evmc_revision rev, bytes_view code) noe if (op == OP_RJUMPV) { if (i + 1 < code.size()) - i += static_cast(1 /* count */ + code[i + 1] * 2 /* tbl */); + { + const auto count = code[i + 1]; + if (count < 1) + return EOFValidationError::invalid_rjumpv_count; + i += static_cast(1 /* count */ + count * 2 /* tbl */); + } else return EOFValidationError::truncated_instruction; } diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index 919be5ab94..807b1da328 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -66,6 +66,7 @@ enum class EOFValidationError invalid_section_bodies_size, undefined_instruction, truncated_instruction, + invalid_rjumpv_count, invalid_rjump_destination, code_section_before_type_section, multiple_type_sections, From dcbc98329cd0a3a9e29c4bcf9122b2a310866583 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 29 Dec 2022 16:55:30 +0100 Subject: [PATCH 67/72] Fix linter errors --- test/unittests/evm_eof_test.cpp | 16 +++++++--------- test/utils/bytecode.hpp | 3 ++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index 12b9b84a02..d89f923883 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -377,15 +377,15 @@ TEST_P(evm, eof1_rjumpv_multiple_offsets) return; rev = EVMC_SHANGHAI; - auto code = eof1_bytecode(rjump(12) + 10 + 68 + 0 + OP_CODECOPY + ret(0, 10) + rjumpv({12, -22, 0}, 1) + 10 + 78 + 0 + OP_CODECOPY + ret(0, 10) + 20 + 68 + 0 + - OP_CODECOPY + ret(0, 20), + auto code = eof1_bytecode(rjump(12) + 10 + 68 + 0 + OP_CODECOPY + ret(0, 10) + + rjumpv({12, -22, 0}, 1) + 10 + 78 + 0 + OP_CODECOPY + ret(0, 10) + + 20 + 68 + 0 + OP_CODECOPY + ret(0, 20), 3, "ef000101000402000100010300000000000000fe"); execute(code); EXPECT_STATUS(EVMC_SUCCESS); ASSERT_EQ(result.output_size, 10); - EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "ef000101000402000100"_hex); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef000101000402000100"_hex); auto& rjumpv_cond = code[35]; @@ -393,8 +393,7 @@ TEST_P(evm, eof1_rjumpv_multiple_offsets) execute(code); EXPECT_STATUS(EVMC_SUCCESS); ASSERT_EQ(result.output_size, 10); - EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "010300000000000000fe"_hex); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), "010300000000000000fe"_hex); rjumpv_cond = 0; execute(code); @@ -403,12 +402,11 @@ TEST_P(evm, eof1_rjumpv_multiple_offsets) EXPECT_EQ(bytes_view(result.output_data, result.output_size), "ef000101000402000100010300000000000000fe"_hex); - rjumpv_cond = 12; // case >= count, same behaviour as for case == 2 + rjumpv_cond = 12; // case >= count, same behaviour as for case == 2 execute(code); EXPECT_STATUS(EVMC_SUCCESS); ASSERT_EQ(result.output_size, 10); - EXPECT_EQ(bytes_view(result.output_data, result.output_size), - "010300000000000000fe"_hex); + EXPECT_EQ(bytes_view(result.output_data, result.output_size), "010300000000000000fe"_hex); } TEST_P(evm, relative_jumps_undefined_in_legacy) diff --git a/test/utils/bytecode.hpp b/test/utils/bytecode.hpp index 72812dd506..698ee98db6 100644 --- a/test/utils/bytecode.hpp +++ b/test/utils/bytecode.hpp @@ -258,7 +258,8 @@ inline bytecode rjumpv(const std::initializer_list offsets, bytecode co { bytecode ret = condition + OP_RJUMPV + static_cast(offsets.size()); for (const auto offset : offsets) - ret += bytecode{big_endian(offset)}; // TODO: Make sure that big_endian works fine for signed type + ret += bytecode{big_endian(offset)}; // TODO: Make sure that big_endian works fine for + // signed type return ret; } From b0516287bb0875b27f2f155075a2c78b57984608 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Thu, 29 Dec 2022 18:35:55 +0100 Subject: [PATCH 68/72] eof: Add long jump test for RJUMPV --- test/unittests/evm_eof_test.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/unittests/evm_eof_test.cpp b/test/unittests/evm_eof_test.cpp index d89f923883..5ca27b8971 100644 --- a/test/unittests/evm_eof_test.cpp +++ b/test/unittests/evm_eof_test.cpp @@ -409,6 +409,33 @@ TEST_P(evm, eof1_rjumpv_multiple_offsets) EXPECT_EQ(bytes_view(result.output_data, result.output_size), "010300000000000000fe"_hex); } +TEST_P(evm, eof1_rjumpv_long_jumps) +{ + // Relative jumps are not implemented in Advanced. + if (is_advanced()) + return; + + rev = EVMC_SHANGHAI; + auto code = + rjump(0x7fff - 3 - 5) + (0x7fff - 3 - 2 - 8 - 5) * bytecode{OP_JUMPDEST} + 7 + ret_top(); + + code += rjumpv({-0x7FFF, 0x7FFF - 8 - 2 - 8}, 0) + + (0x7fff - 8 - 2 - 8) * bytecode{OP_JUMPDEST} + 5 + ret_top(); + + code = eof1_bytecode(code, 2); + auto& rjumpv_cond = code[0x7fff - 3 - 5 + 3 + 1 + 19]; + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(7); + + rjumpv_cond = 1; + + execute(code); + EXPECT_STATUS(EVMC_SUCCESS); + EXPECT_OUTPUT_INT(5); +} + TEST_P(evm, relative_jumps_undefined_in_legacy) { rev = EVMC_SHANGHAI; From 7bd9567e185a08d7cc7c710893d34bbeedc7ac19 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Mon, 2 Jan 2023 13:17:00 +0100 Subject: [PATCH 69/72] eof: Limit number of possible inputs and outputs. --- lib/evmone/eof.cpp | 12 +++++++-- lib/evmone/eof.hpp | 1 + test/unittests/eof_validation_test.cpp | 37 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 29ba99338e..bf2f352195 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -26,6 +26,7 @@ constexpr uint8_t DATA_SECTION = 0x03; constexpr uint8_t MAX_SECTION = DATA_SECTION; constexpr auto CODE_SECTION_NUMBER_LIMIT = 1024; constexpr auto MAX_STACK_HEIGHT = 0x0400; +constexpr auto OUTPUTS_INPUTS_NUMBER_LIMIT = 0x7F; using EOFSectionHeaders = std::array, MAX_SECTION + 1>; @@ -182,8 +183,15 @@ std::pair, EOFValidationError> validate_types( if (types[0].inputs_num != 0 || types[0].outputs_num != 0) return {{}, EOFValidationError::invalid_first_section_type}; - if (types[0].max_stack_height > MAX_STACK_HEIGHT) - return {{}, EOFValidationError::invalid_max_stack_height}; + for (const auto& t : types) + { + if (t.max_stack_height > MAX_STACK_HEIGHT) + return {{}, EOFValidationError::max_stack_height_above_limit}; + + if (t.outputs_num > OUTPUTS_INPUTS_NUMBER_LIMIT || + t.inputs_num > OUTPUTS_INPUTS_NUMBER_LIMIT) + return {{}, EOFValidationError::inputs_outputs_num_above_limit}; + } return {types, EOFValidationError::success}; } diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index 807b1da328..087ff77526 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -80,6 +80,7 @@ enum class EOFValidationError stack_height_mismatch, non_empty_stack_on_terminating_instruction, max_stack_height_above_limit, + inputs_outputs_num_above_limit, unreachable_instructions, stack_underflow, diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index ffece2d415..edf4b12017 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -604,3 +604,40 @@ TEST(eof_validation, deprecated_instructions) EXPECT_EQ(validate_eof(eof1_bytecode(op)), EOFValidationError::undefined_instruction); } } + +TEST(eof_valication, max_arguments_count) +{ + EXPECT_EQ(validate_eof("EF0001 010008 02000200010001 030000 00 00000000 7F7F007F B1 B1"), + EOFValidationError::success); + + EXPECT_EQ(validate_eof("EF0001 010008 02000200010001 030000 00 00000000 80800080 B1 B1"), + EOFValidationError::inputs_outputs_num_above_limit); + + { + auto code = "EF0001 010008 020002000100FF 030000 00 00000000 007F007F B1" + + 127 * bytecode{1} + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::success); + } + + { + auto code = "EF0001 010008 02000200010101 030000 00 00000000 00800080 B1" + + 128 * bytecode{1} + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::inputs_outputs_num_above_limit); + } + + { + auto code = + "EF0001 010008 02000200010080 030000 00 00000000 7F00007F B1" + 127 * OP_POP + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::success); + } + + { + auto code = + "EF0001 010008 02000200010081 030000 00 00000000 80000080 B1" + 128 * OP_POP + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::inputs_outputs_num_above_limit); + } +} From 5ca9116240b2ee0bd182d339aaa83a0573b5a5b2 Mon Sep 17 00:00:00 2001 From: rodiazet Date: Mon, 2 Jan 2023 13:58:23 +0100 Subject: [PATCH 70/72] eof: Add tests for max stack height --- lib/evmone/eof.cpp | 5 ++- test/unittests/eof_validation_test.cpp | 45 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index bf2f352195..917afb8125 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -305,6 +305,8 @@ std::pair validate_max_stack_height( bytes_view code, size_t func_index, const std::vector& funcs_in_outs) { assert(code.size() > 0); + + // Changing this type to smaller integer (uint16_t) have in mind that it can overflow. std::vector stack_heights = std::vector(code.size(), -1); std::stack worklist; @@ -411,9 +413,6 @@ std::pair validate_max_stack_height( auto msh_it = std::max_element(stack_heights.begin(), stack_heights.end()); - if (*msh_it > 1023) - return {EOFValidationError::max_stack_height_above_limit, -1}; - if (std::find(stack_heights.begin(), stack_heights.end(), -1) != stack_heights.end()) return {EOFValidationError::unreachable_instructions, -1}; diff --git a/test/unittests/eof_validation_test.cpp b/test/unittests/eof_validation_test.cpp index edf4b12017..9f452beead 100644 --- a/test/unittests/eof_validation_test.cpp +++ b/test/unittests/eof_validation_test.cpp @@ -641,3 +641,48 @@ TEST(eof_valication, max_arguments_count) EXPECT_EQ(validate_eof(code), EOFValidationError::inputs_outputs_num_above_limit); } } + +TEST(eof_valication, max_stack_heigh) +{ + { + auto code = "EF0001 010008 02000200010C01 030000 00 00000000 00000400 B1" + + 0x400 * bytecode{1} + 0x400 * OP_POP + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::success); + } + + { + auto code = "EF0001 010008 0200020C010001 030000 00 00000400 00000000" + + 0x400 * bytecode{1} + 0x400 * OP_POP + OP_RETF + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::success); + } + + { + auto code = "EF0001 010008 02000200010C04 030000 00 00000000 00000401 B1" + + 0x401 * bytecode{1} + 0x401 * OP_POP + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::max_stack_height_above_limit); + } + + { + auto code = "EF0001 010008 0200020C040001 030000 00 00000401 00000000" + + 0x401 * bytecode{1} + 0x401 * OP_POP + OP_RETF + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::max_stack_height_above_limit); + } + + { + auto code = "EF0001 010008 02000200010C04 030000 00 00000000 00000400 B1" + + 0x401 * bytecode{1} + 0x401 * OP_POP + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::invalid_max_stack_height); + } + + { + auto code = "EF0001 010008 0200020C040001 030000 00 00000400 00000000" + + 0x401 * bytecode{1} + 0x401 * OP_POP + OP_RETF + OP_RETF; + + EXPECT_EQ(validate_eof(code), EOFValidationError::invalid_max_stack_height); + } +} From 0520f2ede0fa9f1fd2ff881ecda041eac8c0f687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Jan 2023 16:54:50 +0100 Subject: [PATCH 71/72] eof: get_error_message() --- lib/evmone/eof.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++++ lib/evmone/eof.hpp | 2 ++ 2 files changed, 78 insertions(+) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 917afb8125..46d4a13e79 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -577,4 +577,80 @@ EOFValidationError validate_eof(evmc_revision rev, bytes_view container) noexcep else return EOFValidationError::eof_version_unknown; } + +std::string_view get_error_message(EOFValidationError err) noexcept +{ + switch (err) + { + case EOFValidationError::success: + return "success"; + case EOFValidationError::starts_with_format: + return "starts_with_format"; + case EOFValidationError::invalid_prefix: + return "invalid_prefix"; + case EOFValidationError::eof_version_mismatch: + return "eof_version_mismatch"; + case EOFValidationError::eof_version_unknown: + return "eof_version_unknown"; + case EOFValidationError::incomplete_section_size: + return "incomplete_section_size"; + case EOFValidationError::incomplete_section_number: + return "incomplete_section_number"; + case EOFValidationError::code_section_missing: + return "code_section_missing"; + case EOFValidationError::type_section_missing: + return "type_section_missing"; + case EOFValidationError::multiple_data_sections: + return "multiple_data_sections"; + case EOFValidationError::unknown_section_id: + return "unknown_section_id"; + case EOFValidationError::zero_section_size: + return "zero_section_size"; + case EOFValidationError::section_headers_not_terminated: + return "section_headers_not_terminated"; + case EOFValidationError::invalid_section_bodies_size: + return "invalid_section_bodies_size"; + case EOFValidationError::undefined_instruction: + return "undefined_instruction"; + case EOFValidationError::truncated_instruction: + return "truncated_instruction"; + case EOFValidationError::invalid_rjumpv_count: + return "invalid_rjumpv_count"; + case EOFValidationError::invalid_rjump_destination: + return "invalid_rjump_destination"; + case EOFValidationError::code_section_before_type_section: + return "code_section_before_type_section"; + case EOFValidationError::multiple_type_sections: + return "multiple_type_sections"; + case EOFValidationError::too_many_code_sections: + return "too_many_code_sections"; + case EOFValidationError::data_section_before_code_section: + return "data_section_before_code_section"; + case EOFValidationError::data_section_before_types_section: + return "data_section_before_types_section"; + case EOFValidationError::invalid_type_section_size: + return "invalid_type_section_size"; + case EOFValidationError::invalid_first_section_type: + return "invalid_first_section_type"; + case EOFValidationError::invalid_max_stack_height: + return "invalid_max_stack_height"; + case EOFValidationError::no_terminating_instruction: + return "no_terminating_instruction"; + case EOFValidationError::stack_height_mismatch: + return "stack_height_mismatch"; + case EOFValidationError::non_empty_stack_on_terminating_instruction: + return "non_empty_stack_on_terminating_instruction"; + case EOFValidationError::max_stack_height_above_limit: + return "max_stack_height_above_limit"; + case EOFValidationError::inputs_outputs_num_above_limit: + return "inputs_outputs_num_above_limit"; + case EOFValidationError::unreachable_instructions: + return "unreachable_instructions"; + case EOFValidationError::stack_underflow: + return "stack_underflow"; + case EOFValidationError::impossible: + return "impossible"; + } + return ""; +} } // namespace evmone diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index 087ff77526..2572937eb0 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -94,4 +94,6 @@ enum class EOFValidationError /// Validates whether given container is a valid EOF according to the rules of given revision. [[nodiscard]] EVMC_EXPORT EOFValidationError validate_eof( evmc_revision rev, bytes_view container) noexcept; + +[[nodiscard]] EVMC_EXPORT std::string_view get_error_message(EOFValidationError err) noexcept; } // namespace evmone From 62bddb353c480c7c1eabf5b8b15526c3a2144e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Jan 2023 16:58:36 +0100 Subject: [PATCH 72/72] Add eofparse testing tool --- test/CMakeLists.txt | 3 ++- test/eofparse/CMakeLists.txt | 7 +++++ test/eofparse/eofparse.cpp | 51 ++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 test/eofparse/CMakeLists.txt create mode 100644 test/eofparse/eofparse.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 041a6f7521..eea4e5013c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,13 +15,14 @@ find_package(benchmark CONFIG REQUIRED) add_subdirectory(utils) add_subdirectory(bench) +add_subdirectory(eofparse) add_subdirectory(integration) add_subdirectory(internal_benchmarks) add_subdirectory(state) add_subdirectory(statetest) add_subdirectory(unittests) -set(targets evmone-bench evmone-bench-internal evmone-state evmone-statetest evmone-unittests testutils) +set(targets evmone-bench evmone-bench-internal evmone-eofparse evmone-state evmone-statetest evmone-unittests testutils) if(EVMONE_FUZZING) add_subdirectory(fuzzer) diff --git a/test/eofparse/CMakeLists.txt b/test/eofparse/CMakeLists.txt new file mode 100644 index 0000000000..e05cfee577 --- /dev/null +++ b/test/eofparse/CMakeLists.txt @@ -0,0 +1,7 @@ +# evmone: Fast Ethereum Virtual Machine implementation +# Copyright 2023 The evmone Authors. +# SPDX-License-Identifier: Apache-2.0 + +add_executable(evmone-eofparse eofparse.cpp) +target_link_libraries(evmone-eofparse PRIVATE evmone) +target_include_directories(evmone-eofparse PRIVATE ${evmone_private_include_dir}) diff --git a/test/eofparse/eofparse.cpp b/test/eofparse/eofparse.cpp new file mode 100644 index 0000000000..3bf09c95e7 --- /dev/null +++ b/test/eofparse/eofparse.cpp @@ -0,0 +1,51 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2023 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include + +int main() +{ + try + { + for (std::string line; std::getline(std::cin, line);) + { + const auto eof = evmc::from_hex(line).value(); + + const auto err = evmone::validate_eof(EVMC_SHANGHAI, eof); + if (err != evmone::EOFValidationError::success) + { + std::cout << "err: " << evmone::get_error_message(err); + } + else + { + const auto header = evmone::read_valid_eof1_header(eof); + + std::cout << "OK "; + for (size_t i = 0; i < header.code_sizes.size(); ++i) + { + if (i != 0) + std::cout << ','; + std::cout << evmc::hex( + evmc::bytes_view{&eof[header.code_offsets.at(i)], header.code_sizes[i]}); + } + } + std::cout << std::endl; + } + } + catch (const std::bad_optional_access&) + { + std::cerr << "invalid hex\n"; + return 1; + } + catch (const std::exception& ex) + { + std::cerr << ex.what() << '\n'; + return 2; + } + + return 0; +}