From 78af74a6cccf9447452ceb9aad9f9bd0ac17cfb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 18 Oct 2024 11:43:33 +0200 Subject: [PATCH] state: Implement `CREATE` address without RLP lib Remove Host's dependency on RLP library by re-implementing `compute_create_address()`. Closes https://github.com/ethereum/evmone/issues/783. --- test/state/host.cpp | 34 ++++++++++++++++++++++++++++------ test/state/host.hpp | 8 ++++---- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/test/state/host.cpp b/test/state/host.cpp index a227d09142..6fe92fd262 100644 --- a/test/state/host.cpp +++ b/test/state/host.cpp @@ -4,7 +4,6 @@ #include "host.hpp" #include "precompiles.hpp" -#include "rlp.hpp" #include #include @@ -177,13 +176,36 @@ bool Host::selfdestruct(const address& addr, const address& beneficiary) noexcep return false; } -address compute_create_address(const address& sender, uint64_t sender_nonce) noexcept +address compute_create_address(const address& sender, uint64_t nonce) noexcept { - // TODO: Compute CREATE address without using RLP library. - const auto rlp_list = rlp::encode_tuple(sender, sender_nonce); - const auto base_hash = keccak256(rlp_list); + static constexpr auto RLP_STR_BASE = 0x80; + static constexpr auto RLP_LIST_BASE = 0xc0; + static constexpr auto ADDRESS_SIZE = sizeof(sender); + static constexpr std::ptrdiff_t NONCE_SIZE = sizeof(nonce); + + uint8_t buffer[ADDRESS_SIZE + NONCE_SIZE + 3]; // 3 for RLP prefix bytes. + auto p = &buffer[1]; // Skip RLP list prefix for now. + *p++ = RLP_STR_BASE + ADDRESS_SIZE; // Set RLP string prefix for address. + p = std::copy_n(sender.bytes, ADDRESS_SIZE, p); + + if (nonce < RLP_STR_BASE) // Short integer encoding with handling 0 as empty string (0x80). + { + *p++ = nonce != 0 ? static_cast(nonce) : RLP_STR_BASE; + } + else // Prefixed integer encoding. + { + const int num_nonzero_bytes = (std::bit_width(nonce) + 7) / 8; + *p++ = static_cast(RLP_STR_BASE + num_nonzero_bytes); + intx::be::unsafe::store(p, nonce); + p = std::shift_left(p, p + NONCE_SIZE, NONCE_SIZE - num_nonzero_bytes); // Skip zero bytes. + } + + const auto total_size = static_cast(p - buffer); + buffer[0] = static_cast(RLP_LIST_BASE + (total_size - 1)); // Set the RLP list prefix. + + const auto base_hash = keccak256({buffer, total_size}); address addr; - std::copy_n(&base_hash.bytes[sizeof(base_hash) - sizeof(addr)], sizeof(addr), addr.bytes); + std::copy_n(&base_hash.bytes[sizeof(base_hash) - ADDRESS_SIZE], ADDRESS_SIZE, addr.bytes); return addr; } diff --git a/test/state/host.hpp b/test/state/host.hpp index e1cfb51efc..90293f5dfd 100644 --- a/test/state/host.hpp +++ b/test/state/host.hpp @@ -17,10 +17,10 @@ using evmc::uint256be; /// or a create transaction. /// This is defined by 𝐀𝐃𝐃𝐑 in Yellow Paper, 7. Contract Creation, (88-90), the case for ΞΆ = βˆ…. /// -/// @param sender The address of the message sender. YP: 𝑠. -/// @param sender_nonce The sender's nonce before the increase. YP: 𝑛. -/// @return The address computed with the CREATE scheme. -[[nodiscard]] address compute_create_address(const address& sender, uint64_t sender_nonce) noexcept; +/// @param sender The address of the message sender. YP: 𝑠. +/// @param nonce The sender's nonce before the increase. YP: 𝑛. +/// @return The address computed with the CREATE scheme. +[[nodiscard]] address compute_create_address(const address& sender, uint64_t nonce) noexcept; /// Computes the address of to-be-created contract with the CREATE2 / EOFCREATE scheme. ///