From ca4c31388ce7b635431e4ccb563843c2367e1159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Feb 2023 12:02:34 +0100 Subject: [PATCH 1/2] state: Expose and test compute_new_account_address() --- test/state/host.cpp | 4 +- test/state/host.hpp | 6 ++ test/unittests/CMakeLists.txt | 1 + .../state_new_account_address_test.cpp | 80 +++++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 test/unittests/state_new_account_address_test.cpp diff --git a/test/state/host.cpp b/test/state/host.cpp index 8c4ae4c79d..0fe1369b41 100644 --- a/test/state/host.cpp +++ b/test/state/host.cpp @@ -110,7 +110,7 @@ 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 evmc_message& msg, uint64_t sender_nonce) noexcept { hash256 addr_base_hash; if (msg.kind == EVMC_CREATE) @@ -156,7 +156,7 @@ 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_nonce); // 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..5c93ff8b3e 100644 --- a/test/state/host.hpp +++ b/test/state/host.hpp @@ -15,6 +15,12 @@ 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 `ADDR()` in Yellow Paper, 7. Contract Creation, (86). +address compute_new_account_address(const evmc_message& msg, uint64_t sender_nonce) 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..dd2ec1e58b --- /dev/null +++ b/test/unittests/state_new_account_address_test.cpp @@ -0,0 +1,80 @@ +// 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) +{ + evmc_message msg{}; + msg.kind = EVMC_CREATE; + + for (const auto& ic : init_codes) // Init-code doesn't affect CREATE. + { + msg.input_data = ic.data(); + msg.input_size = ic.size(); + + msg.sender = senders[0]; + EXPECT_EQ(addr(msg, nonces[0]), 0xbd770416a3345f91e4b34576cb804a576fa48eb1_address); + EXPECT_EQ(addr(msg, nonces[3]), 0x1262d73ea59d3a661bf8751d16cf1a5377149e75_address); + + msg.sender = senders[1]; + EXPECT_EQ(addr(msg, nonces[0]), 0x522b3294e6d06aa25ad0f1b8891242e335d3b459_address); + EXPECT_EQ(addr(msg, nonces[1]), 0x535b3d7a252fa034ed71f0c53ec0c6f784cb64e1_address); + EXPECT_EQ(addr(msg, nonces[2]), 0x09c1ef8f55c61b94e8b92a55d0891d408a991e18_address); + EXPECT_EQ(addr(msg, nonces[3]), 0x001567239734aeadea21023c2a7c0d9bb9ae4af9_address); + + msg.sender = senders[2]; + EXPECT_EQ(addr(msg, nonces[0]), 0x3cb1045aee4a06f522ea2b69e4f3d21ed3c135d1_address); + EXPECT_EQ(addr(msg, nonces[3]), 0xe1aa03e4a7b6991d69aff8ece53ceafdf347082e_address); + + msg.sender = 0xb20a608c624Ca5003905aA834De7156C68b2E1d0_address; + const auto beacon_deposit_address = addr(msg, 0); + EXPECT_EQ(beacon_deposit_address, 0x00000000219ab540356cbb839cbe05303d7705fa_address); + } +} + +TEST(state_new_account_address, create2) +{ + evmc_message msg{}; + msg.kind = EVMC_CREATE2; + + for (const auto n : nonces) // Nonce doesn't affect CREATE2. + { + msg.sender = senders[0]; + msg.input_data = init_codes[0].data(); + msg.input_size = init_codes[0].size(); + msg.create2_salt = salts[0]; + EXPECT_EQ(addr(msg, n), 0xe33c0c7f7df4809055c3eba6c09cfe4baf1bd9e0_address); + + msg.sender = senders[2]; + msg.input_data = init_codes[1].data(); + msg.input_size = init_codes[1].size(); + msg.create2_salt = salts[0]; + EXPECT_EQ(addr(msg, n), 0x3517dea701ed18fc4a99dc111c5946e1f1541dad_address); + + msg.sender = senders[1]; + msg.input_data = init_codes[0].data(); + msg.input_size = init_codes[0].size(); + msg.create2_salt = salts[1]; + EXPECT_EQ(addr(msg, n), 0x7be1c1cb3b8298f21c56add66defce03e2d32604_address); + + msg.sender = senders[2]; + msg.input_data = init_codes[1].data(); + msg.input_size = init_codes[1].size(); + msg.create2_salt = salts[1]; + EXPECT_EQ(addr(msg, n), 0x8f459e65c8f00a9c0c0493de7b0c61c3c27f7384_address); + } +} From bd35f8f1130d927461f7f44d3a3767eb4e234407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Feb 2023 12:21:52 +0100 Subject: [PATCH 2/2] state: Refactor `compute_new_account_address()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor `compute_new_account_address()` to match Yellow Paper 𝐀𝐃𝐃𝐑. This makes it a separate utility independent of `evmc_message`. --- test/state/host.cpp | 25 +++---- test/state/host.hpp | 11 ++- .../state_new_account_address_test.cpp | 69 +++++++------------ 3 files changed, 46 insertions(+), 59 deletions(-) diff --git a/test/state/host.cpp b/test/state/host.cpp index 0fe1369b41..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); } -address compute_new_account_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_account_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 5c93ff8b3e..9106ca4c37 100644 --- a/test/state/host.hpp +++ b/test/state/host.hpp @@ -18,8 +18,15 @@ 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 `ADDR()` in Yellow Paper, 7. Contract Creation, (86). -address compute_new_account_address(const evmc_message& msg, uint64_t sender_nonce) noexcept; +/// 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 { diff --git a/test/unittests/state_new_account_address_test.cpp b/test/unittests/state_new_account_address_test.cpp index dd2ec1e58b..c406072aab 100644 --- a/test/unittests/state_new_account_address_test.cpp +++ b/test/unittests/state_new_account_address_test.cpp @@ -18,63 +18,42 @@ inline constexpr bytes32 salts[] = { TEST(state_new_account_address, create) { - evmc_message msg{}; - msg.kind = EVMC_CREATE; - for (const auto& ic : init_codes) // Init-code doesn't affect CREATE. { - msg.input_data = ic.data(); - msg.input_size = ic.size(); - - msg.sender = senders[0]; - EXPECT_EQ(addr(msg, nonces[0]), 0xbd770416a3345f91e4b34576cb804a576fa48eb1_address); - EXPECT_EQ(addr(msg, nonces[3]), 0x1262d73ea59d3a661bf8751d16cf1a5377149e75_address); - - msg.sender = senders[1]; - EXPECT_EQ(addr(msg, nonces[0]), 0x522b3294e6d06aa25ad0f1b8891242e335d3b459_address); - EXPECT_EQ(addr(msg, nonces[1]), 0x535b3d7a252fa034ed71f0c53ec0c6f784cb64e1_address); - EXPECT_EQ(addr(msg, nonces[2]), 0x09c1ef8f55c61b94e8b92a55d0891d408a991e18_address); - EXPECT_EQ(addr(msg, nonces[3]), 0x001567239734aeadea21023c2a7c0d9bb9ae4af9_address); - - msg.sender = senders[2]; - EXPECT_EQ(addr(msg, nonces[0]), 0x3cb1045aee4a06f522ea2b69e4f3d21ed3c135d1_address); - EXPECT_EQ(addr(msg, nonces[3]), 0xe1aa03e4a7b6991d69aff8ece53ceafdf347082e_address); - - msg.sender = 0xb20a608c624Ca5003905aA834De7156C68b2E1d0_address; - const auto beacon_deposit_address = addr(msg, 0); + 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) { - evmc_message msg{}; - msg.kind = EVMC_CREATE2; - for (const auto n : nonces) // Nonce doesn't affect CREATE2. { - msg.sender = senders[0]; - msg.input_data = init_codes[0].data(); - msg.input_size = init_codes[0].size(); - msg.create2_salt = salts[0]; - EXPECT_EQ(addr(msg, n), 0xe33c0c7f7df4809055c3eba6c09cfe4baf1bd9e0_address); + EXPECT_EQ(addr(senders[0], n, salts[0], init_codes[0]), + 0xe33c0c7f7df4809055c3eba6c09cfe4baf1bd9e0_address); - msg.sender = senders[2]; - msg.input_data = init_codes[1].data(); - msg.input_size = init_codes[1].size(); - msg.create2_salt = salts[0]; - EXPECT_EQ(addr(msg, n), 0x3517dea701ed18fc4a99dc111c5946e1f1541dad_address); + EXPECT_EQ(addr(senders[2], n, salts[0], init_codes[1]), + 0x3517dea701ed18fc4a99dc111c5946e1f1541dad_address); - msg.sender = senders[1]; - msg.input_data = init_codes[0].data(); - msg.input_size = init_codes[0].size(); - msg.create2_salt = salts[1]; - EXPECT_EQ(addr(msg, n), 0x7be1c1cb3b8298f21c56add66defce03e2d32604_address); + EXPECT_EQ(addr(senders[1], n, salts[1], init_codes[0]), + 0x7be1c1cb3b8298f21c56add66defce03e2d32604_address); - msg.sender = senders[2]; - msg.input_data = init_codes[1].data(); - msg.input_size = init_codes[1].size(); - msg.create2_salt = salts[1]; - EXPECT_EQ(addr(msg, n), 0x8f459e65c8f00a9c0c0493de7b0c61c3c27f7384_address); + EXPECT_EQ(addr(senders[2], n, salts[1], init_codes[1]), + 0x8f459e65c8f00a9c0c0493de7b0c61c3c27f7384_address); } }