Skip to content
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
12 changes: 0 additions & 12 deletions src/ethereum/cancun/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
TransientStorage,
account_exists_and_is_empty,
destroy_account,
destroy_touched_empty_accounts,
get_account,
increment_nonce,
modify_state,
Expand Down Expand Up @@ -538,15 +537,6 @@ def process_system_transaction(

system_tx_output = process_message_call(system_tx_message)

# TODO: Empty accounts in post-merge forks are impossible
# see Ethereum Improvement Proposal 7523.
# This line is only included to support invalid tests in the test suite
# and will have to be removed in the future.
# See https://github.com/ethereum/execution-specs/issues/955
destroy_touched_empty_accounts(
block_env.state, system_tx_output.touched_accounts
)

return system_tx_output


Expand Down Expand Up @@ -722,8 +712,6 @@ def process_transaction(
for address in tx_output.accounts_to_delete:
destroy_account(block_env.state, address)

destroy_touched_empty_accounts(block_env.state, tx_output.touched_accounts)

block_output.block_gas_used += tx_gas_used
block_output.blob_gas_used += tx_blob_gas_used

Expand Down
35 changes: 2 additions & 33 deletions src/ethereum/cancun/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,8 @@ def modify_state(
Modify an `Account` in the `State`.
"""
set_account(state, address, modify(get_account(state, address), f))
if account_exists_and_is_empty(state, address):
destroy_account(state, address)


def move_ether(
Expand Down Expand Up @@ -556,22 +558,6 @@ def set_balance(account: Account) -> None:
modify_state(state, address, set_balance)


def touch_account(state: State, address: Address) -> None:
"""
Initializes an account to state.

Parameters
----------
state:
The current state.

address:
The address of the account that need to initialised.
"""
if not account_exists(state, address):
set_account(state, address, EMPTY_ACCOUNT)


def increment_nonce(state: State, address: Address) -> None:
"""
Increments the nonce of an account.
Expand Down Expand Up @@ -702,20 +688,3 @@ def set_transient_storage(
trie_set(trie, key, value)
if trie._data == {}:
del transient_storage._tries[address]


def destroy_touched_empty_accounts(
state: State, touched_accounts: Set[Address]
) -> None:
"""
Destroy all touched accounts that are empty.
Parameters
----------
state: `State`
The current state.
touched_accounts: `Set[Address]`
All the accounts that have been touched in the current transaction.
"""
for address in touched_accounts:
if account_exists_and_is_empty(state, address):
destroy_account(state, address)
23 changes: 1 addition & 22 deletions src/ethereum/cancun/vm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@

from ..blocks import Log, Receipt, Withdrawal
from ..fork_types import Address, VersionedHash
from ..state import State, TransientStorage, account_exists_and_is_empty
from ..state import State, TransientStorage
from ..transactions import LegacyTransaction
from ..trie import Trie
from .precompiled_contracts import RIPEMD160_ADDRESS

__all__ = ("Environment", "Evm", "Message")

Expand Down Expand Up @@ -145,7 +144,6 @@ class Evm:
message: Message
output: Bytes
accounts_to_delete: Set[Address]
touched_accounts: Set[Address]
return_data: Bytes
error: Optional[EthereumException]
accessed_addresses: Set[Address]
Expand All @@ -167,11 +165,6 @@ def incorporate_child_on_success(evm: Evm, child_evm: Evm) -> None:
evm.logs += child_evm.logs
evm.refund_counter += child_evm.refund_counter
evm.accounts_to_delete.update(child_evm.accounts_to_delete)
evm.touched_accounts.update(child_evm.touched_accounts)
if account_exists_and_is_empty(
evm.message.block_env.state, child_evm.message.current_target
):
evm.touched_accounts.add(child_evm.message.current_target)
evm.accessed_addresses.update(child_evm.accessed_addresses)
evm.accessed_storage_keys.update(child_evm.accessed_storage_keys)

Expand All @@ -187,18 +180,4 @@ def incorporate_child_on_error(evm: Evm, child_evm: Evm) -> None:
child_evm :
The child evm to incorporate.
"""
# In block 2675119, the empty account at 0x3 (the RIPEMD160 precompile) was
# cleared despite running out of gas. This is an obscure edge case that can
# only happen to a precompile.
# According to the general rules governing clearing of empty accounts, the
# touch should have been reverted. Due to client bugs, this event went
# unnoticed and 0x3 has been exempted from the rule that touches are
# reverted in order to preserve this historical behaviour.
if RIPEMD160_ADDRESS in child_evm.touched_accounts:
evm.touched_accounts.add(RIPEMD160_ADDRESS)
if child_evm.message.current_target == RIPEMD160_ADDRESS:
if account_exists_and_is_empty(
evm.message.block_env.state, child_evm.message.current_target
):
evm.touched_accounts.add(RIPEMD160_ADDRESS)
evm.gas_left += child_evm.gas_left
5 changes: 0 additions & 5 deletions src/ethereum/cancun/vm/instructions/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

from ...fork_types import Address
from ...state import (
account_exists_and_is_empty,
account_has_code_or_nonce,
account_has_storage,
get_account,
Expand Down Expand Up @@ -546,10 +545,6 @@ def selfdestruct(evm: Evm) -> None:
set_account_balance(evm.message.block_env.state, originator, U256(0))
evm.accounts_to_delete.add(originator)

# mark beneficiary as touched
if account_exists_and_is_empty(evm.message.block_env.state, beneficiary):
evm.touched_accounts.add(beneficiary)

# HALT the execution
evm.running = False

Expand Down
18 changes: 2 additions & 16 deletions src/ethereum/cancun/vm/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
from ..blocks import Log
from ..fork_types import Address
from ..state import (
account_exists_and_is_empty,
account_has_code_or_nonce,
account_has_storage,
begin_transaction,
Expand All @@ -44,7 +43,6 @@
move_ether,
rollback_transaction,
set_code,
touch_account,
)
from ..vm import Message
from ..vm.gas import GAS_CODE_DEPOSIT, charge_gas
Expand Down Expand Up @@ -77,15 +75,13 @@ class MessageCallOutput:
2. `refund_counter`: gas to refund after execution.
3. `logs`: list of `Log` generated during execution.
4. `accounts_to_delete`: Contracts which have self-destructed.
5. `touched_accounts`: Accounts that have been touched.
6. `error`: The error from the execution if any.
5. `error`: The error from the execution if any.
"""

gas_left: Uint
refund_counter: U256
logs: Tuple[Log, ...]
accounts_to_delete: Set[Address]
touched_accounts: Set[Address]
error: Optional[EthereumException]


Expand All @@ -112,25 +108,19 @@ def process_message_call(message: Message) -> MessageCallOutput:
) or account_has_storage(block_env.state, message.current_target)
if is_collision:
return MessageCallOutput(
Uint(0), U256(0), tuple(), set(), set(), AddressCollision()
Uint(0), U256(0), tuple(), set(), AddressCollision()
)
else:
evm = process_create_message(message)
else:
evm = process_message(message)
if account_exists_and_is_empty(
block_env.state, Address(message.target)
):
evm.touched_accounts.add(Address(message.target))

if evm.error:
logs: Tuple[Log, ...] = ()
accounts_to_delete = set()
touched_accounts = set()
else:
logs = evm.logs
accounts_to_delete = evm.accounts_to_delete
touched_accounts = evm.touched_accounts
refund_counter += U256(evm.refund_counter)

tx_end = TransactionEnd(
Expand All @@ -143,7 +133,6 @@ def process_message_call(message: Message) -> MessageCallOutput:
refund_counter=refund_counter,
logs=logs,
accounts_to_delete=accounts_to_delete,
touched_accounts=touched_accounts,
error=evm.error,
)

Expand Down Expand Up @@ -232,8 +221,6 @@ def process_message(message: Message) -> Evm:
# take snapshot of state before processing the message
begin_transaction(state, transient_storage)

touch_account(state, message.current_target)

if message.should_transfer_value and message.value != 0:
move_ether(
state, message.caller, message.current_target, message.value
Expand Down Expand Up @@ -281,7 +268,6 @@ def execute_code(message: Message) -> Evm:
message=message,
output=b"",
accounts_to_delete=set(),
touched_accounts=set(),
return_data=b"",
error=None,
accessed_addresses=message.accessed_addresses,
Expand Down
6 changes: 6 additions & 0 deletions src/ethereum/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ class InvalidBlock(EthereumException):
"""


class StateWithEmptyAccount(EthereumException):
"""
Thrown when the state has empty account.
"""


class InvalidTransaction(EthereumException):
"""
Thrown when a transaction being processed is found to be invalid.
Expand Down
3 changes: 0 additions & 3 deletions src/ethereum/paris/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
State,
account_exists_and_is_empty,
destroy_account,
destroy_touched_empty_accounts,
get_account,
increment_nonce,
set_account_balance,
Expand Down Expand Up @@ -564,8 +563,6 @@ def process_transaction(
for address in tx_output.accounts_to_delete:
destroy_account(block_env.state, address)

destroy_touched_empty_accounts(block_env.state, tx_output.touched_accounts)

block_output.block_gas_used += tx_gas_used

receipt = make_receipt(
Expand Down
37 changes: 3 additions & 34 deletions src/ethereum/paris/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
`EMPTY_ACCOUNT`.
"""
from dataclasses import dataclass, field
from typing import Callable, Dict, Iterable, List, Optional, Set, Tuple
from typing import Callable, Dict, List, Optional, Set, Tuple

from ethereum_types.bytes import Bytes, Bytes32
from ethereum_types.frozen import modify
Expand Down Expand Up @@ -477,6 +477,8 @@ def modify_state(
Modify an `Account` in the `State`.
"""
set_account(state, address, modify(get_account(state, address), f))
if account_exists_and_is_empty(state, address):
destroy_account(state, address)


def move_ether(
Expand Down Expand Up @@ -523,22 +525,6 @@ def set_balance(account: Account) -> None:
modify_state(state, address, set_balance)


def touch_account(state: State, address: Address) -> None:
"""
Initializes an account to state.

Parameters
----------
state:
The current state.

address:
The address of the account that need to initialised.
"""
if not account_exists(state, address):
set_account(state, address, EMPTY_ACCOUNT)


def increment_nonce(state: State, address: Address) -> None:
"""
Increments the nonce of an account.
Expand Down Expand Up @@ -611,20 +597,3 @@ def get_storage_original(state: State, address: Address, key: Bytes32) -> U256:
assert isinstance(original_value, U256)

return original_value


def destroy_touched_empty_accounts(
state: State, touched_accounts: Iterable[Address]
) -> None:
"""
Destroy all touched accounts that are empty.
Parameters
----------
state: `State`
The current state.
touched_accounts: `Iterable[Address]`
All the accounts that have been touched in the current transaction.
"""
for address in touched_accounts:
if account_exists_and_is_empty(state, address):
destroy_account(state, address)
23 changes: 1 addition & 22 deletions src/ethereum/paris/vm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@

from ..blocks import Log, Receipt
from ..fork_types import Address
from ..state import State, account_exists_and_is_empty
from ..state import State
from ..transactions import LegacyTransaction
from ..trie import Trie
from .precompiled_contracts import RIPEMD160_ADDRESS

__all__ = ("Environment", "Evm", "Message")

Expand Down Expand Up @@ -133,7 +132,6 @@ class Evm:
message: Message
output: Bytes
accounts_to_delete: Set[Address]
touched_accounts: Set[Address]
return_data: Bytes
error: Optional[EthereumException]
accessed_addresses: Set[Address]
Expand All @@ -155,11 +153,6 @@ def incorporate_child_on_success(evm: Evm, child_evm: Evm) -> None:
evm.logs += child_evm.logs
evm.refund_counter += child_evm.refund_counter
evm.accounts_to_delete.update(child_evm.accounts_to_delete)
evm.touched_accounts.update(child_evm.touched_accounts)
if account_exists_and_is_empty(
evm.message.block_env.state, child_evm.message.current_target
):
evm.touched_accounts.add(child_evm.message.current_target)
evm.accessed_addresses.update(child_evm.accessed_addresses)
evm.accessed_storage_keys.update(child_evm.accessed_storage_keys)

Expand All @@ -175,18 +168,4 @@ def incorporate_child_on_error(evm: Evm, child_evm: Evm) -> None:
child_evm :
The child evm to incorporate.
"""
# In block 2675119, the empty account at 0x3 (the RIPEMD160 precompile) was
# cleared despite running out of gas. This is an obscure edge case that can
# only happen to a precompile.
# According to the general rules governing clearing of empty accounts, the
# touch should have been reverted. Due to client bugs, this event went
# unnoticed and 0x3 has been exempted from the rule that touches are
# reverted in order to preserve this historical behaviour.
if RIPEMD160_ADDRESS in child_evm.touched_accounts:
evm.touched_accounts.add(RIPEMD160_ADDRESS)
if child_evm.message.current_target == RIPEMD160_ADDRESS:
if account_exists_and_is_empty(
evm.message.block_env.state, child_evm.message.current_target
):
evm.touched_accounts.add(RIPEMD160_ADDRESS)
evm.gas_left += child_evm.gas_left
Loading
Loading