Skip to content

Commit d91fb50

Browse files
committed
feat(fw,tests): framework changes for eip7742.
1 parent e546b9c commit d91fb50

File tree

8 files changed

+103
-45
lines changed

8 files changed

+103
-45
lines changed

src/ethereum_test_fixtures/blockchain.py

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ class FixtureHeader(CamelModel):
111111
None
112112
)
113113
requests_hash: Annotated[Hash, HeaderForkRequirement("requests")] | None = Field(None)
114+
target_blob_count: Annotated[
115+
ZeroPaddedHexNumber, HeaderForkRequirement("target_blob_count")
116+
] | None = Field(None)
114117

115118
fork: Fork | None = Field(None, exclude=True)
116119

@@ -199,6 +202,8 @@ class FixtureExecutionPayload(CamelModel):
199202
blob_gas_used: HexNumber | None = Field(None)
200203
excess_blob_gas: HexNumber | None = Field(None)
201204

205+
target_blob_count: HexNumber | None = Field(None)
206+
202207
block_hash: Hash
203208

204209
transactions: List[Bytes]
@@ -224,7 +229,7 @@ def from_fixture_header(
224229

225230
EngineNewPayloadV1Parameters = Tuple[FixtureExecutionPayload]
226231
EngineNewPayloadV3Parameters = Tuple[FixtureExecutionPayload, List[Hash], Hash]
227-
EngineNewPayloadV4Parameters = Tuple[FixtureExecutionPayload, List[Hash], Hash, List[Bytes]]
232+
EngineNewPayloadV4Parameters = Tuple[FixtureExecutionPayload, List[Hash], Hash, List[Bytes], HexNumber]
228233

229234
# Important: We check EngineNewPayloadV3Parameters first as it has more fields, and pydantic
230235
# has a weird behavior when the smaller tuple is checked first.
@@ -286,32 +291,34 @@ def from_fixture_header(
286291
transactions=transactions,
287292
withdrawals=withdrawals,
288293
)
289-
params: EngineNewPayloadParameters
290-
if (
291-
fork.engine_new_payload_requests(header.number, header.timestamp)
292-
and requests is not None
293-
):
294-
parent_beacon_block_root = header.parent_beacon_block_root
295-
assert parent_beacon_block_root is not None
296-
params = (
297-
execution_payload,
298-
Transaction.list_blob_versioned_hashes(transactions),
299-
parent_beacon_block_root,
300-
requests,
301-
)
302-
elif fork.engine_new_payload_blob_hashes(header.number, header.timestamp):
303-
parent_beacon_block_root = header.parent_beacon_block_root
304-
assert parent_beacon_block_root is not None
305-
params = (
306-
execution_payload,
307-
Transaction.list_blob_versioned_hashes(transactions),
308-
parent_beacon_block_root,
309-
)
310-
else:
311-
params = (execution_payload,)
312294

295+
params: List[Any] = [execution_payload]
296+
if fork.engine_new_payload_blob_hashes(header.number, header.timestamp):
297+
blob_hashes = Transaction.list_blob_versioned_hashes(transactions)
298+
if blob_hashes is None:
299+
raise ValueError(f"Blob hashes are required for ${fork}.")
300+
params.append(blob_hashes)
301+
302+
if fork.engine_new_payload_beacon_root(header.number, header.timestamp):
303+
parent_beacon_block_root = header.parent_beacon_block_root
304+
if parent_beacon_block_root is None:
305+
raise ValueError(f"Parent beacon block root is required for ${fork}.")
306+
params.append(parent_beacon_block_root)
307+
308+
if fork.engine_new_payload_requests(header.number, header.timestamp):
309+
if requests is None:
310+
raise ValueError(f"Requests are required for ${fork}.")
311+
params.append(requests)
312+
313+
if fork.engine_new_payload_target_blob_count(header.number, header.timestamp):
314+
target_blob_count = header.target_blob_count
315+
if target_blob_count is None:
316+
raise ValueError(f"Target blob count is required for ${fork}.")
317+
params.append(target_blob_count)
318+
319+
payload_params: EngineNewPayloadParameters = tuple(params)
313320
new_payload = cls(
314-
params=params,
321+
params=payload_params,
315322
new_payload_version=new_payload_version,
316323
forkchoice_updated_version=forkchoice_updated_version,
317324
**kwargs,

src/ethereum_test_fixtures/tests/test_blockchain.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,7 @@
668668
excess_blob_gas=18,
669669
parent_beacon_block_root=19,
670670
requests_hash=20,
671+
target_blob_count=10,
671672
),
672673
transactions=[
673674
Transaction(
@@ -790,7 +791,7 @@
790791
).requests_list
791792
],
792793
],
793-
"forkchoiceUpdatedVersion": "3",
794+
"forkchoiceUpdatedVersion": "4",
794795
"newPayloadVersion": "4",
795796
"validationError": "BlockException.INCORRECT_BLOCK_FORMAT"
796797
"|TransactionException.INTRINSIC_GAS_TOO_LOW",
@@ -947,7 +948,7 @@
947948
],
948949
],
949950
"newPayloadVersion": "4",
950-
"forkchoiceUpdatedVersion": "3",
951+
"forkchoiceUpdatedVersion": "4",
951952
"validationError": "BlockException.INCORRECT_BLOCK_FORMAT"
952953
"|TransactionException.INTRINSIC_GAS_TOO_LOW",
953954
},
@@ -1191,6 +1192,7 @@ def test_json_deserialization(
11911192
withdrawals_root=Hash(16),
11921193
blob_gas_used=17,
11931194
excess_blob_gas=18,
1195+
target_blob_count=10,
11941196
),
11951197
transactions=[
11961198
Transaction(
@@ -1249,6 +1251,7 @@ def test_json_deserialization(
12491251
"baseFeePerGas": hex(15),
12501252
"blobGasUsed": hex(17),
12511253
"excessBlobGas": hex(18),
1254+
"targetBlobCount": hex(10),
12521255
"blockHash": "0xd90115b7fde329f64335763a446af1"
12531256
"50ab67e639281dccdb07a007d18bb80211",
12541257
"transactions": [

src/ethereum_test_forks/base_fork.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,14 @@ def transaction_intrinsic_cost_calculator(
246246
"""
247247
pass
248248

249+
@classmethod
250+
@abstractmethod
251+
def header_target_blob_count_required(cls, block_number: int, timestamp: int) -> bool:
252+
"""
253+
Returns true if the header must contain target blob count
254+
"""
255+
pass
256+
249257
@classmethod
250258
@abstractmethod
251259
def blob_gas_per_blob(cls, block_number: int, timestamp: int) -> int:
@@ -254,6 +262,14 @@ def blob_gas_per_blob(cls, block_number: int, timestamp: int) -> int:
254262
"""
255263
pass
256264

265+
@classmethod
266+
@abstractmethod
267+
def target_blob_count(cls, block_number: int, timestamp: int) -> int:
268+
"""
269+
Returns the target blobs per block for a given fork.
270+
"""
271+
pass
272+
257273
@classmethod
258274
@abstractmethod
259275
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
@@ -353,7 +369,15 @@ def engine_new_payload_beacon_root(cls, block_number: int = 0, timestamp: int =
353369
@abstractmethod
354370
def engine_new_payload_requests(cls, block_number: int = 0, timestamp: int = 0) -> bool:
355371
"""
356-
Returns true if the engine api version requires new payload calls to include requests.
372+
returns true if the engine api version requires new payload calls to include requests.
373+
"""
374+
pass
375+
376+
@classmethod
377+
@abstractmethod
378+
def engine_new_payload_target_blob_count(cls, block_number: int = 0, timestamp: int = 0) -> bool:
379+
"""
380+
returns true if the engine api version requires new payload calls to include target blob count.
357381
"""
358382
pass
359383

src/ethereum_test_forks/forks/forks.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -938,9 +938,16 @@ def header_beacon_root_required(cls, block_number: int = 0, timestamp: int = 0)
938938
@classmethod
939939
def blob_gas_per_blob(cls, block_number: int, timestamp: int) -> int:
940940
"""
941-
Blobs are enabled started from Cancun.
941+
Blobs are enabled starting from Cancun.
942942
"""
943943
return 2**17
944+
945+
@classmethod
946+
def target_blob_count(cls, block_number: int, timestamp: int) -> int:
947+
"""
948+
Blobs are enabled starting from Cancun, with a static target of 3 blobs.
949+
"""
950+
return 3
944951

945952
@classmethod
946953
def tx_types(cls, block_number: int = 0, timestamp: int = 0) -> List[int]:
@@ -1176,6 +1183,14 @@ def header_requests_required(cls, block_number: int, timestamp: int) -> bool:
11761183
"""
11771184
return True
11781185

1186+
@classmethod
1187+
def header_target_blob_count_required(cls, block_number: int = 0, timestamp: int = 0) -> bool:
1188+
"""
1189+
Prague requires that the execution layer header contains the beacon
1190+
chain target blob count.
1191+
"""
1192+
return True
1193+
11791194
@classmethod
11801195
def engine_new_payload_requests(cls, block_number: int = 0, timestamp: int = 0) -> bool:
11811196
"""
@@ -1184,9 +1199,9 @@ def engine_new_payload_requests(cls, block_number: int = 0, timestamp: int = 0)
11841199
return True
11851200

11861201
@classmethod
1187-
def engine_new_payload_blob_hashes(cls, block_number: int = 0, timestamp: int = 0) -> bool:
1202+
def engine_new_payload_target_blob_count(cls, block_number: int = 0, timestamp: int = 0) -> bool:
11881203
"""
1189-
Starting at Prague, new payload directives must contain requests as parameter.
1204+
Starting at Prague, new payloads include the target blob count as a parameter.
11901205
"""
11911206
return True
11921207

@@ -1199,16 +1214,6 @@ def engine_new_payload_version(
11991214
"""
12001215
return 4
12011216

1202-
@classmethod
1203-
def engine_forkchoice_updated_version(
1204-
cls, block_number: int = 0, timestamp: int = 0
1205-
) -> Optional[int]:
1206-
"""
1207-
At Prague, version number of NewPayload and ForkchoiceUpdated diverge.
1208-
"""
1209-
return 3
1210-
1211-
12121217
class CancunEIP7692( # noqa: SC200
12131218
Cancun,
12141219
transition_tool_name="Prague", # Evmone enables (only) EOF at Prague

src/ethereum_test_specs/blockchain.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class Header(CamelModel):
119119
excess_blob_gas: Removable | HexNumber | None = None
120120
parent_beacon_block_root: Removable | Hash | None = None
121121
requests_hash: Removable | Hash | None = None
122+
target_blob_count: Removable | HexNumber | None = None
122123

123124
REMOVE_FIELD: ClassVar[Removable] = Removable()
124125
"""
@@ -353,12 +354,17 @@ def make_genesis(
353354
blob_gas_used=env.blob_gas_used,
354355
excess_blob_gas=env.excess_blob_gas,
355356
withdrawals_root=(
356-
Withdrawal.list_root(env.withdrawals) if env.withdrawals is not None else None
357+
Withdrawal.list_root(env.withdrawals)
358+
if env.withdrawals is not None
359+
else None
357360
),
358361
parent_beacon_block_root=env.parent_beacon_block_root,
359362
requests_hash=Requests(max_request_type=fork.max_request_type(0, 0))
360363
if fork.header_requests_required(0, 0)
361364
else None,
365+
target_blob_count=fork.target_blob_count(0, 0)
366+
if fork.header_target_blob_count_required(0, 0)
367+
else None,
362368
fork=fork,
363369
)
364370

src/ethereum_test_types/types.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ class EnvironmentGeneric(CamelModel, Generic[NumberBoundTypeVar]):
389389
difficulty: NumberBoundTypeVar | None = Field(None, alias="currentDifficulty")
390390
base_fee_per_gas: NumberBoundTypeVar | None = Field(None, alias="currentBaseFee")
391391
excess_blob_gas: NumberBoundTypeVar | None = Field(None, alias="currentExcessBlobGas")
392+
target_blob_count: NumberBoundTypeVar | None = Field(None, alias="currentTargetBlobCount")
392393

393394
parent_difficulty: NumberBoundTypeVar | None = Field(None)
394395
parent_timestamp: NumberBoundTypeVar | None = Field(None)
@@ -474,6 +475,9 @@ def set_fork_requirements(self, fork: Fork) -> "Environment":
474475
):
475476
updated_values["parent_beacon_block_root"] = 0
476477

478+
if fork.header_target_blob_count_required(number, timestamp) and self.target_blob_count is None:
479+
updated_values["target_blob_count"] = fork.target_blob_count(number, timestamp)
480+
477481
return self.copy(**updated_values)
478482

479483

src/pytest_plugins/execute/rpc/hive.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,16 @@ def base_pre_genesis(
260260
timestamp=timestamp,
261261
),
262262
)
263-
if base_fork.header_requests_required(block_number=block_number, timestamp=timestamp)
263+
if base_fork.header_requests_required(
264+
block_number=block_number, timestamp=timestamp
265+
)
266+
else None,
267+
target_blob_count=base_fork.target_blob_count(
268+
block_number=block_number, timestamp=timestamp
269+
)
270+
if base_fork.header_target_blob_count_required(
271+
block_number=block_number, timestamp=timestamp
272+
)
264273
else None,
265274
)
266275

tests/cancun/eip4844_blobs/test_blob_txs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ def test_invalid_normal_gas(
738738
@pytest.mark.parametrize(
739739
"tx_error", [TransactionException.TYPE_3_TX_MAX_BLOB_GAS_ALLOWANCE_EXCEEDED], ids=[""]
740740
)
741-
@pytest.mark.valid_from("Cancun")
741+
@pytest.mark.valid_until("Cancun")
742742
def test_invalid_block_blob_count(
743743
blockchain_test: BlockchainTestFiller,
744744
pre: Alloc,
@@ -1008,7 +1008,7 @@ def test_insufficient_balance_blob_tx_combinations(
10081008
],
10091009
ids=["too_few_blobs", "too_many_blobs"],
10101010
)
1011-
@pytest.mark.valid_from("Cancun")
1011+
@pytest.mark.valid_until("Cancun")
10121012
def test_invalid_tx_blob_count(
10131013
state_test: StateTestFiller,
10141014
state_env: Environment,

0 commit comments

Comments
 (0)