diff --git a/test/state/host.cpp b/test/state/host.cpp index 9f5c0d6732..3df784a81a 100644 --- a/test/state/host.cpp +++ b/test/state/host.cpp @@ -140,28 +140,29 @@ address compute_new_account_address(const address& sender, uint64_t sender_nonce std::optional Host::prepare_message(evmc_message msg) { - auto& sender_acc = m_state.get(msg.sender); - const auto sender_nonce = sender_acc.nonce; - - // Bump sender nonce. if (msg.depth == 0 || msg.kind == EVMC_CREATE || msg.kind == EVMC_CREATE2) { - if (sender_nonce == Account::NonceMax) - return {}; // Light early exception, cannot happen for depth == 0. - ++sender_acc.nonce; - } + auto& sender_acc = m_state.get(msg.sender); + const auto sender_nonce = sender_acc.nonce; - if (msg.kind == EVMC_CREATE || msg.kind == EVMC_CREATE2) - { - // Compute and fill create address. - assert(msg.recipient == address{}); - assert(msg.code_address == address{}); - 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); + // EIP-2681 (already checked for depth 0 during transaction validation). + if (sender_nonce == Account::NonceMax) + return {}; // Light early exception. + + ++sender_acc.nonce; // Bump sender nonce. + + if (msg.kind == EVMC_CREATE || msg.kind == EVMC_CREATE2) + { + // Compute and set the address of the account being created. + assert(msg.recipient == address{}); + assert(msg.code_address == address{}); + 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); + } } return msg; @@ -252,9 +253,10 @@ evmc::Result Host::execute_message(const evmc_message& msg) noexcept auto* const dst_acc = (msg.kind == EVMC_CALL) ? &m_state.touch(msg.recipient) : m_state.find(msg.code_address); - if (msg.kind == EVMC_CALL) + if (msg.kind == EVMC_CALL && !evmc::is_zero(msg.value)) { - // Transfer value. + // Transfer value: sender → recipient. + // The sender's balance is already checked therefore the sender account must exist. const auto value = intx::be::load(msg.value); assert(m_state.get(msg.sender).balance >= value); m_state.get(msg.sender).balance -= value; diff --git a/test/state/state.cpp b/test/state/state.cpp index 5fab2758d6..de7654133a 100644 --- a/test/state/state.cpp +++ b/test/state/state.cpp @@ -107,7 +107,7 @@ std::variant validate_transaction(const Account& sende if (!sender_acc.code.empty()) return make_error_code(SENDER_NOT_EOA); // Origin must not be a contract (EIP-3607). - if (sender_acc.nonce == Account::NonceMax) + if (sender_acc.nonce == Account::NonceMax) // Nonce value limit (EIP-2681). return make_error_code(NONCE_HAS_MAX_VALUE); if (sender_acc.nonce < tx.nonce) diff --git a/test/unittests/state_transition_create_test.cpp b/test/unittests/state_transition_create_test.cpp index 6011197223..cfa43b546c 100644 --- a/test/unittests/state_transition_create_test.cpp +++ b/test/unittests/state_transition_create_test.cpp @@ -32,3 +32,15 @@ TEST_F(state_transition, create_tx) expect.post[create_address].code = bytes{0xFE}; } + +TEST_F(state_transition, create2_max_nonce) +{ + // The address to be created by CREATE2 of the "To" sender and empty initcode. + static constexpr auto create_address = 0x36fd63ce1cb5ee2993f19d1fae4e84d52f6f1595_address; + + tx.to = To; + pre.insert(*tx.to, {.nonce = ~uint64_t{0}, .code = create2()}); + + expect.post[*tx.to].nonce = pre.get(*tx.to).nonce; // Nonce is unchanged. + expect.post[create_address].exists = false; +}