Skip to content

Commit 55d4d1c

Browse files
committed
fix(tests): reconcile EIP-2780/8037 gas expectations across cherry-picked specs
1 parent e66b45d commit 55d4d1c

5 files changed

Lines changed: 64 additions & 45 deletions

File tree

tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,9 +1363,12 @@ def test_create_tx_header_gas_used(
13631363
intrinsic_cost = fork.transaction_intrinsic_cost_calculator()
13641364
# Regular-only creation intrinsic; STOP initcode deploys empty
13651365
# code (zero deposit) and the pre-existing target adds no state
1366-
# gas, so the regular intrinsic dominates.
1366+
# gas, so the regular intrinsic dominates. Block regular gas
1367+
# excludes any calldata-floor top-up, so use the raw intrinsic.
13671368
expected_gas_used = intrinsic_cost(
1368-
calldata=bytes(initcode), contract_creation=True
1369+
calldata=bytes(initcode),
1370+
contract_creation=True,
1371+
return_cost_deducted_prior_execution=True,
13691372
)
13701373
else:
13711374
# For a minimal CREATE tx deploying Op.STOP (1 byte),
@@ -2162,27 +2165,38 @@ def test_failed_create_tx_refills_top_frame_new_account(
21622165
21632166
* REVERT preserves ``gas_left`` and ``refill_frame_state_gas`` returns
21642167
the spilled ``NEW_ACCOUNT`` to it, so the state block nets to zero
2165-
and the sender pays only ``intrinsic_regular + revert_regular``.
2168+
and the sender pays only the regular consumption (pinned to the
2169+
calldata floor).
21662170
* HALT (INVALID) refills the spilled ``NEW_ACCOUNT`` to ``gas_left``
21672171
and then burns all of it, so the sender pays the full ``gas_limit``.
21682172
"""
21692173
gas_costs = fork.gas_costs()
21702174
intrinsic_calc = fork.transaction_intrinsic_cost_calculator()
21712175

21722176
intrinsic_regular = intrinsic_calc(
2173-
calldata=bytes(init_code), contract_creation=True
2177+
calldata=bytes(init_code),
2178+
contract_creation=True,
2179+
return_cost_deducted_prior_execution=True,
21742180
)
21752181
# gas_limit must cover the top-frame NEW_ACCOUNT so the initcode runs.
21762182
gas_limit = intrinsic_regular + gas_costs.NEW_ACCOUNT + 1000
21772183

21782184
if init_code == Op.INVALID:
21792185
# Exceptional halt burns all gas_left (the refilled NEW_ACCOUNT
21802186
# included).
2181-
expected_gas_used = gas_limit
2187+
expected_header_gas = expected_receipt_gas = gas_limit
21822188
else:
21832189
# REVERT refills the spilled NEW_ACCOUNT, netting the state block
2184-
# to zero, so only the regular consumption is billed.
2185-
expected_gas_used = intrinsic_regular + init_code.regular_cost(fork)
2190+
# to zero, so only the regular consumption is billed. The tiny
2191+
# initcode pins the receipt to the calldata floor, which block
2192+
# regular gas excludes.
2193+
expected_header_gas = intrinsic_regular + init_code.regular_cost(fork)
2194+
expected_receipt_gas = max(
2195+
expected_header_gas,
2196+
fork.transaction_data_floor_cost_calculator()(
2197+
data=init_code, contract_creation=True
2198+
),
2199+
)
21862200

21872201
sender = pre.fund_eoa()
21882202
created = compute_create_address(address=sender, nonce=0)
@@ -2193,15 +2207,15 @@ def test_failed_create_tx_refills_top_frame_new_account(
21932207
gas_limit=gas_limit,
21942208
sender=sender,
21952209
expected_receipt=TransactionReceipt(
2196-
cumulative_gas_used=expected_gas_used,
2210+
cumulative_gas_used=expected_receipt_gas,
21972211
),
21982212
)
21992213

22002214
state_test(
22012215
pre=pre,
22022216
post={created: Account.NONEXISTENT},
22032217
tx=tx,
2204-
blockchain_test_header_verify=Header(gas_used=expected_gas_used),
2218+
blockchain_test_header_verify=Header(gas_used=expected_header_gas),
22052219
)
22062220

22072221

@@ -2271,11 +2285,12 @@ def test_create_tx_collision_refunds_reservoir(
22712285
address collision when `gas_limit > TX_MAX_GAS_LIMIT`.
22722286
22732287
EIP-8037 splits `gas_limit` into the capped regular budget and a
2274-
state-gas reservoir. On collision the inner regular gas is burnt
2275-
and `intrinsic_state_gas` is refunded; the reservoir must also
2276-
be refunded to the sender. `header.gas_used` is fixed at the
2277-
regular cap regardless of reservoir handling, so the sender's
2278-
post-balance is the primary discriminating assertion.
2288+
state-gas reservoir seeded with the create component. On collision
2289+
the inner regular gas is burnt and the alive target is never
2290+
charged; the full reservoir must be returned to the sender.
2291+
`header.gas_used` is fixed at the regular cap regardless of
2292+
reservoir handling, so the sender's post-balance is the primary
2293+
discriminating assertion.
22792294
"""
22802295
gas_limit_cap = fork.transaction_gas_limit_cap()
22812296
assert gas_limit_cap is not None
@@ -2900,7 +2915,7 @@ def test_create_collision_burned_gas_counted_in_block_regular(
29002915
)
29012916

29022917
# CPSB-agnostic baseline: block_state_gas is zero for this tx (the
2903-
# collision refunds the NEW_ACCOUNT state charge), so header.gas_used
2918+
# existent collision target is not charged), so header.gas_used
29042919
# equals the regular-gas total. Decompose the parent + inner frame
29052920
# accounting from fork APIs so the baseline tracks future cost
29062921
# changes automatically.
@@ -2922,23 +2937,21 @@ def test_create_collision_burned_gas_counted_in_block_regular(
29222937
)
29232938
# MSTORE writes the initcode at memory[0:32] (one word).
29242939
memory_expansion = fork.memory_expansion_gas_calculator()(new_bytes=32)
2925-
# gas_left at the moment NEW_ACCOUNT spills into the regular pool
2926-
# (reservoir is empty for tx_gas_limit < TX_MAX_GAS_LIMIT).
2927-
gas_at_create_after_state = (
2940+
# gas_left at the CREATE split. The collision target is existent, so no
2941+
# account-creation charge is applied before the 63/64 split.
2942+
gas_at_create = (
29282943
gas_limit
29292944
- intrinsic
29302945
- factory_pre_create
29312946
- memory_expansion
29322947
- create_base
2933-
- new_account
29342948
)
29352949
# Inner burns 63/64 of the available gas on collision; the parent
2936-
# retains 1/64. The state-spill of NEW_ACCOUNT is refunded back to
2937-
# gas_left on collision (nets zero). Post-CREATE consumes from the
2938-
# retained pool. A mutation that drops the burned forwarded gas
2939-
# from regular accounting would reduce this baseline.
2940-
retained = gas_at_create_after_state // 64
2941-
baseline_gas_used = gas_limit - retained - new_account + post_create_static
2950+
# retains 1/64. Post-CREATE consumes from the retained pool. A
2951+
# mutation that drops the burned forwarded gas from regular
2952+
# accounting would reduce this baseline.
2953+
retained = gas_at_create // 64
2954+
baseline_gas_used = gas_limit - retained + post_create_static
29422955

29432956
blockchain_test(
29442957
pre=pre,

tests/amsterdam/eip8038_state_access_gas_cost_increase/test_selfdestruct_gas.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,12 @@ def test_same_tx_created_selfdestruct_self_burn(
569569

570570
# Creation intrinsic is regular-only under EIP-2780; the pre-existing
571571
# target adds no top-frame NEW_ACCOUNT and the self-burn adds no state
572-
# gas, so net state gas is zero.
572+
# gas, so net state gas is zero. Use the raw intrinsic: the initcode
573+
# execution keeps the receipt above the calldata floor.
573574
intrinsic_regular = intrinsic_calc(
574-
calldata=bytes(init_code), contract_creation=True
575+
calldata=bytes(init_code),
576+
contract_creation=True,
577+
return_cost_deducted_prior_execution=True,
575578
)
576579
expected_regular = intrinsic_regular + init_code.regular_cost(fork)
577580
expected_gas_used = expected_regular

tests/ported_static/stCreateTest/test_transaction_collision_to_empty_but_code.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,17 @@ def test_transaction_collision_to_empty_but_code(
137137
error=_exc,
138138
)
139139

140-
# On collision, all execution gas is reclassified to regular and the
141-
# tx-time state reservoir is restored. Under EIP-8037 2D gas this
142-
# gives header.gas_used = max(intrinsic_regular + execution_gas,
143-
# intrinsic_state); pre-EIP-8037 the state component is zero, so the
144-
# same expression collapses to tx.gas.
140+
# On collision, all execution gas is burned as regular. Under
141+
# EIP-2780 the creation NEW_ACCOUNT is a top-frame runtime charge,
142+
# never levied on collision, and the intrinsic state component is
143+
# zero, so the expression collapses to tx.gas on every fork.
145144
intrinsic_total = fork.transaction_intrinsic_cost_calculator()(
146145
calldata=bytes(tx_data[d]),
147146
contract_creation=True,
148147
)
149-
intrinsic_state = fork.create_state_gas()
148+
intrinsic_state = fork.transaction_intrinsic_state_gas(
149+
contract_creation=True
150+
)
150151
intrinsic_regular = intrinsic_total - intrinsic_state
151152
execution_gas = tx_gas[g] - intrinsic_total
152153
expected_header_gas_used = max(

tests/ported_static/stCreateTest/test_transaction_collision_to_empty_but_nonce.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,17 @@ def test_transaction_collision_to_empty_but_nonce(
105105
contract_0: Account(storage={1: 0}, nonce=1),
106106
}
107107

108-
# On collision, all execution gas is reclassified to regular and the
109-
# tx-time state reservoir is restored. Under EIP-8037 2D gas this
110-
# gives header.gas_used = max(intrinsic_regular + execution_gas,
111-
# intrinsic_state); pre-EIP-8037 the state component is zero, so the
112-
# same expression collapses to tx.gas.
108+
# On collision, all execution gas is burned as regular. Under
109+
# EIP-2780 the creation NEW_ACCOUNT is a top-frame runtime charge,
110+
# never levied on collision, and the intrinsic state component is
111+
# zero, so the expression collapses to tx.gas on every fork.
113112
intrinsic_total = fork.transaction_intrinsic_cost_calculator()(
114113
calldata=bytes(tx_data[d]),
115114
contract_creation=True,
116115
)
117-
intrinsic_state = fork.create_state_gas()
116+
intrinsic_state = fork.transaction_intrinsic_state_gas(
117+
contract_creation=True
118+
)
118119
intrinsic_regular = intrinsic_total - intrinsic_state
119120
execution_gas = tx_gas[g] - intrinsic_total
120121
expected_header_gas_used = max(

tests/ported_static/stEIP3607/test_init_colliding_with_non_empty_account.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,17 @@ def test_init_colliding_with_non_empty_account(
164164
sender: Account(nonce=1),
165165
}
166166

167-
# On collision, all execution gas is reclassified to regular and the
168-
# tx-time state reservoir is restored. Under EIP-8037 2D gas this
169-
# gives header.gas_used = max(intrinsic_regular + execution_gas,
170-
# intrinsic_state); pre-EIP-8037 the state component is zero, so the
171-
# same expression collapses to tx.gas.
167+
# On collision, all execution gas is burned as regular. Under
168+
# EIP-2780 the creation NEW_ACCOUNT is a top-frame runtime charge,
169+
# never levied on collision, and the intrinsic state component is
170+
# zero, so the expression collapses to tx.gas on every fork.
172171
intrinsic_total = fork.transaction_intrinsic_cost_calculator()(
173172
calldata=bytes(tx_data[d]),
174173
contract_creation=True,
175174
)
176-
intrinsic_state = fork.create_state_gas()
175+
intrinsic_state = fork.transaction_intrinsic_state_gas(
176+
contract_creation=True
177+
)
177178
intrinsic_regular = intrinsic_total - intrinsic_state
178179
execution_gas = tx_gas[g] - intrinsic_total
179180
expected_header_gas_used = max(

0 commit comments

Comments
 (0)