From 5fad30bde638c60ceccdbc6e84969e1fd7b507ff Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Thu, 23 Jan 2025 17:23:51 +0100 Subject: [PATCH 1/2] EIP-7702: EXTCODE* work on full delegation designation --- test/state/host.cpp | 13 +------------ test/unittests/state_transition_eip7702_test.cpp | 5 ++--- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/test/state/host.cpp b/test/state/host.cpp index 68296234a5..fe45c94d5c 100644 --- a/test/state/host.cpp +++ b/test/state/host.cpp @@ -9,14 +9,6 @@ namespace evmone::state { -namespace -{ -/// The value returned by EXTCODEHASH of an address with EIP-7702 delegation designator. -/// See https://eips.ethereum.org/EIPS/eip-7702#delegation-designation -constexpr auto EIP7702_CODE_HASH_SENTINEL = - 0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329_bytes32; -} // namespace - bool Host::account_exists(const address& addr) const noexcept { const auto* const acc = m_state.find(addr); @@ -89,7 +81,7 @@ namespace /// unconditionally, because EOF contracts dot no have EXTCODE* instructions. bytes_view extcode(bytes_view code) noexcept { - return (is_eof_container(code) || is_code_delegated(code)) ? code.substr(0, 2) : code; + return is_eof_container(code) ? code.substr(0, 2) : code; } /// Check if an existing account is the "create collision" @@ -132,9 +124,6 @@ bytes32 Host::get_code_hash(const address& addr) const noexcept if (is_eof_container(code)) return EOF_CODE_HASH_SENTINEL; - if (is_code_delegated(code)) - return EIP7702_CODE_HASH_SENTINEL; - return acc->code_hash; } diff --git a/test/unittests/state_transition_eip7702_test.cpp b/test/unittests/state_transition_eip7702_test.cpp index c98b81d770..473566851d 100644 --- a/test/unittests/state_transition_eip7702_test.cpp +++ b/test/unittests/state_transition_eip7702_test.cpp @@ -72,7 +72,7 @@ TEST_F(state_transition, eip7702_extcodesize) expect.post[callee].exists = true; expect.post[delegate].exists = true; - expect.post[To].storage[0x01_bytes32] = 0x02_bytes32; + expect.post[To].storage[0x01_bytes32] = 0x17_bytes32; } TEST_F(state_transition, eip7702_extcodehash_delegation_to_empty) @@ -87,8 +87,7 @@ TEST_F(state_transition, eip7702_extcodehash_delegation_to_empty) expect.post[callee].exists = true; expect.post[delegate].exists = false; - expect.post[To].storage[0x00_bytes32] = - 0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329_bytes32; + expect.post[To].storage[0x00_bytes32] = keccak256(bytes{0xef, 0x01, 0x00} + hex(delegate)); expect.post[To].storage[0x01_bytes32] = 0x01_bytes32; } From a92a4ed405f8385e10c359794063c41493c619f6 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Mon, 13 Jan 2025 12:03:40 +0100 Subject: [PATCH 2/2] Refactor EIP-7702: delegation resolution in EVM instead of host function --- evmc | 2 +- lib/evmone/CMakeLists.txt | 1 + lib/evmone/delegation.hpp | 42 +++++++++++++++++++++++++++++++ lib/evmone/instructions_calls.cpp | 9 ++++--- test/state/host.cpp | 13 ---------- test/state/host.hpp | 2 -- test/state/state.cpp | 5 ++-- test/state/state.hpp | 11 -------- 8 files changed, 52 insertions(+), 33 deletions(-) create mode 100644 lib/evmone/delegation.hpp diff --git a/evmc b/evmc index 3845070938..37b008414c 160000 --- a/evmc +++ b/evmc @@ -1 +1 @@ -Subproject commit 384507093822118e3a60756a56b7b6eb2e99cbda +Subproject commit 37b008414c260e941a784306991ac03e4b67a7de diff --git a/lib/evmone/CMakeLists.txt b/lib/evmone/CMakeLists.txt index 777c0800f2..75daf16d0c 100644 --- a/lib/evmone/CMakeLists.txt +++ b/lib/evmone/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(evmone baseline_instruction_table.cpp baseline_instruction_table.hpp constants.hpp + delegation.hpp eof.cpp eof.hpp instructions.hpp diff --git a/lib/evmone/delegation.hpp b/lib/evmone/delegation.hpp new file mode 100644 index 0000000000..613831b7c8 --- /dev/null +++ b/lib/evmone/delegation.hpp @@ -0,0 +1,42 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2025 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include +#include + +namespace evmone +{ +using evmc::bytes_view; + +/// Prefix of code for delegated accounts +/// defined by [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) +constexpr uint8_t DELEGATION_MAGIC_BYTES[] = {0xef, 0x01, 0x00}; +constexpr bytes_view DELEGATION_MAGIC{DELEGATION_MAGIC_BYTES, std::size(DELEGATION_MAGIC_BYTES)}; + +/// Check if code contains EIP-7702 delegation designator +inline constexpr bool is_code_delegated(bytes_view code) noexcept +{ + return code.starts_with(DELEGATION_MAGIC); +} + +/// Get EIP-7702 delegate address from the code of addr, if it is delegated. +inline std::optional get_delegate_address( + const evmc::address& addr, const evmc::HostInterface& host) noexcept +{ + uint8_t prefix[std::size(DELEGATION_MAGIC)] = {}; + host.copy_code(addr, 0, prefix, std::size(prefix)); + + if (!is_code_delegated(bytes_view{prefix, std::size(prefix)})) + return {}; + + evmc::address delegate_address; + assert(host.get_code_size(addr) == + std::size(DELEGATION_MAGIC) + std::size(delegate_address.bytes)); + host.copy_code( + addr, std::size(prefix), delegate_address.bytes, std::size(delegate_address.bytes)); + return delegate_address; +} +} // namespace evmone diff --git a/lib/evmone/instructions_calls.cpp b/lib/evmone/instructions_calls.cpp index 4951690a2c..d83e21c1f8 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 "delegation.hpp" #include "eof.hpp" #include "instructions.hpp" @@ -28,19 +29,19 @@ inline std::variant get_target_address( if (state.rev < EVMC_PRAGUE) return addr; - const auto delegate_addr = state.host.get_delegate_address(addr); - if (delegate_addr == evmc::address{}) + const auto delegate_addr = get_delegate_address(addr, state.host); + if (!delegate_addr) return addr; const auto delegate_account_access_cost = - (state.host.access_account(delegate_addr) == EVMC_ACCESS_COLD ? + (state.host.access_account(*delegate_addr) == EVMC_ACCESS_COLD ? instr::cold_account_access_cost : instr::warm_storage_read_cost); if ((gas_left -= delegate_account_access_cost) < 0) return Result{EVMC_OUT_OF_GAS, gas_left}; - return delegate_addr; + return *delegate_addr; } } // namespace diff --git a/test/state/host.cpp b/test/state/host.cpp index fe45c94d5c..f0d4550d66 100644 --- a/test/state/host.cpp +++ b/test/state/host.cpp @@ -552,17 +552,4 @@ void Host::set_transient_storage( m_state.journal_transient_storage_change(addr, key, slot); slot = value; } - -address Host::get_delegate_address(const address& addr) const noexcept -{ - const auto raw_code = m_state.get_code(addr); - - if (!is_code_delegated(raw_code)) - return {}; - - address delegate; - assert(raw_code.size() == std::size(DELEGATION_MAGIC) + sizeof(delegate)); - std::copy_n(&raw_code[std::size(DELEGATION_MAGIC)], sizeof(delegate), delegate.bytes); - return delegate; -} } // namespace evmone::state diff --git a/test/state/host.hpp b/test/state/host.hpp index 6f299a31f5..9b911d67bb 100644 --- a/test/state/host.hpp +++ b/test/state/host.hpp @@ -92,8 +92,6 @@ class Host : public evmc::Host public: evmc_access_status access_account(const address& addr) noexcept override; - address get_delegate_address(const address& addr) const noexcept override; - private: evmc_access_status access_storage(const address& addr, const bytes32& key) noexcept override; diff --git a/test/state/state.cpp b/test/state/state.cpp index a00dcc8a53..e071f968d4 100644 --- a/test/state/state.cpp +++ b/test/state/state.cpp @@ -7,6 +7,7 @@ #include "host.hpp" #include "state_view.hpp" #include +#include #include #include @@ -604,9 +605,9 @@ TransactionReceipt transition(const StateView& state_view, const BlockInfo& bloc auto message = build_message(tx, tx_props.execution_gas_limit, rev); if (tx.to.has_value()) { - if (const auto delegate = host.get_delegate_address(*tx.to)) + if (const auto delegate = get_delegate_address(*tx.to, host)) { - message.code_address = delegate; + message.code_address = *delegate; message.flags |= EVMC_DELEGATED; host.access_account(message.code_address); } diff --git a/test/state/state.hpp b/test/state/state.hpp index 272e430a1f..6d916a1b60 100644 --- a/test/state/state.hpp +++ b/test/state/state.hpp @@ -150,15 +150,4 @@ TransactionReceipt transition(const StateView& state, const BlockInfo& block, [[nodiscard]] std::variant validate_transaction( const StateView& state_view, const BlockInfo& block, const Transaction& tx, evmc_revision rev, int64_t block_gas_left, int64_t blob_gas_left) noexcept; - -/// Prefix of code for delegated accounts -/// defined by [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) -constexpr uint8_t DELEGATION_MAGIC_BYTES[] = {0xef, 0x01, 0x00}; -constexpr bytes_view DELEGATION_MAGIC{DELEGATION_MAGIC_BYTES, std::size(DELEGATION_MAGIC_BYTES)}; - -/// Check if code contains EIP-7702 delegation designator -constexpr bool is_code_delegated(bytes_view code) noexcept -{ - return code.starts_with(DELEGATION_MAGIC); -} } // namespace evmone::state