From 9aebfe3a078766a7c54bc204c2a5d6e90d5d0ed9 Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:36:20 +0100 Subject: [PATCH] Add test for new EXTCODE* behavior --- test/state/host.cpp | 10 +- test/unittests/CMakeLists.txt | 1 + .../state_transition_extcode_test.cpp | 94 +++++++++++++++++++ 3 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 test/unittests/state_transition_extcode_test.cpp diff --git a/test/state/host.cpp b/test/state/host.cpp index cb7588cad6..82c36657f6 100644 --- a/test/state/host.cpp +++ b/test/state/host.cpp @@ -82,30 +82,30 @@ namespace /// For EXTCODE* instructions if the target is an EOF account, then only return EF00. /// While we only do this if the caller is legacy, it is not a problem doing this /// unconditionally, because EOF contracts dot no have EXTCODE* instructions. -bytes_view extcode(bytes_view code) noexcept +bytes_view extcode(bytes_view code, evmc_revision rev) noexcept { - return is_eof_container(code) ? code.substr(0, 2) : code; + return (rev >= EVMC_PRAGUE && is_eof_container(code)) ? code.substr(0, 2) : code; } } // namespace size_t Host::get_code_size(const address& addr) const noexcept { const auto* const acc = m_state.find(addr); - return (acc != nullptr) ? extcode(acc->code).size() : 0; + return (acc != nullptr) ? extcode(acc->code, m_rev).size() : 0; } bytes32 Host::get_code_hash(const address& addr) const noexcept { // TODO: Cache code hash. It will be needed also to compute the MPT hash. const auto* const acc = m_state.find(addr); - return (acc != nullptr && !acc->is_empty()) ? keccak256(extcode(acc->code)) : bytes32{}; + return (acc != nullptr && !acc->is_empty()) ? keccak256(extcode(acc->code, m_rev)) : bytes32{}; } size_t Host::copy_code(const address& addr, size_t code_offset, uint8_t* buffer_data, size_t buffer_size) const noexcept { const auto* const acc = m_state.find(addr); - const auto code = (acc != nullptr) ? extcode(acc->code) : bytes_view{}; + const auto code = (acc != nullptr) ? extcode(acc->code, m_rev) : bytes_view{}; const auto code_slice = code.substr(std::min(code_offset, code.size())); const auto num_bytes = std::min(buffer_size, code_slice.size()); std::copy_n(code_slice.begin(), num_bytes, buffer_data); diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index 5dc1d5899b..05ccab6993 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -56,6 +56,7 @@ target_sources( state_transition_block_test.cpp state_transition_create_test.cpp state_transition_eof_test.cpp + state_transition_extcode_test.cpp state_transition_selfdestruct_test.cpp state_transition_trace_test.cpp state_transition_transient_storage_test.cpp diff --git a/test/unittests/state_transition_extcode_test.cpp b/test/unittests/state_transition_extcode_test.cpp new file mode 100644 index 0000000000..feadf6fc66 --- /dev/null +++ b/test/unittests/state_transition_extcode_test.cpp @@ -0,0 +1,94 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2023 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include "../utils/bytecode.hpp" +#include "state_transition.hpp" + +using namespace evmc::literals; +using namespace evmone::test; + +constexpr auto target = 0xfffffffffffffffffffffffffffffffffffffffe_address; +constexpr auto ones = 0x1111111111111111111111111111111111111111111111111111111111111111_bytes32; + +TEST_F(state_transition, legacy_extcodesize_eof_cancun) +{ + pre.insert(target, {.code = eof_bytecode("FE")}); + + rev = EVMC_CANCUN; + tx.to = To; + pre.insert(*tx.to, { + .code = bytecode(push(target) + sstore(1, OP_EXTCODESIZE)), + }); + expect.post[*tx.to].storage[0x01_bytes32] = 0x14_bytes32; + expect.post[target].exists = true; +} + +TEST_F(state_transition, legacy_extcodesize_eof) +{ + pre.insert(target, {.code = eof_bytecode("FE")}); + + rev = EVMC_PRAGUE; + tx.to = To; + pre.insert(*tx.to, { + .code = bytecode(push(target) + sstore(1, OP_EXTCODESIZE)), + }); + expect.post[*tx.to].storage[0x01_bytes32] = 0x02_bytes32; + expect.post[target].exists = true; +} + +TEST_F(state_transition, legacy_extcodehash_eof_cancun) +{ + pre.insert(target, {.code = eof_bytecode("FE")}); + + rev = EVMC_CANCUN; + tx.to = To; + pre.insert(*tx.to, { + .code = bytecode(push(target) + sstore(1, OP_EXTCODEHASH)), + }); + expect.post[*tx.to].storage[0x01_bytes32] = keccak256(bytecode(eof_bytecode("FE"))); + expect.post[target].exists = true; +} + +TEST_F(state_transition, legacy_extcodehash_eof) +{ + pre.insert(target, {.code = eof_bytecode("FE")}); + + rev = EVMC_PRAGUE; + tx.to = To; + pre.insert(*tx.to, { + .code = bytecode(push(target) + sstore(1, OP_EXTCODEHASH)), + }); + expect.post[*tx.to].storage[0x01_bytes32] = keccak256(bytecode("EF00")); + expect.post[target].exists = true; +} + +TEST_F(state_transition, legacy_extcodecopy_eof_cancun) +{ + pre.insert(target, {.code = eof_bytecode("FE")}); + + rev = EVMC_CANCUN; + tx.to = To; + pre.insert(*tx.to, { + .code = bytecode(mstore(0, ones) + push(20) + push0() + push0() + + push(target) + OP_EXTCODECOPY + sstore(1, mload(0))), + }); + expect.post[*tx.to].storage[0x01_bytes32] = + 0xef000101000402000100010400000000800000fe111111111111111111111111_bytes32; + expect.post[target].exists = true; +} + +TEST_F(state_transition, legacy_extcodecopy_eof) +{ + pre.insert(target, {.code = eof_bytecode("FE")}); + + rev = EVMC_PRAGUE; + tx.to = To; + pre.insert(*tx.to, { + .code = bytecode(mstore(0, ones) + push(20) + push0() + push0() + + push(target) + OP_EXTCODECOPY + sstore(1, mload(0))), + }); + expect.post[*tx.to].storage[0x01_bytes32] = + 0xef00000000000000000000000000000000000000111111111111111111111111_bytes32; + expect.post[target].exists = true; +}