@@ -43,6 +43,10 @@ class RefundTestType(Enum):
43
43
The execution gas minus the refund is less than the data floor, hence the data floor cost is
44
44
charged.
45
45
"""
46
+ EXECUTION_GAS_MINUS_REFUND_EQUAL_TO_DATA_FLOOR = 2
47
+ """
48
+ The execution gas minus the refund is equal to the data floor.
49
+ """
46
50
47
51
48
52
class RefundType (Flag ):
@@ -127,6 +131,22 @@ def contract_creating_tx() -> bool:
127
131
return False
128
132
129
133
134
+ @pytest .fixture
135
+ def intrinsic_gas_data_floor_minimum_delta () -> int :
136
+ """
137
+ Induce a minimum delta between the transaction intrinsic gas cost and the
138
+ floor data gas cost.
139
+
140
+ Since at least one of the cases requires some execution gas expenditure (SSTORE clearing),
141
+ we need to introduce an increment of the floor data cost above the transaction intrinsic gas
142
+ cost, otherwise the floor data cost would always be the below the execution gas cost even
143
+ after the refund is applied.
144
+
145
+ This value has been set as of Prague and should be adjusted if the gas costs change.
146
+ """
147
+ return 250
148
+
149
+
130
150
@pytest .fixture
131
151
def execution_gas_used (
132
152
tx_intrinsic_gas_cost_before_execution : int ,
@@ -140,9 +160,10 @@ def execution_gas_used(
140
160
141
161
This gas amount is on top of the transaction intrinsic gas cost.
142
162
143
- Since intrinsic_gas_data_floor_minimum_delta is zero for all test cases, if this value is zero
144
- it will result in the refund being applied to the execution gas cost and the resulting amount
145
- being always below the floor data cost.
163
+ If this value were zero it would result in the refund being applied to the execution gas cost
164
+ and the resulting amount being always below the floor data cost, hence we need to find a
165
+ higher value in this function to ensure we get both scenarios where the refund drives
166
+ the execution cost below the floor data cost and above the floor data cost.
146
167
"""
147
168
148
169
def execution_gas_cost (execution_gas : int ) -> int :
@@ -151,13 +172,18 @@ def execution_gas_cost(execution_gas: int) -> int:
151
172
152
173
execution_gas = prefix_code_gas
153
174
154
- assert execution_gas_cost (execution_gas ) < tx_floor_data_cost , "tx_floor_data_cost is too low"
175
+ assert execution_gas_cost (execution_gas ) < tx_floor_data_cost , (
176
+ "tx_floor_data_cost is too low, there might have been a gas cost change that caused this "
177
+ "test to fail. Try increasing the intrinsic_gas_data_floor_minimum_delta fixture."
178
+ )
155
179
156
180
# Dumb for-loop to find the execution gas cost that will result in the expected refund.
157
181
while execution_gas_cost (execution_gas ) < tx_floor_data_cost :
158
182
execution_gas += 1
159
- if refund_test_type == RefundTestType .EXECUTION_GAS_MINUS_REFUND_GREATER_THAN_DATA_FLOOR :
183
+ if refund_test_type == RefundTestType .EXECUTION_GAS_MINUS_REFUND_EQUAL_TO_DATA_FLOOR :
160
184
return execution_gas
185
+ elif refund_test_type == RefundTestType .EXECUTION_GAS_MINUS_REFUND_GREATER_THAN_DATA_FLOOR :
186
+ return execution_gas + 1
161
187
elif refund_test_type == RefundTestType .EXECUTION_GAS_MINUS_REFUND_LESS_THAN_DATA_FLOOR :
162
188
return execution_gas - 1
163
189
@@ -183,9 +209,16 @@ def to(
183
209
prefix_code_gas : int ,
184
210
code_storage : Dict ,
185
211
) -> Address | None :
186
- """Return a contract that consumes the expected execution gas."""
212
+ """
213
+ Return a contract that consumes the expected execution gas.
214
+
215
+ At the moment we naively use JUMPDEST to consume the gas, which can yield very big contracts.
216
+
217
+ Ideally, we can use memory expansion to consume gas.
218
+ """
219
+ extra_gas = execution_gas_used - prefix_code_gas
187
220
return pre .deploy_contract (
188
- prefix_code + (Op .JUMPDEST * ( execution_gas_used - prefix_code_gas ) ) + Op .STOP ,
221
+ prefix_code + (Op .JUMPDEST * extra_gas ) + Op .STOP ,
189
222
storage = code_storage ,
190
223
)
191
224
@@ -211,6 +244,7 @@ def tx_gas_limit(
211
244
[
212
245
RefundTestType .EXECUTION_GAS_MINUS_REFUND_GREATER_THAN_DATA_FLOOR ,
213
246
RefundTestType .EXECUTION_GAS_MINUS_REFUND_LESS_THAN_DATA_FLOOR ,
247
+ RefundTestType .EXECUTION_GAS_MINUS_REFUND_EQUAL_TO_DATA_FLOOR ,
214
248
],
215
249
)
216
250
@pytest .mark .parametrize (
@@ -236,7 +270,9 @@ def test_gas_refunds_from_data_floor(
236
270
if refund_test_type == RefundTestType .EXECUTION_GAS_MINUS_REFUND_LESS_THAN_DATA_FLOOR :
237
271
assert gas_used < tx_floor_data_cost
238
272
elif refund_test_type == RefundTestType .EXECUTION_GAS_MINUS_REFUND_GREATER_THAN_DATA_FLOOR :
239
- assert gas_used >= tx_floor_data_cost
273
+ assert gas_used > tx_floor_data_cost
274
+ elif refund_test_type == RefundTestType .EXECUTION_GAS_MINUS_REFUND_EQUAL_TO_DATA_FLOOR :
275
+ assert gas_used == tx_floor_data_cost
240
276
else :
241
277
raise ValueError ("Invalid refund test type" )
242
278
if gas_used < tx_floor_data_cost :
0 commit comments