22
33import pytest
44
5+ from ethereum_test_base_types .base_types import Address , Bytes
56from ethereum_test_tools import (
67 Account ,
78 Alloc ,
1314from ethereum_test_tools .vm .opcode import Opcodes
1415from ethereum_test_tools .vm .opcode import Opcodes as Op
1516from ethereum_test_types .eof .v1 import Container
17+ from ethereum_test_types .helpers import compute_create_address
18+ from tests .prague .eip7702_set_code_tx .spec import Spec
1619
1720from .. import EOF_FORK_NAME
1821from .helpers import (
22+ slot_all_subcall_gas_gone ,
1923 slot_code_worked ,
2024 slot_create_address ,
2125 smallest_initcode_subcontainer ,
3842 ],
3943)
4044@pytest .mark .parametrize (
41- "deploy_code " ,
45+ "initcode " ,
4246 [
47+ Bytes ("0xEF00" ),
48+ Bytes ("0xEF0001" ),
4349 pytest .param (smallest_initcode_subcontainer , id = "deploy_eof_initcontainer" ),
4450 pytest .param (smallest_runtime_subcontainer , id = "deploy_eof_container" ),
4551 ],
4652)
47- def test_cross_version_creates_fail (
53+ def test_cross_version_creates_fail_light (
4854 state_test : StateTestFiller ,
4955 pre : Alloc ,
5056 legacy_create_opcode : Opcodes ,
51- deploy_code : Container ,
57+ initcode : Bytes | Container ,
5258):
53- """Verifies that CREATE and CREATE2 cannot create EOF contracts ."""
59+ """Verifies that CREATE and CREATE2 cannot run EOF initcodes and fail early on attempt ."""
5460 env = Environment ()
55- salt_param = [ 0 ] if legacy_create_opcode == Op . CREATE2 else []
61+
5662 sender = pre .fund_eoa ()
63+
64+ tx_gas_limit = 10_000_000
65+
5766 contract_address = pre .deploy_contract (
5867 code = Op .CALLDATACOPY (0 , 0 , Op .CALLDATASIZE )
59- + Op .SSTORE (slot_create_address , legacy_create_opcode (0 , 0 , Op .CALLDATASIZE , * salt_param ))
68+ + Op .SSTORE (slot_create_address , legacy_create_opcode (size = Op .CALLDATASIZE ))
69+ # Aproximates whether code until here consumed the 63/64th gas given to subcall
70+ + Op .SSTORE (slot_all_subcall_gas_gone , Op .LT (Op .GAS , tx_gas_limit // 64 ))
6071 + Op .SSTORE (slot_code_worked , value_code_worked )
6172 + Op .STOP
6273 )
6374
64- # Storage in 0 should be empty as the create/create2 should fail,
65- # and 1 in 1 to show execution continued and did not halt
6675 post = {
6776 contract_address : Account (
6877 storage = {
6978 slot_create_address : EOFCREATE_FAILURE ,
7079 slot_code_worked : value_code_worked ,
71- }
72- )
80+ slot_all_subcall_gas_gone : 0 ,
81+ },
82+ nonce = 1 ,
83+ ),
84+ # Double check no accounts were created
85+ compute_create_address (address = contract_address , nonce = 1 ): Account .NONEXISTENT ,
86+ compute_create_address (
87+ address = contract_address , initcode = initcode , salt = 0 , opcode = Op .CREATE2
88+ ): Account .NONEXISTENT ,
7389 }
7490 tx = Transaction (
7591 to = contract_address ,
76- gas_limit = 10_000_000 ,
77- gas_price = 10 ,
78- protected = False ,
92+ gas_limit = tx_gas_limit ,
7993 sender = sender ,
80- data = deploy_code ,
94+ data = initcode ,
95+ )
96+
97+ state_test (
98+ env = env ,
99+ pre = pre ,
100+ post = post ,
101+ tx = tx ,
102+ )
103+
104+
105+ @pytest .mark .parametrize (
106+ "legacy_create_opcode" ,
107+ [
108+ pytest .param (Op .CREATE , id = "CREATE" ),
109+ pytest .param (Op .CREATE2 , id = "CREATE2" ),
110+ ],
111+ )
112+ @pytest .mark .parametrize (
113+ "initcode" ,
114+ [
115+ Bytes ("0xEF" ),
116+ Bytes ("0xEF01" ),
117+ Bytes ("0xEF0101" ),
118+ Spec .delegation_designation (Address (0xAA )),
119+ Bytes ("0xEF02" ),
120+ ],
121+ )
122+ def test_cross_version_creates_fail_hard (
123+ state_test : StateTestFiller ,
124+ pre : Alloc ,
125+ legacy_create_opcode : Opcodes ,
126+ initcode : Bytes ,
127+ ):
128+ """
129+ Verifies that CREATE and CREATE2 fail hard on attempt to run initcode starting with `EF` but
130+ not `EF00`.
131+ """
132+ env = Environment ()
133+
134+ sender = pre .fund_eoa ()
135+
136+ tx_gas_limit = 10_000_000
137+
138+ contract_address = pre .deploy_contract (
139+ code = Op .CALLDATACOPY (0 , 0 , Op .CALLDATASIZE )
140+ + Op .SSTORE (slot_create_address , legacy_create_opcode (size = Op .CALLDATASIZE ))
141+ # Aproximates whether code until here consumed the 63/64th gas given to subcall
142+ + Op .SSTORE (slot_all_subcall_gas_gone , Op .LT (Op .GAS , tx_gas_limit // 64 ))
143+ + Op .SSTORE (slot_code_worked , value_code_worked )
144+ + Op .STOP
145+ )
146+
147+ post = {
148+ contract_address : Account (
149+ storage = {
150+ slot_create_address : EOFCREATE_FAILURE ,
151+ slot_code_worked : value_code_worked ,
152+ slot_all_subcall_gas_gone : 1 ,
153+ },
154+ nonce = 2 ,
155+ ),
156+ # Double check no accounts were created
157+ compute_create_address (address = contract_address , nonce = 1 ): Account .NONEXISTENT ,
158+ compute_create_address (
159+ address = contract_address , initcode = initcode , salt = 0 , opcode = Op .CREATE2
160+ ): Account .NONEXISTENT ,
161+ }
162+ tx = Transaction (
163+ to = contract_address ,
164+ gas_limit = tx_gas_limit ,
165+ sender = sender ,
166+ data = initcode ,
81167 )
82168
83169 state_test (
@@ -98,6 +184,10 @@ def test_cross_version_creates_fail(
98184@pytest .mark .parametrize (
99185 "deploy_code" ,
100186 [
187+ Bytes ("0xEF" ),
188+ Bytes ("0xEF00" ),
189+ Bytes ("0xEF0001" ),
190+ Bytes ("0xEF01" ),
101191 pytest .param (smallest_initcode_subcontainer , id = "deploy_eof_initcontainer" ),
102192 pytest .param (smallest_runtime_subcontainer , id = "deploy_eof_container" ),
103193 ],
@@ -106,9 +196,13 @@ def test_legacy_initcode_eof_contract_fails(
106196 state_test : StateTestFiller ,
107197 pre : Alloc ,
108198 legacy_create_opcode : Opcodes ,
109- deploy_code : Container ,
199+ deploy_code : Bytes | Container ,
110200):
111- """Verifies that legacy initcode cannot create EOF."""
201+ """
202+ Verifies that legacy initcode cannot create EOF.
203+
204+ This tests only ensures EIP-3541 behavior is kept, not altered by EIP-7620.
205+ """
112206 env = Environment ()
113207 init_code = LegacyInitcode (deploy_code = deploy_code )
114208 salt_param = [0 ] if legacy_create_opcode == Op .CREATE2 else []
@@ -131,8 +225,6 @@ def test_legacy_initcode_eof_contract_fails(
131225 tx = Transaction (
132226 to = contract_address ,
133227 gas_limit = 10_000_000 ,
134- gas_price = 10 ,
135- protected = False ,
136228 data = init_code ,
137229 sender = sender ,
138230 )
0 commit comments