Skip to content

EOAs that delegate to a precompile #1191

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

Merged
merged 4 commits into from
Apr 19, 2025
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
1 change: 1 addition & 0 deletions src/ethereum/prague/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ def process_system_transaction(
is_static=False,
accessed_addresses=set(),
accessed_storage_keys=set(),
disable_precompiles=False,
parent_evm=None,
)

Expand Down
4 changes: 4 additions & 0 deletions src/ethereum/prague/utils/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ def prepare_message(
accessed_addresses.update(PRE_COMPILED_CONTRACTS.keys())
accessed_addresses.update(tx_env.access_list_addresses)

disable_precompiles = False

if isinstance(tx.to, Bytes0):
current_target = compute_contract_address(
tx_env.origin,
Expand All @@ -66,6 +68,7 @@ def prepare_message(

delegated_address = get_delegated_code_address(code)
if delegated_address is not None:
disable_precompiles = True
accessed_addresses.add(delegated_address)
code = get_account(block_env.state, delegated_address).code

Expand All @@ -91,5 +94,6 @@ def prepare_message(
is_static=False,
accessed_addresses=accessed_addresses,
accessed_storage_keys=set(tx_env.access_list_storage_keys),
disable_precompiles=disable_precompiles,
parent_evm=None,
)
1 change: 1 addition & 0 deletions src/ethereum/prague/vm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class Message:
is_static: bool
accessed_addresses: Set[Address]
accessed_storage_keys: Set[Tuple[Address, Bytes32]]
disable_precompiles: bool
parent_evm: Optional["Evm"]


Expand Down
1 change: 1 addition & 0 deletions src/ethereum/prague/vm/eoa_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ def set_delegation(message: Message) -> U256:
message.code = get_account(state, message.code_address).code

if is_valid_delegation(message.code):
message.disable_precompiles = True
message.code_address = Address(
message.code[EOA_DELEGATION_MARKER_LENGTH:]
)
Expand Down
26 changes: 11 additions & 15 deletions src/ethereum/prague/vm/instructions/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def generic_create(
is_static=False,
accessed_addresses=evm.accessed_addresses.copy(),
accessed_storage_keys=evm.accessed_storage_keys.copy(),
disable_precompiles=False,
parent_evm=evm,
)
child_evm = process_create_message(child_message)
Expand Down Expand Up @@ -290,7 +291,7 @@ def generic_call(
memory_output_start_position: U256,
memory_output_size: U256,
code: bytes,
is_delegated_code: bool,
disable_precompiles: bool,
) -> None:
"""
Perform the core logic of the `CALL*` family of opcodes.
Expand All @@ -307,12 +308,6 @@ def generic_call(
call_data = memory_read_bytes(
evm.memory, memory_input_start_position, memory_input_size
)
code = get_account(evm.message.block_env.state, code_address).code

if is_delegated_code and len(code) == 0:
evm.gas_left += gas
push(evm.stack, U256(1))
return

child_message = Message(
block_env=evm.message.block_env,
Expand All @@ -330,6 +325,7 @@ def generic_call(
is_static=True if is_staticcall else evm.message.is_static,
accessed_addresses=evm.accessed_addresses.copy(),
accessed_storage_keys=evm.accessed_storage_keys.copy(),
disable_precompiles=disable_precompiles,
parent_evm=evm,
)
child_evm = process_message(child_message)
Expand Down Expand Up @@ -386,7 +382,7 @@ def call(evm: Evm) -> None:

code_address = to
(
is_delegated_code,
disable_precompiles,
code_address,
code,
delegated_access_gas_cost,
Expand Down Expand Up @@ -432,7 +428,7 @@ def call(evm: Evm) -> None:
memory_output_start_position,
memory_output_size,
code,
is_delegated_code,
disable_precompiles,
)

# PROGRAM COUNTER
Expand Down Expand Up @@ -475,7 +471,7 @@ def callcode(evm: Evm) -> None:
access_gas_cost = GAS_COLD_ACCOUNT_ACCESS

(
is_delegated_code,
disable_precompiles,
code_address,
code,
delegated_access_gas_cost,
Expand Down Expand Up @@ -516,7 +512,7 @@ def callcode(evm: Evm) -> None:
memory_output_start_position,
memory_output_size,
code,
is_delegated_code,
disable_precompiles,
)

# PROGRAM COUNTER
Expand Down Expand Up @@ -618,7 +614,7 @@ def delegatecall(evm: Evm) -> None:
access_gas_cost = GAS_COLD_ACCOUNT_ACCESS

(
is_delegated_code,
disable_precompiles,
code_address,
code,
delegated_access_gas_cost,
Expand Down Expand Up @@ -646,7 +642,7 @@ def delegatecall(evm: Evm) -> None:
memory_output_start_position,
memory_output_size,
code,
is_delegated_code,
disable_precompiles,
)

# PROGRAM COUNTER
Expand Down Expand Up @@ -687,7 +683,7 @@ def staticcall(evm: Evm) -> None:

code_address = to
(
is_delegated_code,
disable_precompiles,
code_address,
code,
delegated_access_gas_cost,
Expand Down Expand Up @@ -719,7 +715,7 @@ def staticcall(evm: Evm) -> None:
memory_output_start_position,
memory_output_size,
code,
is_delegated_code,
disable_precompiles,
)

# PROGRAM COUNTER
Expand Down
2 changes: 2 additions & 0 deletions src/ethereum/prague/vm/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ def execute_code(message: Message) -> Evm:
)
try:
if evm.message.code_address in PRE_COMPILED_CONTRACTS:
if message.disable_precompiles:
return evm
evm_trace(evm, PrecompileStart(evm.message.code_address))
PRE_COMPILED_CONTRACTS[evm.message.code_address](evm)
evm_trace(evm, PrecompileEnd())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def json_to_data(self) -> Bytes:
def json_to_access_list(self) -> Any:
"""Get the access list of the transaction."""
access_list = []
for sublist in self.raw.get("accessLists", []):
for sublist in self.raw.get("accessList", []):
access_list.append(
self.fork.Access(
self.fork.hex_to_address(sublist.get("address")),
Expand Down Expand Up @@ -192,7 +192,7 @@ def read(self) -> Any:
elif "maxFeePerGas" in self.raw:
tx_cls = self.fork.FeeMarketTransaction
tx_byte_prefix = b"\x02"
elif "accessLists" in self.raw:
elif "accessList" in self.raw:
tx_cls = self.fork.AccessListTransaction
tx_byte_prefix = b"\x01"
else:
Expand Down
2 changes: 1 addition & 1 deletion src/ethereum_spec_tools/evm_tools/statetest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def run_test_case(
tx[k] = value[v]
elif k == "accessLists":
if value[d] is not None:
tx["accessLists"] = value[d]
tx["accessList"] = value[d]
else:
tx[k] = value

Expand Down
2 changes: 1 addition & 1 deletion tests/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
},
"latest_fork_tests": {
"url": "https://github.com/gurukamath/latest_fork_tests.git",
"commit_hash": "bc74af5",
"commit_hash": "7a22f8e",
"fixture_path": "tests/fixtures/latest_fork_tests",
},
}
Expand Down
2 changes: 1 addition & 1 deletion tests/helpers/load_evm_tools_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def load_evm_tools_test(test_case: Dict[str, str], fork_name: str) -> None:
tx[k] = value[v]
elif k == "accessLists":
if value[d] is not None:
tx["accessLists"] = value[d]
tx["accessList"] = value[d]
else:
tx[k] = value

Expand Down
3 changes: 2 additions & 1 deletion whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -466,4 +466,5 @@ x2
eoa

blockchain
listdir
listdir
precompiles
Loading