Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

host: Don't assume the sender account exists #731

Merged
merged 1 commit into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 23 additions & 21 deletions test/state/host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,28 +140,29 @@ address compute_new_account_address(const address& sender, uint64_t sender_nonce

std::optional<evmc_message> 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;
Expand Down Expand Up @@ -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<intx::uint256>(msg.value);
assert(m_state.get(msg.sender).balance >= value);
m_state.get(msg.sender).balance -= value;
Expand Down
2 changes: 1 addition & 1 deletion test/state/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ std::variant<int64_t, std::error_code> 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)
Expand Down
12 changes: 12 additions & 0 deletions test/unittests/state_transition_create_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}