Skip to content

Commit 2e707c2

Browse files
authored
feat(spec,test): update bal-devnet-7 EIP-8037 bytes values; CPSB 1174 -> 1530 (#2827)
1 parent 9d3906e commit 2e707c2

62 files changed

Lines changed: 1955 additions & 644 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/testing/src/execution_testing/forks/forks/eips/amsterdam/eip_8037.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@
1919
from ....base_fork import BaseFork
2020
from ....gas_costs import GasCosts
2121

22+
# EIP-8037 state byte sizes (mirrors EELS amsterdam/vm/gas.py).
23+
STATE_BYTES_PER_NEW_ACCOUNT = 120
24+
STATE_BYTES_PER_STORAGE_SET = 64
25+
STATE_BYTES_PER_AUTH_BASE = 23
26+
27+
# EIP-8037 regular gas base costs.
28+
PER_AUTH_BASE_COST = 7_500
29+
REGULAR_GAS_CREATE = 9_000
30+
2231

2332
class EIP8037(BaseFork):
2433
"""EIP-8037 class."""
@@ -28,12 +37,11 @@ def cost_per_state_byte(cls) -> int:
2837
"""
2938
Return the fixed cost per state byte for EIP-8037.
3039
"""
31-
return 1174
40+
return 1530
3241

3342
@classmethod
3443
def sstore_state_gas(cls) -> int:
3544
"""Return state gas for a zero-to-nonzero SSTORE (EIP-8037)."""
36-
STATE_BYTES_PER_STORAGE_SET = 32 # noqa: N806
3745
return STATE_BYTES_PER_STORAGE_SET * cls.cost_per_state_byte()
3846

3947
@classmethod
@@ -57,13 +65,6 @@ def gas_costs(cls) -> GasCosts:
5765
"""
5866
cpsb = cls.cost_per_state_byte()
5967
parent = super(EIP8037, cls).gas_costs()
60-
# EIP-8037 state byte sizes (EELS amsterdam/vm/gas.py)
61-
STATE_BYTES_PER_STORAGE_SET = 32 # noqa: N806
62-
STATE_BYTES_PER_NEW_ACCOUNT = 112 # noqa: N806
63-
STATE_BYTES_PER_AUTH_BASE = 23 # noqa: N806
64-
# EIP-8037 regular gas base costs
65-
PER_AUTH_BASE_COST = 7_500 # noqa: N806
66-
REGULAR_GAS_CREATE = 9_000 # noqa: N806
6768
new_acct = STATE_BYTES_PER_NEW_ACCOUNT * cpsb
6869
return replace(
6970
parent,
@@ -258,8 +259,6 @@ def transaction_intrinsic_state_gas(
258259
- Auth: (NEW_ACCOUNT + AUTH_BASE) * cpsb
259260
"""
260261
cpsb = cls.cost_per_state_byte()
261-
STATE_BYTES_PER_NEW_ACCOUNT = 112 # noqa: N806
262-
STATE_BYTES_PER_AUTH_BASE = 23 # noqa: N806
263262
state_gas = 0
264263
if contract_creation:
265264
state_gas += STATE_BYTES_PER_NEW_ACCOUNT * cpsb
@@ -278,7 +277,7 @@ def _calculate_sstore_gas(
278277
Calculate updated SSTORE gas cost.
279278
280279
For 0->nonzero: regular (UPDATE - COLD_SLOAD) + state
281-
(32 * cpsb).
280+
(STATE_BYTES_PER_STORAGE_SET * cpsb).
282281
For nonzero->different nonzero: regular
283282
(UPDATE - COLD_SLOAD).
284283
Otherwise: WARM_SLOAD.
@@ -324,7 +323,7 @@ def _calculate_sstore_state_gas(
324323
and current_value != new_value
325324
and original_value == 0
326325
):
327-
return 32 * cpsb
326+
return STATE_BYTES_PER_STORAGE_SET * cpsb
328327
return 0
329328

330329
@classmethod
@@ -368,9 +367,9 @@ def _calculate_sstore_state_refund(
368367
"""
369368
Calculate SSTORE state gas refund.
370369
371-
Return the state-gas portion (`32 * cpsb`) when a slot that
372-
was originally empty is restored back to zero within the
373-
transaction; otherwise return 0.
370+
Return the state-gas portion (`STATE_BYTES_PER_STORAGE_SET *
371+
cpsb`) when a slot that was originally empty is restored back
372+
to zero within the transaction; otherwise return 0.
374373
"""
375374
del gas_costs
376375
metadata = opcode.metadata
@@ -384,7 +383,7 @@ def _calculate_sstore_state_refund(
384383
if current_value != new_value:
385384
if original_value == new_value:
386385
if original_value == 0:
387-
return 32 * cpsb
386+
return STATE_BYTES_PER_STORAGE_SET * cpsb
388387
return 0
389388

390389
@classmethod
@@ -394,8 +393,9 @@ def _calculate_selfdestruct_state_refund(
394393
"""
395394
Calculate SELFDESTRUCT state gas refund.
396395
397-
Account creation: 112 × cost_per_state_byte
398-
Created storage slots: 32 × cost_per_state_byte per non-zero slot
396+
Account creation: STATE_BYTES_PER_NEW_ACCOUNT × cost_per_state_byte
397+
Created storage slots: STATE_BYTES_PER_STORAGE_SET ×
398+
cost_per_state_byte per non-zero slot
399399
Code deposit: len(code) × cost_per_state_byte
400400
"""
401401
del gas_costs
@@ -411,9 +411,11 @@ def _calculate_selfdestruct_state_refund(
411411
]
412412
state_refund = 0
413413
if self_destructed_account:
414-
state_refund = 112 * cpsb
414+
state_refund = STATE_BYTES_PER_NEW_ACCOUNT * cpsb
415415
state_refund += (
416-
32 * cpsb * self_destructed_account_storage_slot_count
416+
STATE_BYTES_PER_STORAGE_SET
417+
* cpsb
418+
* self_destructed_account_storage_slot_count
417419
)
418420
state_refund += cpsb * self_destructed_account_code_deposit
419421
return state_refund

src/ethereum/forks/amsterdam/vm/gas.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@
2626
from .exceptions import OutOfGasError
2727

2828
# EIP-8037 state gas accounting constants
29-
COST_PER_STATE_BYTE = Uint(1174)
29+
COST_PER_STATE_BYTE = Uint(1530)
3030

31-
STATE_BYTES_PER_NEW_ACCOUNT = Uint(112)
32-
STATE_BYTES_PER_STORAGE_SET = Uint(32)
31+
STATE_BYTES_PER_NEW_ACCOUNT = Uint(120)
32+
STATE_BYTES_PER_STORAGE_SET = Uint(64)
3333
STATE_BYTES_PER_AUTH_BASE = Uint(23)
3434

3535
PER_AUTH_BASE_COST = Uint(7500)

tests/amsterdam/eip7708_eth_transfer_logs/test_burn_logs.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def test_selfdestruct_to_self_same_tx(
8383
state_test: StateTestFiller,
8484
env: Environment,
8585
pre: Alloc,
86+
fork: Fork,
8687
sender: EOA,
8788
contract_balance: int,
8889
create_opcode: Op,
@@ -125,7 +126,9 @@ def test_selfdestruct_to_self_same_tx(
125126
sender=sender,
126127
to=factory,
127128
value=contract_balance,
128-
gas_limit=200_000,
129+
# Same-tx CREATE+SELFDESTRUCT charges NEW_ACCOUNT state gas
130+
# under EIP-8037 (0 otherwise).
131+
gas_limit=200_000 + fork.gas_costs().NEW_ACCOUNT,
129132
expected_receipt=TransactionReceipt(logs=expected_logs),
130133
)
131134

@@ -144,6 +147,7 @@ def test_selfdestruct_to_different_address_same_tx(
144147
state_test: StateTestFiller,
145148
env: Environment,
146149
pre: Alloc,
150+
fork: Fork,
147151
sender: EOA,
148152
contract_balance: int,
149153
create_opcode: Op,
@@ -189,7 +193,9 @@ def test_selfdestruct_to_different_address_same_tx(
189193
sender=sender,
190194
to=factory,
191195
value=contract_balance,
192-
gas_limit=200_000,
196+
# Same-tx CREATE+SELFDESTRUCT charges NEW_ACCOUNT state gas
197+
# under EIP-8037 (0 otherwise).
198+
gas_limit=200_000 + fork.gas_costs().NEW_ACCOUNT,
193199
expected_receipt=TransactionReceipt(logs=expected_logs),
194200
)
195201

@@ -222,6 +228,7 @@ def test_selfdestruct_same_tx_via_call(
222228
state_test: StateTestFiller,
223229
env: Environment,
224230
pre: Alloc,
231+
fork: Fork,
225232
sender: EOA,
226233
to_self: bool,
227234
call_twice: bool,
@@ -303,7 +310,9 @@ def test_selfdestruct_same_tx_via_call(
303310
sender=sender,
304311
to=factory,
305312
value=0,
306-
gas_limit=300_000,
313+
# CREATE-then-CALL with same-tx SELFDESTRUCT charges
314+
# NEW_ACCOUNT state gas under EIP-8037 (0 otherwise).
315+
gas_limit=200_000 + fork.gas_costs().NEW_ACCOUNT,
307316
expected_receipt=TransactionReceipt(logs=expected_logs),
308317
)
309318

@@ -507,7 +516,7 @@ def test_finalization_burn_logs(
507516
to=None,
508517
value=0,
509518
data=factory_code,
510-
gas_limit=1_000_000,
519+
gas_limit=2_000_000,
511520
expected_receipt=TransactionReceipt(
512521
logs=execution_logs + finalization_logs
513522
),

tests/amsterdam/eip7708_eth_transfer_logs/test_fork_transition.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Alloc,
1212
Block,
1313
BlockchainTestFiller,
14+
Fork,
1415
Op,
1516
Transaction,
1617
TransactionReceipt,
@@ -35,6 +36,7 @@
3536
def test_burn_log_at_fork_transition(
3637
blockchain_test: BlockchainTestFiller,
3738
pre: Alloc,
39+
fork: Fork,
3840
same_tx: bool,
3941
to_self: bool,
4042
) -> None:
@@ -117,19 +119,34 @@ def test_burn_log_at_fork_transition(
117119
beneficiary: Account(balance=contract_balance * 3),
118120
}
119121

122+
# `fork` is a TransitionFork here; resolve to the post-transition
123+
# fork (where the larger NEW_ACCOUNT applies) so the gas budget
124+
# covers the same-tx CREATE+SELFDESTRUCT on the post-transition
125+
# block. The pre-transition block has plenty of headroom.
126+
pre_transition_timestamp = 14_999
127+
transition_timestamp = 15_000
128+
post_transition_timestamp = 15_001
129+
post_fork = fork.fork_at(timestamp=post_transition_timestamp)
130+
gas_limit = 200_000 + post_fork.gas_costs().NEW_ACCOUNT
120131
blocks = [
121132
Block(
122133
timestamp=ts,
123134
txs=[
124135
Transaction(
125136
to=targets[i],
126137
sender=sender,
127-
gas_limit=200_000,
138+
gas_limit=gas_limit,
128139
expected_receipt=TransactionReceipt(logs=expected_logs[i]),
129140
)
130141
],
131142
)
132-
for i, ts in enumerate([14_999, 15_000, 15_001])
143+
for i, ts in enumerate(
144+
[
145+
pre_transition_timestamp,
146+
transition_timestamp,
147+
post_transition_timestamp,
148+
]
149+
)
133150
]
134151

135152
blockchain_test(pre=pre, blocks=blocks, post=post)

tests/amsterdam/eip7708_eth_transfer_logs/test_transfer_logs.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,16 +1095,20 @@ def test_transfer_with_all_tx_types(
10951095
state_test: StateTestFiller,
10961096
env: Environment,
10971097
pre: Alloc,
1098+
fork: Fork,
10981099
sender: EOA,
10991100
typed_transaction: Transaction,
11001101
) -> None:
11011102
"""Test that ETH transfers emit logs for all transaction types."""
11021103
recipient = pre.nonexistent_account()
11031104
transfer_amount = 1000
11041105

1106+
# Sending value to a nonexistent recipient charges NEW_ACCOUNT
1107+
# state gas under EIP-8037 (0 otherwise).
11051108
tx = typed_transaction.copy(
11061109
to=recipient,
11071110
value=transfer_amount,
1111+
gas_limit=typed_transaction.gas_limit + fork.gas_costs().NEW_ACCOUNT,
11081112
expected_receipt=TransactionReceipt(
11091113
logs=[transfer_log(sender, recipient, transfer_amount)]
11101114
),

tests/amsterdam/eip7843_slotnum/test_slotnum.py

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
Alloc,
77
Environment,
88
Fork,
9+
Header,
910
Op,
1011
StateTestFiller,
1112
Transaction,
@@ -32,6 +33,7 @@
3233
def test_slotnum_value(
3334
state_test: StateTestFiller,
3435
pre: Alloc,
36+
fork: Fork,
3537
slot_number: int,
3638
) -> None:
3739
"""
@@ -40,27 +42,37 @@ def test_slotnum_value(
4042
The slot number is provided by the consensus layer and should be
4143
accessible via the SLOTNUM opcode (0x4B).
4244
"""
43-
# Store SLOTNUM result at storage key 0
44-
code = Op.SSTORE(0, Op.SLOTNUM)
45+
# Store SLOTNUM result at storage key 0. Metadata pins the
46+
# storage transition (0->slot_number) so `code.gas_cost(fork)`
47+
# picks the right SSTORE branch under EIP-8037's 2D gas model.
48+
code = Op.SSTORE(
49+
key=0,
50+
value=Op.SLOTNUM,
51+
key_warm=False,
52+
original_value=0,
53+
new_value=slot_number,
54+
)
4555
code_address = pre.deploy_contract(code)
4656

57+
intrinsic_cost = fork.transaction_intrinsic_cost_calculator()()
58+
code_state = code.state_cost(fork)
59+
code_regular = code.gas_cost(fork) - code_state
60+
4761
tx = Transaction(
4862
sender=pre.fund_eoa(),
49-
gas_limit=100_000,
63+
gas_limit=intrinsic_cost + code_regular + code_state,
5064
to=code_address,
5165
)
5266

53-
post = {
54-
code_address: Account(
55-
storage={0: slot_number},
56-
),
57-
}
67+
# block.gas_used = max(regular_dimension, state_dimension).
68+
expected_gas_used = max(intrinsic_cost + code_regular, code_state)
5869

5970
state_test(
6071
env=Environment(slot_number=slot_number),
6172
pre=pre,
6273
tx=tx,
63-
post=post,
74+
post={code_address: Account(storage={0: slot_number})},
75+
blockchain_test_header_verify=Header(gas_used=expected_gas_used),
6476
)
6577

6678

@@ -88,25 +100,42 @@ def test_slotnum_gas_cost(
88100
callee_code = Op.SLOTNUM + Op.STOP
89101
callee_address = pre.deterministic_deploy_contract(deploy_code=callee_code)
90102

91-
# Caller calls the callee with limited gas and stores result
92-
caller_code = Op.SSTORE(0, Op.CALL(gas=call_gas, address=callee_address))
103+
# Caller calls the callee with `call_gas`; SSTOREs the call's
104+
# success bit (1 if SLOTNUM had enough gas, 0 if it OOG'd).
105+
sstore_value = 1 if call_succeeds else 0
106+
caller_code = Op.SSTORE(
107+
key=0,
108+
value=Op.CALL(
109+
gas=call_gas,
110+
address=callee_address,
111+
address_warm=False,
112+
),
113+
key_warm=False,
114+
original_value=0,
115+
new_value=sstore_value,
116+
)
93117
caller_address = pre.deploy_contract(caller_code)
94118

119+
intrinsic_cost = fork.transaction_intrinsic_cost_calculator()()
120+
code_state = caller_code.state_cost(fork)
121+
# Static opcode-metadata calc misses the gas burned in the inner
122+
# CALL frame; add it back. `call_gas` is the full forwarded amount
123+
# — for `enough_gas` SLOTNUM consumes it all; for `out_of_gas`
124+
# the OOG burns the entire forwarded budget.
125+
code_regular = caller_code.gas_cost(fork) - code_state + call_gas
126+
95127
tx = Transaction(
96128
sender=pre.fund_eoa(),
97-
gas_limit=100_000,
129+
gas_limit=intrinsic_cost + code_regular + code_state,
98130
to=caller_address,
99131
)
100132

101-
post = {
102-
caller_address: Account(
103-
storage={0: 1 if call_succeeds else 0},
104-
),
105-
}
133+
expected_gas_used = max(intrinsic_cost + code_regular, code_state)
106134

107135
state_test(
108136
env=Environment(slot_number=12345),
109137
pre=pre,
110138
tx=tx,
111-
post=post,
139+
post={caller_address: Account(storage={0: sstore_value})},
140+
blockchain_test_header_verify=Header(gas_used=expected_gas_used),
112141
)

0 commit comments

Comments
 (0)