From 650647337bb0344ca171d4d70fe878ae1a06ab9d Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 26 Sep 2025 14:25:29 +0200 Subject: [PATCH] Rebase of top of forks/amsterdam --- src/ethereum/forks/amsterdam/utils/address.py | 27 ++++++++++ .../amsterdam/vm/instructions/__init__.py | 2 + .../forks/amsterdam/vm/instructions/system.py | 51 +++++++++++++++++-- 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/ethereum/forks/amsterdam/utils/address.py b/src/ethereum/forks/amsterdam/utils/address.py index 69f91d0a03..44954a006c 100644 --- a/src/ethereum/forks/amsterdam/utils/address.py +++ b/src/ethereum/forks/amsterdam/utils/address.py @@ -89,3 +89,30 @@ def compute_create2_contract_address( padded_address = left_pad_zero_bytes(canonical_address, 20) return Address(padded_address) + + +def compute_setdelegate_contract_address( + address: Address, salt: Bytes32 +) -> Address: + """ + Computes address of the delegation objects account that needs to be + created or updated, which is based on the sender address and salt. + + Parameters + ---------- + address : + The address of the account that wants to create the new account. + salt : + Address generation salt. + + Returns + ------- + address: `ethereum.osaka.fork_types.Address` + The computed address of the delegation object. + """ + preimage = b"\xef\x01\x00" + address + salt + computed_address = keccak256(preimage) + canonical_address = computed_address[-20:] + padded_address = left_pad_zero_bytes(canonical_address, 20) + + return Address(padded_address) diff --git a/src/ethereum/forks/amsterdam/vm/instructions/__init__.py b/src/ethereum/forks/amsterdam/vm/instructions/__init__.py index 9cc30668e7..6fcfef5c5d 100644 --- a/src/ethereum/forks/amsterdam/vm/instructions/__init__.py +++ b/src/ethereum/forks/amsterdam/vm/instructions/__init__.py @@ -210,6 +210,7 @@ class Ops(enum.Enum): RETURN = 0xF3 DELEGATECALL = 0xF4 CREATE2 = 0xF5 + SETDELEGATE = 0xF6 STATICCALL = 0xFA REVERT = 0xFD SELFDESTRUCT = 0xFF @@ -365,4 +366,5 @@ class Ops(enum.Enum): Ops.STATICCALL: system_instructions.staticcall, Ops.REVERT: system_instructions.revert, Ops.CREATE2: system_instructions.create2, + Ops.SETDELEGATE: system_instructions.setdelegate, } diff --git a/src/ethereum/forks/amsterdam/vm/instructions/system.py b/src/ethereum/forks/amsterdam/vm/instructions/system.py index d7308821bd..05173c8246 100644 --- a/src/ethereum/forks/amsterdam/vm/instructions/system.py +++ b/src/ethereum/forks/amsterdam/vm/instructions/system.py @@ -19,6 +19,7 @@ from ...fork_types import Address from ...state import ( + account_exists, account_has_code_or_nonce, account_has_storage, get_account, @@ -28,9 +29,12 @@ set_account_balance, ) from ...utils.address import ( - compute_contract_address, - compute_create2_contract_address, - to_address_masked, + EOA_DELEGATION_MARKER, + PER_EMPTY_ACCOUNT_COST, + PER_AUTH_BASE_COST, + NULL_ADDRESS, + access_delegation, + is_valid_delegation, ) from ...vm.eoa_delegation import access_delegation from .. import ( @@ -39,7 +43,7 @@ incorporate_child_on_error, incorporate_child_on_success, ) -from ..exceptions import OutOfGasError, Revert, WriteInStaticContext +from ..exceptions import AddressCollision, OutOfGasError, Revert, WriteInStaticContext from ..gas import ( GAS_CALL_VALUE, GAS_COLD_ACCOUNT_ACCESS, @@ -241,6 +245,45 @@ def create2(evm: Evm) -> None: evm.pc += Uint(1) +def setdelegate(evm: EVM) -> None: + # GAS + charge_gas(evm, PER_EMPTY_ACCOUNT_COST) + + # STATIC CHECK + if evm.message.is_static: + raise WriteInStaticContext + + # STACK + target = to_address_masked(pop(evm.stack)) + salt = pop(evm.stack).to_be_bytes32() + + # OPERATION + location = compute_setdelegate_contract_address( + evm.message.current_target, + salt, + ) + + evm.accessed_addresses.add(location) + + current_code = get_account(state, location).code + if current_code != b"" and not is_valid_delegation(current_code): + raise AddressCollision + + if account_exists(state, location): + evm.refund_counter += U256(PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST) + + if target == NULL_ADDRESS: + code_to_set = b"" + else: + code_to_set = EOA_DELEGATION_MARKER + target + set_code(state, location, code_to_set) + + push(evm.stack, location) + + # PROGRAM COUNTER + evm.pc += Uint(1) + + def return_(evm: Evm) -> None: """ Halts execution returning output data.