Skip to content

Commit 0bcf0c5

Browse files
authored
host: Don't assume the sender account exists (#731)
This change is basically refactoring with the goal not to access the call sender's account unnecessary.
1 parent 9e9681d commit 0bcf0c5

File tree

3 files changed

+36
-22
lines changed

3 files changed

+36
-22
lines changed

test/state/host.cpp

+23-21
Original file line numberDiff line numberDiff line change
@@ -140,28 +140,29 @@ address compute_new_account_address(const address& sender, uint64_t sender_nonce
140140

141141
std::optional<evmc_message> Host::prepare_message(evmc_message msg)
142142
{
143-
auto& sender_acc = m_state.get(msg.sender);
144-
const auto sender_nonce = sender_acc.nonce;
145-
146-
// Bump sender nonce.
147143
if (msg.depth == 0 || msg.kind == EVMC_CREATE || msg.kind == EVMC_CREATE2)
148144
{
149-
if (sender_nonce == Account::NonceMax)
150-
return {}; // Light early exception, cannot happen for depth == 0.
151-
++sender_acc.nonce;
152-
}
145+
auto& sender_acc = m_state.get(msg.sender);
146+
const auto sender_nonce = sender_acc.nonce;
153147

154-
if (msg.kind == EVMC_CREATE || msg.kind == EVMC_CREATE2)
155-
{
156-
// Compute and fill create address.
157-
assert(msg.recipient == address{});
158-
assert(msg.code_address == address{});
159-
msg.recipient = compute_new_account_address(msg.sender, sender_nonce,
160-
(msg.kind == EVMC_CREATE2) ? std::optional{msg.create2_salt} : std::nullopt,
161-
{msg.input_data, msg.input_size});
162-
163-
// By EIP-2929, the access to new created address is never reverted.
164-
access_account(msg.recipient);
148+
// EIP-2681 (already checked for depth 0 during transaction validation).
149+
if (sender_nonce == Account::NonceMax)
150+
return {}; // Light early exception.
151+
152+
++sender_acc.nonce; // Bump sender nonce.
153+
154+
if (msg.kind == EVMC_CREATE || msg.kind == EVMC_CREATE2)
155+
{
156+
// Compute and set the address of the account being created.
157+
assert(msg.recipient == address{});
158+
assert(msg.code_address == address{});
159+
msg.recipient = compute_new_account_address(msg.sender, sender_nonce,
160+
(msg.kind == EVMC_CREATE2) ? std::optional{msg.create2_salt} : std::nullopt,
161+
{msg.input_data, msg.input_size});
162+
163+
// By EIP-2929, the access to new created address is never reverted.
164+
access_account(msg.recipient);
165+
}
165166
}
166167

167168
return msg;
@@ -252,9 +253,10 @@ evmc::Result Host::execute_message(const evmc_message& msg) noexcept
252253
auto* const dst_acc =
253254
(msg.kind == EVMC_CALL) ? &m_state.touch(msg.recipient) : m_state.find(msg.code_address);
254255

255-
if (msg.kind == EVMC_CALL)
256+
if (msg.kind == EVMC_CALL && !evmc::is_zero(msg.value))
256257
{
257-
// Transfer value.
258+
// Transfer value: sender → recipient.
259+
// The sender's balance is already checked therefore the sender account must exist.
258260
const auto value = intx::be::load<intx::uint256>(msg.value);
259261
assert(m_state.get(msg.sender).balance >= value);
260262
m_state.get(msg.sender).balance -= value;

test/state/state.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ std::variant<int64_t, std::error_code> validate_transaction(const Account& sende
107107
if (!sender_acc.code.empty())
108108
return make_error_code(SENDER_NOT_EOA); // Origin must not be a contract (EIP-3607).
109109

110-
if (sender_acc.nonce == Account::NonceMax)
110+
if (sender_acc.nonce == Account::NonceMax) // Nonce value limit (EIP-2681).
111111
return make_error_code(NONCE_HAS_MAX_VALUE);
112112

113113
if (sender_acc.nonce < tx.nonce)

test/unittests/state_transition_create_test.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,15 @@ TEST_F(state_transition, create_tx)
3232

3333
expect.post[create_address].code = bytes{0xFE};
3434
}
35+
36+
TEST_F(state_transition, create2_max_nonce)
37+
{
38+
// The address to be created by CREATE2 of the "To" sender and empty initcode.
39+
static constexpr auto create_address = 0x36fd63ce1cb5ee2993f19d1fae4e84d52f6f1595_address;
40+
41+
tx.to = To;
42+
pre.insert(*tx.to, {.nonce = ~uint64_t{0}, .code = create2()});
43+
44+
expect.post[*tx.to].nonce = pre.get(*tx.to).nonce; // Nonce is unchanged.
45+
expect.post[create_address].exists = false;
46+
}

0 commit comments

Comments
 (0)