Skip to content
Open
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
6 changes: 4 additions & 2 deletions src/ethereum/forks/amsterdam/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ def process_system_transaction(
authorizations=(),
index_in_block=None,
tx_hash=None,
state_changes=system_tx_state_changes,
)

system_tx_message = Message(
Expand All @@ -667,7 +668,8 @@ def process_system_transaction(
accessed_storage_keys=set(),
disable_precompiles=False,
parent_evm=None,
transaction_state_changes=system_tx_state_changes,
is_create=False,
state_changes=create_child_frame(system_tx_state_changes),
)

system_tx_output = process_message_call(system_tx_message)
Expand Down Expand Up @@ -991,13 +993,13 @@ def process_transaction(
authorizations=authorizations,
index_in_block=index,
tx_hash=get_transaction_hash(encode_transaction(tx)),
state_changes=tx_state_changes,
)

message = prepare_message(
block_env,
tx_env,
tx,
tx_state_changes,
)

tx_output = process_message_call(message)
Expand Down
8 changes: 5 additions & 3 deletions src/ethereum/forks/amsterdam/utils/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from ..fork_types import Address
from ..state import get_account
from ..state_tracker import StateChanges
from ..state_tracker import create_child_frame
from ..transactions import Transaction
from ..vm import BlockEnvironment, Message, TransactionEnvironment
from ..vm.precompiled_contracts.mapping import PRE_COMPILED_CONTRACTS
Expand All @@ -28,7 +28,6 @@ def prepare_message(
block_env: BlockEnvironment,
tx_env: TransactionEnvironment,
tx: Transaction,
transaction_state_changes: StateChanges,
) -> Message:
"""
Execute a transaction against the provided environment.
Expand Down Expand Up @@ -63,11 +62,13 @@ def prepare_message(
msg_data = Bytes(b"")
code = tx.data
code_address = None
is_create = True
elif isinstance(tx.to, Address):
current_target = tx.to
msg_data = tx.data
code = get_account(block_env.state, tx.to).code
code_address = tx.to
is_create = False
else:
raise AssertionError("Target must be address or empty bytes")

Expand All @@ -91,5 +92,6 @@ def prepare_message(
accessed_storage_keys=set(tx_env.access_list_storage_keys),
disable_precompiles=False,
parent_evm=None,
transaction_state_changes=transaction_state_changes,
is_create=is_create,
state_changes=create_child_frame(tx_env.state_changes),
)
4 changes: 3 additions & 1 deletion src/ethereum/forks/amsterdam/vm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class TransactionEnvironment:
authorizations: Tuple[Authorization, ...]
index_in_block: Optional[Uint]
tx_hash: Optional[Hash32]
state_changes: StateChanges


@dataclass
Expand All @@ -142,7 +143,8 @@ class Message:
accessed_storage_keys: Set[Tuple[Address, Bytes32]]
disable_precompiles: bool
parent_evm: Optional["Evm"]
transaction_state_changes: StateChanges
is_create: bool
state_changes: StateChanges


@dataclass
Expand Down
14 changes: 5 additions & 9 deletions src/ethereum/forks/amsterdam/vm/eoa_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ def set_delegation(message: Message) -> U256:
"""
state = message.block_env.state
refund_counter = U256(0)
tx_state_changes = message.tx_env.state_changes
for auth in message.tx_env.authorizations:
if auth.chain_id not in (message.block_env.chain_id, U256(0)):
continue
Expand All @@ -236,7 +237,7 @@ def set_delegation(message: Message) -> U256:
authority_account = get_account(state, authority)
authority_code = authority_account.code

track_address(message.block_env.block_state_changes, authority)
track_address(tx_state_changes, authority)

if authority_code and not is_valid_delegation(authority_code):
continue
Expand All @@ -253,22 +254,17 @@ def set_delegation(message: Message) -> U256:
else:
code_to_set = EOA_DELEGATION_MARKER + auth.address

state_changes = (
message.transaction_state_changes
or message.block_env.block_state_changes
)

# Capture pre-code before any changes (first-write-wins)
capture_pre_code(state_changes, authority, authority_code)
capture_pre_code(tx_state_changes, authority, authority_code)

# Set delegation code
# Uses authority_code (current) for tracking to handle multiple auths
# Net-zero filtering happens in commit_transaction_frame
set_authority_code(
state, authority, code_to_set, state_changes, authority_code
state, authority, code_to_set, tx_state_changes, authority_code
)

increment_nonce(state, authority, state_changes)
increment_nonce(state, authority, tx_state_changes)

if message.code_address is None:
raise InvalidBlock("Invalid type 4 transaction: no target")
Expand Down
12 changes: 9 additions & 3 deletions src/ethereum/forks/amsterdam/vm/instructions/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@
move_ether,
set_account_balance,
)
from ...state_tracker import capture_pre_balance, track_address
from ...state_tracker import (
capture_pre_balance,
create_child_frame,
track_address,
)
from ...utils.address import (
compute_contract_address,
compute_create2_contract_address,
Expand Down Expand Up @@ -144,7 +148,8 @@ def generic_create(
accessed_storage_keys=evm.accessed_storage_keys.copy(),
disable_precompiles=False,
parent_evm=evm,
transaction_state_changes=evm.message.transaction_state_changes,
is_create=True,
state_changes=create_child_frame(evm.state_changes),
)

child_evm = process_create_message(child_message)
Expand Down Expand Up @@ -341,7 +346,8 @@ def generic_call(
accessed_storage_keys=evm.accessed_storage_keys.copy(),
disable_precompiles=disable_precompiles,
parent_evm=evm,
transaction_state_changes=evm.message.transaction_state_changes,
is_create=False,
state_changes=create_child_frame(evm.state_changes),
)

child_evm = process_message(child_message)
Expand Down
66 changes: 26 additions & 40 deletions src/ethereum/forks/amsterdam/vm/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ def get_parent_frame(message: Message) -> StateChanges:
Frame selection logic:
- Nested calls: Parent EVM's frame
- Top-level calls: Transaction frame
- System transactions: Block frame

Parameters
----------
Expand All @@ -93,12 +92,9 @@ def get_parent_frame(message: Message) -> StateChanges:
The parent frame to use for creating child frames.

"""
if message.parent_evm is not None:
return message.parent_evm.state_changes
elif message.transaction_state_changes is not None:
return message.transaction_state_changes
else:
return message.block_env.block_state_changes
assert message.parent_evm is not None

return message.parent_evm.state_changes


def get_message_state_frame(message: Message) -> StateChanges:
Expand All @@ -119,13 +115,7 @@ def get_message_state_frame(message: Message) -> StateChanges:

"""
parent_frame = get_parent_frame(message)
if (
message.parent_evm is not None
or message.transaction_state_changes is not None
):
return create_child_frame(parent_frame)
else:
return parent_frame
return create_child_frame(parent_frame)


@dataclass
Expand Down Expand Up @@ -173,9 +163,7 @@ def process_message_call(message: Message) -> MessageCallOutput:
is_collision = account_has_code_or_nonce(
block_env.state, message.current_target
) or account_has_storage(block_env.state, message.current_target)
track_address(
message.transaction_state_changes, message.current_target
)
track_address(message.tx_env.state_changes, message.current_target)
if is_collision:
return MessageCallOutput(
Uint(0),
Expand All @@ -199,19 +187,19 @@ def process_message_call(message: Message) -> MessageCallOutput:
message.code_address = delegated_address

# EIP-7928: Track delegation target when loaded as call target
track_address(
message.block_env.block_state_changes, delegated_address
)
track_address(message.tx_env.state_changes, delegated_address)

evm = process_message(message)

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

tx_end = TransactionEnd(
int(message.gas) - int(evm.gas_left), evm.output, evm.error
Expand Down Expand Up @@ -263,10 +251,7 @@ def process_create_message(message: Message) -> Evm:
# added to SELFDESTRUCT by EIP-6780.
mark_account_created(state, message.current_target)

parent_frame = get_parent_frame(message)
create_frame = create_child_frame(parent_frame)

increment_nonce(state, message.current_target, create_frame)
increment_nonce(state, message.current_target, message.state_changes)
evm = process_message(message)
if not evm.error:
contract_code = evm.output
Expand All @@ -280,19 +265,22 @@ def process_create_message(message: Message) -> Evm:
raise OutOfGasError
except ExceptionalHalt as error:
rollback_transaction(state, transient_storage)
merge_on_failure(create_frame)
merge_on_failure(message.state_changes)
evm.gas_left = Uint(0)
evm.output = b""
evm.error = error
else:
set_code(
state, message.current_target, contract_code, create_frame
state,
message.current_target,
contract_code,
message.state_changes,
)
commit_transaction(state, transient_storage)
merge_on_success(create_frame)
merge_on_success(message.state_changes)
else:
rollback_transaction(state, transient_storage)
merge_on_failure(create_frame)
merge_on_failure(message.state_changes)
return evm


Expand All @@ -318,42 +306,40 @@ def process_message(message: Message) -> Evm:

begin_transaction(state, transient_storage)

parent_frame = get_parent_frame(message)
state_changes = get_message_state_frame(message)

track_address(state_changes, message.current_target)
track_address(message.state_changes, message.current_target)

if message.should_transfer_value and message.value != 0:
move_ether(
state,
message.caller,
message.current_target,
message.value,
state_changes,
message.state_changes,
)

evm = execute_code(message, state_changes)
evm = execute_code(message)
if evm.error:
rollback_transaction(state, transient_storage)
if state_changes != parent_frame:
if not message.is_create:
# For create messages further checks need to be done
# before merging the state changes. These are done
# in the `process_create_message` function
merge_on_failure(evm.state_changes)
else:
commit_transaction(state, transient_storage)
if state_changes != parent_frame:
if not message.is_create:
merge_on_success(evm.state_changes)
return evm


def execute_code(message: Message, state_changes: StateChanges) -> Evm:
def execute_code(message: Message) -> Evm:
"""
Executes bytecode present in the `message`.

Parameters
----------
message :
Transaction specific items.
state_changes :
The state changes frame to use for tracking.

Returns
-------
Expand Down Expand Up @@ -381,7 +367,7 @@ def execute_code(message: Message, state_changes: StateChanges) -> Evm:
error=None,
accessed_addresses=message.accessed_addresses,
accessed_storage_keys=message.accessed_storage_keys,
state_changes=state_changes,
state_changes=message.state_changes,
)
try:
if evm.message.code_address in PRE_COMPILED_CONTRACTS:
Expand Down
Loading
Loading