55
66import pytest
77
8- from ethereum_test_tools import Account , Alloc , Environment , StateTestFiller , Transaction
8+ from ethereum_test_tools import Alloc , Environment , StateTestFiller
99from ethereum_test_tools .eof .v1 import Container
1010from ethereum_test_tools .vm .opcode import Opcodes as Op
11- from ethereum_test_types .eof .v1 import Section
12- from ethereum_test_types .types import EOA
13- from ethereum_test_vm import Bytecode , EVMCodeType
1411
1512from .. import EOF_FORK_NAME
13+ from ..gas_test import gas_test
1614from . import REFERENCE_SPEC_GIT_PATH , REFERENCE_SPEC_VERSION
17- from .helpers import (
18- slot_cold_gas ,
19- slot_oog_call_result ,
20- slot_sanity_call_result ,
21- slot_warm_gas ,
22- value_call_legacy_abort ,
23- value_call_legacy_success ,
24- )
2515
2616REFERENCE_SPEC_GIT_PATH = REFERENCE_SPEC_GIT_PATH
2717REFERENCE_SPEC_VERSION = REFERENCE_SPEC_VERSION
@@ -47,126 +37,6 @@ def state_env() -> Environment:
4737 return Environment ()
4838
4939
50- def gas_test (
51- state_test : StateTestFiller ,
52- env : Environment ,
53- pre : Alloc ,
54- setup_code : Bytecode ,
55- subject_code : Bytecode ,
56- tear_down_code : Bytecode ,
57- cold_gas : int ,
58- warm_gas : int | None = None ,
59- subject_subcontainer : Container | None = None ,
60- sender : EOA | None = None ,
61- subject_balance : int = 0 ,
62- oog_difference : int = 1 ,
63- ):
64- """
65- Creates a State Test to check the gas cost of a sequence of EOF code.
66-
67- `setup_code` and `tear_down_code` are called multiple times during the test, and MUST NOT have
68- any side-effects which persist across message calls, and in particular, any effects on the gas
69- usage of `subject_code`.
70- """
71- if cold_gas <= 0 :
72- raise ValueError (f"Target gas allocations (cold_gas) must be > 0, got { cold_gas } " )
73- if warm_gas is None :
74- warm_gas = cold_gas
75-
76- if not sender :
77- sender = pre .fund_eoa ()
78-
79- address_baseline = pre .deploy_contract (Container .Code (setup_code + tear_down_code ))
80- code_subject = setup_code + subject_code + tear_down_code
81- address_subject = pre .deploy_contract (
82- Container .Code (code_subject )
83- if not subject_subcontainer
84- else Container (
85- sections = [
86- Section .Code (code_subject ),
87- Section .Container (subject_subcontainer ),
88- ]
89- ),
90- balance = subject_balance ,
91- )
92- # 2 times GAS, POP, CALL, 6 times PUSH1 - instructions charged for at every gas run
93- gas_single_gas_run = 2 * 2 + 2 + WARM_ACCOUNT_ACCESS_GAS + 6 * 3
94- address_legacy_harness = pre .deploy_contract (
95- code = (
96- # warm subject and baseline without executing
97- (Op .BALANCE (address_subject ) + Op .POP + Op .BALANCE (address_baseline ) + Op .POP )
98- # Baseline gas run
99- + (
100- Op .GAS
101- + Op .CALL (address = address_baseline , gas = Op .GAS )
102- + Op .POP
103- + Op .GAS
104- + Op .SWAP1
105- + Op .SUB
106- )
107- # cold gas run
108- + (
109- Op .GAS
110- + Op .CALL (address = address_subject , gas = Op .GAS )
111- + Op .POP
112- + Op .GAS
113- + Op .SWAP1
114- + Op .SUB
115- )
116- # warm gas run
117- + (
118- Op .GAS
119- + Op .CALL (address = address_subject , gas = Op .GAS )
120- + Op .POP
121- + Op .GAS
122- + Op .SWAP1
123- + Op .SUB
124- )
125- # Store warm gas: DUP3 is the gas of the baseline gas run
126- + (Op .DUP3 + Op .SWAP1 + Op .SUB + Op .PUSH2 (slot_warm_gas ) + Op .SSTORE )
127- # store cold gas: DUP2 is the gas of the baseline gas run
128- + (Op .DUP2 + Op .SWAP1 + Op .SUB + Op .PUSH2 (slot_cold_gas ) + Op .SSTORE )
129- # oog gas run:
130- # - DUP7 is the gas of the baseline gas run, after other CALL args were pushed
131- # - subtract the gas charged by the harness
132- # - add warm gas charged by the subject
133- # - subtract `oog_difference` to cause OOG exception (1 by default)
134- + Op .SSTORE (
135- slot_oog_call_result ,
136- Op .CALL (
137- gas = Op .ADD (warm_gas - gas_single_gas_run - oog_difference , Op .DUP7 ),
138- address = address_subject ,
139- ),
140- )
141- # sanity gas run: not subtracting 1 to see if enough gas makes the call succeed
142- + Op .SSTORE (
143- slot_sanity_call_result ,
144- Op .CALL (
145- gas = Op .ADD (warm_gas - gas_single_gas_run , Op .DUP7 ),
146- address = address_subject ,
147- ),
148- )
149- + Op .STOP
150- ),
151- evm_code_type = EVMCodeType .LEGACY , # Needs to be legacy to use GAS opcode
152- )
153-
154- post = {
155- address_legacy_harness : Account (
156- storage = {
157- slot_warm_gas : warm_gas ,
158- slot_cold_gas : cold_gas ,
159- slot_oog_call_result : value_call_legacy_abort ,
160- slot_sanity_call_result : value_call_legacy_success ,
161- },
162- ),
163- }
164-
165- tx = Transaction (to = address_legacy_harness , gas_limit = env .gas_limit , sender = sender )
166-
167- state_test (env = env , pre = pre , tx = tx , post = post )
168-
169-
17040@pytest .mark .parametrize (
17141 ["opcode" , "pre_setup" , "cold_gas" , "warm_gas" , "new_account" ],
17242 [
0 commit comments