Skip to content

Commit 5e6a38e

Browse files
feat(tests): EIP-7691: Fork transition tests (#1082)
* refactor(tests): EIP-4844, EIP-7691: Fill fork transition blob tests in newer forks * fix(tests): Rebase fixes, add more checks to the test * chengelog * feat(tests): more blob gas tests for fork transitions (#1107) * feat(tests): more edge cases for blob gas at transitions * Apply suggestions from code review --------- Co-authored-by: Mario Vega <[email protected]> * fix(tests): Remove type-2 txs, destination account is empty * tox: typing --------- Co-authored-by: danceratopz <[email protected]>
1 parent b4f9b16 commit 5e6a38e

File tree

2 files changed

+209
-59
lines changed

2 files changed

+209
-59
lines changed

docs/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Release tarball changes:
2828
- 🔀 Update EIP-7251 according to [spec updates](https://github.com/ethereum/EIPs/pull/9127) ([#1024](https://github.com/ethereum/execution-spec-tests/pull/1024)).
2929
- 🔀 Update EIP-7002 according to [spec updates](https://github.com/ethereum/EIPs/pull/9119) ([#1024](https://github.com/ethereum/execution-spec-tests/pull/1024)).
3030
- 🔀 Update EIP-2935 according to [spec updates](https://github.com/ethereum/EIPs/pull/9144) ([#1046](https://github.com/ethereum/execution-spec-tests/pull/1046))
31-
-[EIP-7691](https://eips.ethereum.org/EIPS/eip-7691) Blob throughput increase tests by parametrization of existing EIP-4844 tests ([#1023](https://github.com/ethereum/execution-spec-tests/pull/1023))
31+
-[EIP-7691](https://eips.ethereum.org/EIPS/eip-7691) Blob throughput increase tests by parametrization of existing EIP-4844 tests ([#1023](https://github.com/ethereum/execution-spec-tests/pull/1023), [#1082](https://github.com/ethereum/execution-spec-tests/pull/1082))
3232

3333
### 🛠️ Framework
3434

tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py

Lines changed: 208 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,19 @@
88

99
import pytest
1010

11-
from ethereum_test_forks import Cancun, Fork
11+
from ethereum_test_forks import Fork
1212
from ethereum_test_tools import (
13+
EOA,
1314
Account,
1415
Address,
16+
Alloc,
1517
Block,
1618
BlockchainTestFiller,
1719
BlockException,
1820
EngineAPIError,
1921
Environment,
2022
Hash,
2123
Header,
22-
TestAddress,
2324
Transaction,
2425
add_kzg_version,
2526
)
@@ -29,10 +30,6 @@
2930
REFERENCE_SPEC_GIT_PATH = ref_spec_4844.git_path
3031
REFERENCE_SPEC_VERSION = ref_spec_4844.version
3132

32-
# All tests run on the transition fork from Shanghai to Cancun
33-
pytestmark = pytest.mark.valid_at_transition_to("Cancun")
34-
35-
3633
# Timestamp of the fork
3734
FORK_TIMESTAMP = 15_000
3835

@@ -43,89 +40,171 @@ def env() -> Environment: # noqa: D103
4340

4441

4542
@pytest.fixture
46-
def pre() -> Mapping[Address, Account]: # noqa: D103
47-
return {
48-
TestAddress: Account(balance=10**40),
49-
}
43+
def pre_fork_blobs_per_block(fork: Fork) -> int:
44+
"""Amount of blobs to produce with the pre-fork rules."""
45+
if fork.supports_blobs(timestamp=0):
46+
return fork.max_blobs_per_block(timestamp=0)
47+
return 0
48+
49+
50+
@pytest.fixture
51+
def sender(pre: Alloc) -> EOA:
52+
"""Sender account."""
53+
return pre.fund_eoa()
5054

5155

5256
@pytest.fixture
53-
def pre_fork_blocks():
57+
def pre_fork_blocks(
58+
pre_fork_blobs_per_block: int,
59+
destination_account: Address,
60+
sender: EOA,
61+
) -> List[Block]:
5462
"""Generate blocks to reach the fork."""
55-
return [Block(timestamp=t) for t in range(999, FORK_TIMESTAMP, 1_000)]
63+
return [
64+
Block(
65+
txs=[
66+
Transaction(
67+
ty=Spec.BLOB_TX_TYPE,
68+
to=destination_account,
69+
value=1,
70+
gas_limit=3_000_000,
71+
max_fee_per_gas=1_000_000,
72+
max_priority_fee_per_gas=10,
73+
max_fee_per_blob_gas=100,
74+
access_list=[],
75+
blob_versioned_hashes=add_kzg_version(
76+
[Hash(x) for x in range(pre_fork_blobs_per_block)],
77+
Spec.BLOB_COMMITMENT_VERSION_KZG,
78+
),
79+
sender=sender,
80+
)
81+
]
82+
if pre_fork_blobs_per_block > 0
83+
else [],
84+
timestamp=t,
85+
)
86+
for t in range(999, FORK_TIMESTAMP, 1_000)
87+
]
88+
89+
90+
@pytest.fixture
91+
def pre_fork_excess_blobs(
92+
fork: Fork,
93+
pre_fork_blobs_per_block: int,
94+
pre_fork_blocks: List[Block],
95+
) -> int:
96+
"""
97+
Return the cummulative excess blobs up until the fork given the pre_fork_blobs_per_block
98+
and the target blobs in the fork prior.
99+
"""
100+
if not fork.supports_blobs(timestamp=0):
101+
return 0
102+
target_blobs = fork.target_blobs_per_block(timestamp=0)
103+
if pre_fork_blobs_per_block > target_blobs:
104+
return (pre_fork_blobs_per_block - target_blobs) * (len(pre_fork_blocks) - 1)
105+
return 0
56106

57107

58108
@pytest.fixture
59109
def post_fork_block_count(fork: Fork) -> int:
60110
"""Amount of blocks to produce with the post-fork rules."""
61111
return SpecHelpers.get_min_excess_blobs_for_blob_gas_price(fork=fork, blob_gas_price=2) // (
62-
fork.max_blobs_per_block() - fork.target_blobs_per_block()
112+
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP)
113+
- fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP)
63114
)
64115

65116

66117
@pytest.fixture
67-
def blob_count_per_block() -> int:
118+
def post_fork_blobs_per_block(fork: Fork) -> int:
68119
"""Amount of blocks to produce with the post-fork rules."""
69-
return 4
120+
return fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP) + 1
70121

71122

72123
@pytest.fixture
73-
def destination_account() -> Address: # noqa: D103
74-
return Address(0x100)
124+
def destination_account(pre: Alloc) -> Address: # noqa: D103
125+
# Empty account to receive the blobs
126+
return pre.fund_eoa(amount=0)
127+
128+
129+
@pytest.fixture
130+
def fork_block_excess_blob_gas(
131+
fork: Fork,
132+
pre_fork_excess_blobs: int,
133+
pre_fork_blobs_per_block: int,
134+
) -> int:
135+
"""Calculate the expected excess blob gas for the fork block."""
136+
if pre_fork_blobs_per_block == 0:
137+
return 0
138+
calc_excess_blob_gas_post_fork = fork.excess_blob_gas_calculator(timestamp=FORK_TIMESTAMP)
139+
return calc_excess_blob_gas_post_fork(
140+
parent_excess_blobs=pre_fork_excess_blobs,
141+
parent_blob_count=pre_fork_blobs_per_block,
142+
)
75143

76144

77145
@pytest.fixture
78146
def post_fork_blocks(
79147
destination_account: Address,
80148
post_fork_block_count: int,
81-
blob_count_per_block: int,
149+
post_fork_blobs_per_block: int,
150+
fork_block_excess_blob_gas: int,
151+
sender: EOA,
82152
):
83153
"""Generate blocks past the fork."""
84-
return [
85-
Block(
86-
txs=[
154+
blocks = []
155+
for i in range(post_fork_block_count):
156+
txs = (
157+
[
87158
Transaction(
88159
ty=Spec.BLOB_TX_TYPE,
89-
nonce=b,
90160
to=destination_account,
91161
value=1,
92-
gas_limit=3000000,
93-
max_fee_per_gas=1000000,
162+
gas_limit=3_000_000,
163+
max_fee_per_gas=1_000_000,
94164
max_priority_fee_per_gas=10,
95165
max_fee_per_blob_gas=100,
96-
access_list=[],
97166
blob_versioned_hashes=add_kzg_version(
98-
[Hash(x) for x in range(blob_count_per_block)],
167+
[Hash(x) for x in range(post_fork_blobs_per_block)],
99168
Spec.BLOB_COMMITMENT_VERSION_KZG,
100169
),
170+
sender=sender,
101171
)
102-
if blob_count_per_block > 0
103-
else Transaction(
104-
ty=2,
105-
nonce=b,
106-
to=destination_account,
107-
value=1,
108-
gas_limit=3000000,
109-
max_fee_per_gas=1000000,
110-
max_priority_fee_per_gas=10,
111-
access_list=[],
112-
)
113-
],
172+
]
173+
if post_fork_blobs_per_block > 0
174+
else []
114175
)
115-
for b in range(post_fork_block_count)
116-
]
176+
if i == 0:
177+
# Check the excess blob gas on the first block of the new fork
178+
blocks.append(
179+
Block(
180+
txs=txs,
181+
excess_blob_gas=fork_block_excess_blob_gas,
182+
)
183+
)
184+
else:
185+
blocks.append(Block(txs=txs))
186+
return blocks
117187

118188

119189
@pytest.fixture
120190
def post( # noqa: D103
191+
pre_fork_blocks: List[Block],
192+
pre_fork_blobs_per_block: int,
121193
post_fork_block_count: int,
194+
post_fork_blobs_per_block: int,
122195
destination_account: Address,
123196
) -> Mapping[Address, Account]:
197+
pre_fork_value = len(pre_fork_blocks) if pre_fork_blobs_per_block > 0 else 0
198+
post_fork_value = post_fork_block_count if post_fork_blobs_per_block > 0 else 0
199+
total_value = pre_fork_value + post_fork_value
200+
if total_value == 0:
201+
return {}
124202
return {
125-
destination_account: Account(balance=post_fork_block_count),
203+
destination_account: Account(balance=total_value),
126204
}
127205

128206

207+
@pytest.mark.valid_at_transition_to("Cancun")
129208
@pytest.mark.parametrize(
130209
"excess_blob_gas_present,blob_gas_used_present",
131210
[
@@ -137,7 +216,7 @@ def post( # noqa: D103
137216
def test_invalid_pre_fork_block_with_blob_fields(
138217
blockchain_test: BlockchainTestFiller,
139218
env: Environment,
140-
pre: Mapping[Address, Account],
219+
pre: Alloc,
141220
pre_fork_blocks: List[Block],
142221
excess_blob_gas_present: bool,
143222
blob_gas_used_present: bool,
@@ -166,10 +245,10 @@ def test_invalid_pre_fork_block_with_blob_fields(
166245
)
167246
],
168247
genesis_environment=env,
169-
tag="invalid_pre_fork_blob_fields",
170248
)
171249

172250

251+
@pytest.mark.valid_at_transition_to("Cancun")
173252
@pytest.mark.parametrize(
174253
"excess_blob_gas_missing,blob_gas_used_missing",
175254
[
@@ -181,7 +260,7 @@ def test_invalid_pre_fork_block_with_blob_fields(
181260
def test_invalid_post_fork_block_without_blob_fields(
182261
blockchain_test: BlockchainTestFiller,
183262
env: Environment,
184-
pre: Mapping[Address, Account],
263+
pre: Alloc,
185264
pre_fork_blocks: List[Block],
186265
excess_blob_gas_missing: bool,
187266
blob_gas_used_missing: bool,
@@ -211,28 +290,100 @@ def test_invalid_post_fork_block_without_blob_fields(
211290
)
212291
],
213292
genesis_environment=env,
214-
tag="blob_fields_missing_post_fork",
215293
)
216294

217295

218-
@pytest.mark.parametrize(
219-
"post_fork_block_count,blob_count_per_block",
220-
[
221-
(
222-
SpecHelpers.get_min_excess_blobs_for_blob_gas_price(fork=Cancun, blob_gas_price=2)
223-
// (Cancun.max_blobs_per_block() - Cancun.target_blobs_per_block())
296+
@pytest.mark.valid_at_transition_to("Cancun", subsequent_forks=False)
297+
@pytest.mark.parametrize_by_fork(
298+
"post_fork_block_count,post_fork_blobs_per_block",
299+
lambda fork: [
300+
pytest.param(
301+
SpecHelpers.get_min_excess_blobs_for_blob_gas_price(fork=fork, blob_gas_price=2)
302+
// (
303+
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP)
304+
- fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP)
305+
)
306+
+ 2,
307+
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP),
308+
id="max_blobs",
309+
),
310+
pytest.param(10, 0, id="no_blobs"),
311+
pytest.param(10, fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP), id="target_blobs"),
312+
],
313+
)
314+
def test_fork_transition_excess_blob_gas_at_blob_genesis(
315+
blockchain_test: BlockchainTestFiller,
316+
env: Environment,
317+
pre: Alloc,
318+
pre_fork_blocks: List[Block],
319+
post_fork_blocks: List[Block],
320+
post: Mapping[Address, Account],
321+
):
322+
"""
323+
Test `excessBlobGas` calculation in the header when the fork is activated.
324+
325+
Also produce enough blocks to test the blob gas price increase when the block is full with
326+
`SpecHelpers.max_blobs_per_block()` blobs.
327+
"""
328+
blockchain_test(
329+
pre=pre,
330+
post=post,
331+
blocks=pre_fork_blocks + post_fork_blocks,
332+
genesis_environment=env,
333+
)
334+
335+
336+
@pytest.mark.valid_at_transition_to("Prague", subsequent_forks=True)
337+
@pytest.mark.parametrize_by_fork(
338+
"post_fork_block_count,pre_fork_blobs_per_block,post_fork_blobs_per_block",
339+
lambda fork: [
340+
pytest.param(
341+
SpecHelpers.get_min_excess_blobs_for_blob_gas_price(fork=fork, blob_gas_price=2)
342+
// (
343+
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP)
344+
- fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP)
345+
)
224346
+ 2,
225-
Cancun.max_blobs_per_block(),
347+
fork.max_blobs_per_block(timestamp=0),
348+
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP),
349+
id="max_blobs",
350+
),
351+
pytest.param(
352+
10,
353+
0,
354+
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP),
355+
id="no_blobs_before",
356+
),
357+
pytest.param(
358+
10,
359+
fork.max_blobs_per_block(timestamp=0),
360+
0,
361+
id="no_blobs_after",
362+
),
363+
pytest.param(
364+
10,
365+
fork.target_blobs_per_block(timestamp=0),
366+
fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP),
367+
id="target_blobs",
368+
),
369+
pytest.param(
370+
10,
371+
1,
372+
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP),
373+
id="single_blob_to_max_blobs",
374+
),
375+
pytest.param(
376+
10,
377+
fork.max_blobs_per_block(timestamp=0),
378+
1,
379+
id="max_blobs_to_single_blob",
226380
),
227-
(10, 0),
228-
(10, Cancun.target_blobs_per_block()),
229381
],
230-
ids=["max_blobs", "no_blobs", "target_blobs"],
231382
)
232-
def test_fork_transition_excess_blob_gas(
383+
def test_fork_transition_excess_blob_gas_post_blob_genesis(
233384
blockchain_test: BlockchainTestFiller,
234385
env: Environment,
235-
pre: Mapping[Address, Account],
386+
pre: Alloc,
236387
pre_fork_blocks: List[Block],
237388
post_fork_blocks: List[Block],
238389
post: Mapping[Address, Account],
@@ -248,5 +399,4 @@ def test_fork_transition_excess_blob_gas(
248399
post=post,
249400
blocks=pre_fork_blocks + post_fork_blocks,
250401
genesis_environment=env,
251-
tag="correct_initial_blob_gas_calc",
252402
)

0 commit comments

Comments
 (0)