diff --git a/test/state/host.cpp b/test/state/host.cpp index 8c4ae4c79d..6b18320ba6 100644 --- a/test/state/host.cpp +++ b/test/state/host.cpp @@ -110,27 +110,26 @@ bool Host::selfdestruct(const address& addr, const address& beneficiary) noexcep return !std::exchange(acc.destructed, true); } -static address compute_new_address(const evmc_message& msg, uint64_t sender_nonce) noexcept +address compute_new_account_address(const address& sender, uint64_t sender_nonce, + const std::optional& salt, bytes_view init_code) noexcept { hash256 addr_base_hash; - if (msg.kind == EVMC_CREATE) + if (!salt.has_value()) // CREATE { // TODO: Compute CREATE address without using RLP library. - const auto rlp_list = rlp::encode_tuple(address{msg.sender}, sender_nonce); + const auto rlp_list = rlp::encode_tuple(sender, sender_nonce); addr_base_hash = keccak256(rlp_list); } - else + else // CREATE2 { - assert(msg.kind == EVMC_CREATE2); - const auto init_code_hash = keccak256({msg.input_data, msg.input_size}); - uint8_t buffer[1 + sizeof(msg.sender) + sizeof(msg.create2_salt) + sizeof(init_code_hash)]; + const auto init_code_hash = keccak256(init_code); + uint8_t buffer[1 + sizeof(sender) + sizeof(*salt) + sizeof(init_code_hash)]; static_assert(std::size(buffer) == 85); buffer[0] = 0xff; - std::copy_n(msg.sender.bytes, sizeof(msg.sender), &buffer[1]); - std::copy_n( - msg.create2_salt.bytes, sizeof(msg.create2_salt), &buffer[1 + sizeof(msg.sender)]); + std::copy_n(sender.bytes, sizeof(sender), &buffer[1]); + std::copy_n(salt->bytes, sizeof(salt->bytes), &buffer[1 + sizeof(sender)]); std::copy_n(init_code_hash.bytes, sizeof(init_code_hash), - &buffer[1 + sizeof(msg.sender) + sizeof(msg.create2_salt)]); + &buffer[1 + sizeof(sender) + sizeof(salt->bytes)]); addr_base_hash = keccak256({buffer, std::size(buffer)}); } evmc_address new_addr{}; @@ -156,7 +155,9 @@ std::optional Host::prepare_message(evmc_message msg) // Compute and fill create address. assert(msg.recipient == address{}); assert(msg.code_address == address{}); - msg.recipient = compute_new_address(msg, sender_nonce); + msg.recipient = compute_new_account_address(msg.sender, sender_nonce, + (msg.kind == EVMC_CREATE2) ? std::optional{msg.create2_salt} : std::nullopt, + {msg.input_data, msg.input_size}); // By EIP-2929, the access to new created address is never reverted. access_account(msg.recipient); diff --git a/test/state/host.hpp b/test/state/host.hpp index 021b05af8d..9106ca4c37 100644 --- a/test/state/host.hpp +++ b/test/state/host.hpp @@ -15,6 +15,19 @@ using evmc::uint256be; inline constexpr size_t max_code_size = 0x6000; inline constexpr size_t max_initcode_size = 2 * max_code_size; +/// Computes the address of to-be-created contract. +/// +/// Computes the new account address for the contract creation context +/// as defined by 𝐀𝐃𝐃𝐑 in Yellow Paper, 7. Contract Creation, (86). +/// +/// @param sender The address of the message sender. YP: 𝑠. +/// @param sender_nonce The sender's nonce before the increase. YP: 𝑛. +/// @param salt The salt for CREATE2. If null, CREATE address is computed. YP: ΞΆ. +/// @param init_code The contract creation init code. Value only affects CREATE2. YP: 𝐒. +/// @return The computed address for CREATE or CREATE2 scheme. +address compute_new_account_address(const address& sender, uint64_t sender_nonce, + const std::optional& salt, bytes_view init_code) noexcept; + class Host : public evmc::Host { evmc_revision m_rev; diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index 6cf4718dc9..47d779660b 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(evmone-unittests state_bloom_filter_test.cpp state_mpt_hash_test.cpp state_mpt_test.cpp + state_new_account_address_test.cpp state_rlp_test.cpp statetest_loader_test.cpp statetest_loader_tx_test.cpp diff --git a/test/unittests/state_new_account_address_test.cpp b/test/unittests/state_new_account_address_test.cpp new file mode 100644 index 0000000000..c406072aab --- /dev/null +++ b/test/unittests/state_new_account_address_test.cpp @@ -0,0 +1,59 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2023 The evmone Authors. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +using namespace evmc; +using namespace evmc::literals; +inline constexpr auto addr = evmone::state::compute_new_account_address; + +inline constexpr uint64_t nonces[] = {0, 1, 0x80, 0xffffffffffffffff}; +inline constexpr address senders[] = { + 0x00_address, 0x01_address, 0x8000000000000000000000000000000000000000_address}; +inline const bytes init_codes[] = {bytes{}, bytes{0xFE}}; +inline constexpr bytes32 salts[] = { + 0x00_bytes32, 0xe75fb554e433e03763a1560646ee22dcb74e5274b34c5ad644e7c0f619a7e1d0_bytes32}; + +TEST(state_new_account_address, create) +{ + for (const auto& ic : init_codes) // Init-code doesn't affect CREATE. + { + auto s = senders[0]; + EXPECT_EQ(addr(s, nonces[0], {}, ic), 0xbd770416a3345f91e4b34576cb804a576fa48eb1_address); + EXPECT_EQ(addr(s, nonces[3], {}, ic), 0x1262d73ea59d3a661bf8751d16cf1a5377149e75_address); + + s = senders[1]; + EXPECT_EQ(addr(s, nonces[0], {}, ic), 0x522b3294e6d06aa25ad0f1b8891242e335d3b459_address); + EXPECT_EQ(addr(s, nonces[1], {}, ic), 0x535b3d7a252fa034ed71f0c53ec0c6f784cb64e1_address); + EXPECT_EQ(addr(s, nonces[2], {}, ic), 0x09c1ef8f55c61b94e8b92a55d0891d408a991e18_address); + EXPECT_EQ(addr(s, nonces[3], {}, ic), 0x001567239734aeadea21023c2a7c0d9bb9ae4af9_address); + + s = senders[2]; + EXPECT_EQ(addr(s, nonces[0], {}, ic), 0x3cb1045aee4a06f522ea2b69e4f3d21ed3c135d1_address); + EXPECT_EQ(addr(s, nonces[3], {}, ic), 0xe1aa03e4a7b6991d69aff8ece53ceafdf347082e_address); + + const auto beacon_deposit_address = + addr(0xb20a608c624Ca5003905aA834De7156C68b2E1d0_address, 0, {}, ic); + EXPECT_EQ(beacon_deposit_address, 0x00000000219ab540356cbb839cbe05303d7705fa_address); + } +} + +TEST(state_new_account_address, create2) +{ + for (const auto n : nonces) // Nonce doesn't affect CREATE2. + { + EXPECT_EQ(addr(senders[0], n, salts[0], init_codes[0]), + 0xe33c0c7f7df4809055c3eba6c09cfe4baf1bd9e0_address); + + EXPECT_EQ(addr(senders[2], n, salts[0], init_codes[1]), + 0x3517dea701ed18fc4a99dc111c5946e1f1541dad_address); + + EXPECT_EQ(addr(senders[1], n, salts[1], init_codes[0]), + 0x7be1c1cb3b8298f21c56add66defce03e2d32604_address); + + EXPECT_EQ(addr(senders[2], n, salts[1], init_codes[1]), + 0x8f459e65c8f00a9c0c0493de7b0c61c3c27f7384_address); + } +}