Skip to content

Commit 1dd0e4c

Browse files
--globalspencer-tb
authored andcommitted
improvement: Add Engine API forkchoice updated field to fixtures for hive.
1 parent 3fec884 commit 1dd0e4c

File tree

6 files changed

+197
-5
lines changed

6 files changed

+197
-5
lines changed

src/ethereum_test_forks/base_fork.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,19 +161,40 @@ def engine_new_payload_version(
161161
@abstractmethod
162162
def engine_new_payload_blob_hashes(cls, block_number: int = 0, timestamp: int = 0) -> bool:
163163
"""
164-
Returns true if the engine api version requires new payload calls to include blob hashes.
164+
Returns true if the engine new payload version requires new calls to include blob hashes.
165165
"""
166166
pass
167167

168168
@classmethod
169169
@abstractmethod
170170
def engine_new_payload_beacon_root(cls, block_number: int = 0, timestamp: int = 0) -> bool:
171171
"""
172-
Returns true if the engine api version requires new payload calls to include a parent
172+
Returns true if the engine new payload version requires new calls to include a parent
173173
beacon block root.
174174
"""
175175
pass
176176

177+
@classmethod
178+
@abstractmethod
179+
def engine_forkchoice_updated_version(
180+
cls, block_number: int = 0, timestamp: int = 0
181+
) -> Optional[int]:
182+
"""
183+
Returns `None` if this fork's canonical chain cannot be set using the forkchoice method.
184+
"""
185+
pass
186+
187+
@classmethod
188+
@abstractmethod
189+
def engine_forkchoice_updated_beacon_root(
190+
cls, block_number: int = 0, timestamp: int = 0
191+
) -> bool:
192+
"""
193+
Returns true if the engine forkchoice updated version requires new calls to include a
194+
parent beacon block root.
195+
"""
196+
pass
197+
177198
# Meta information about the fork
178199
@classmethod
179200
def name(cls) -> str:

src/ethereum_test_forks/forks/forks.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,16 @@ def engine_new_payload_version(
284284
cls, block_number: int = 0, timestamp: int = 0
285285
) -> Optional[int]:
286286
"""
287-
Starting at the merge, payloads can be sent through the engine API
287+
Starting at the merge, payloads can be sent through the engine API.
288+
"""
289+
return 1
290+
291+
@classmethod
292+
def engine_forkchoice_updated_version(
293+
cls, block_number: int = 0, timestamp: int = 0
294+
) -> Optional[int]:
295+
"""
296+
Starting at the merge, forkchoice update determines the canonical chain
288297
"""
289298
return 1
290299

@@ -306,7 +315,16 @@ def engine_new_payload_version(
306315
cls, block_number: int = 0, timestamp: int = 0
307316
) -> Optional[int]:
308317
"""
309-
Starting at Shanghai, new payload calls must use version 2
318+
Starting at Shanghai, new payload calls must use version 2.
319+
"""
320+
return 2
321+
322+
@classmethod
323+
def engine_forkchoice_updated_version(
324+
cls, block_number: int = 0, timestamp: int = 0
325+
) -> Optional[int]:
326+
"""
327+
Starting at Shanghai, forkchoice updated calls must use version 2.
310328
"""
311329
return 2
312330

@@ -379,7 +397,7 @@ def engine_new_payload_version(
379397
cls, block_number: int = 0, timestamp: int = 0
380398
) -> Optional[int]:
381399
"""
382-
Starting at Cancun, new payload calls must use version 3
400+
Starting at Cancun, new payload calls must use version 3.
383401
"""
384402
return 3
385403

@@ -396,3 +414,21 @@ def engine_new_payload_beacon_root(cls, block_number: int = 0, timestamp: int =
396414
Starting at Cancun, payloads must have a parent beacon block root.
397415
"""
398416
return True
417+
418+
@classmethod
419+
def engine_forkchoice_updated_version(
420+
cls, block_number: int = 0, timestamp: int = 0
421+
) -> Optional[int]:
422+
"""
423+
Starting at Cancun, forkchoice updated calls must use version 3.
424+
"""
425+
return 3
426+
427+
@classmethod
428+
def engine_forkchoice_updated_beacon_root(
429+
cls, block_number: int = 0, timestamp: int = 0
430+
) -> bool:
431+
"""
432+
Starting at Cancun, forkchoice update calls must have a parent beacon block root.
433+
"""
434+
return True

src/ethereum_test_tools/common/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
Environment,
3838
Fixture,
3939
FixtureBlock,
40+
FixtureEngineForkchoiceUpdated,
4041
FixtureEngineNewPayload,
4142
FixtureHeader,
4243
Hash,
@@ -73,6 +74,7 @@
7374
"Environment",
7475
"Fixture",
7576
"FixtureBlock",
77+
"FixtureEngineForkchoiceUpdated",
7678
"FixtureEngineNewPayload",
7779
"FixtureHeader",
7880
"Hash",

src/ethereum_test_tools/common/types.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2400,6 +2400,113 @@ def copy_with_rlp(self, rlp: Bytes | BytesConvertible | None) -> "Block":
24002400
return new_block
24012401

24022402

2403+
@dataclass(kw_only=True)
2404+
class FixtureEnginePayloadAttributes:
2405+
"""
2406+
Representation of the engine api payload attributes from a block within a test fixture.
2407+
"""
2408+
2409+
mix_digest: Hash = field(
2410+
json_encoder=JSONEncoder.Field(
2411+
name="prevRandao",
2412+
),
2413+
)
2414+
2415+
coinbase: Address = field(
2416+
json_encoder=JSONEncoder.Field(
2417+
name="feeRecipient",
2418+
)
2419+
)
2420+
2421+
timestamp: int = field(
2422+
json_encoder=JSONEncoder.Field(
2423+
cast_type=HexNumber,
2424+
)
2425+
)
2426+
2427+
withdrawals: Optional[List[Withdrawal]] = field(
2428+
default=None,
2429+
json_encoder=JSONEncoder.Field(
2430+
to_json=True,
2431+
),
2432+
)
2433+
2434+
beacon_root: Optional[Hash] = field(
2435+
default=None,
2436+
json_encoder=JSONEncoder.Field(
2437+
name="parentBeaconBlockRoot",
2438+
),
2439+
)
2440+
2441+
@classmethod
2442+
def from_fixture_header(
2443+
cls,
2444+
fork,
2445+
header: FixtureHeader,
2446+
withdrawals: Optional[List[Withdrawal]] = None,
2447+
) -> "FixtureEnginePayloadAttributes":
2448+
"""
2449+
Returns `FixtureEnginePayloadAttributes` from a `FixtureHeader` and a list of withdrawals.
2450+
"""
2451+
return cls(
2452+
mix_digest=header.mix_digest,
2453+
coinbase=header.coinbase,
2454+
timestamp=header.timestamp,
2455+
withdrawals=withdrawals,
2456+
beacon_root=header.beacon_root
2457+
if fork.engine_forkchoice_updated_beacon_root(header.number, header.timestamp)
2458+
else None,
2459+
)
2460+
2461+
2462+
@dataclass(kw_only=True)
2463+
class FixtureEngineForkchoiceUpdated:
2464+
"""
2465+
Representation of the `engine_forkchoiceUpdatedVX` information to be
2466+
sent using the block information.
2467+
"""
2468+
2469+
payload_attributes: FixtureEnginePayloadAttributes = field(
2470+
json_encoder=JSONEncoder.Field(
2471+
name="payloadAttributes",
2472+
to_json=True,
2473+
)
2474+
)
2475+
2476+
version: int = field(
2477+
json_encoder=JSONEncoder.Field(),
2478+
)
2479+
2480+
@classmethod
2481+
def from_fixture_header(
2482+
cls,
2483+
fork: Fork,
2484+
header: FixtureHeader,
2485+
withdrawals: Optional[List[Withdrawal]],
2486+
) -> Optional["FixtureEngineForkchoiceUpdated"]:
2487+
"""
2488+
Creates `FixtureEngineForkchoiceUpdated` from a `FixtureHeader`.
2489+
"""
2490+
forkchoice_updated_version = fork.engine_forkchoice_updated_version(
2491+
header.number,
2492+
header.timestamp,
2493+
)
2494+
2495+
if forkchoice_updated_version is None:
2496+
return None
2497+
2498+
forkchoice_updated = cls(
2499+
payload_attributes=FixtureEnginePayloadAttributes.from_fixture_header(
2500+
fork=fork,
2501+
header=header,
2502+
withdrawals=withdrawals,
2503+
),
2504+
version=forkchoice_updated_version,
2505+
)
2506+
2507+
return forkchoice_updated
2508+
2509+
24032510
@dataclass(kw_only=True)
24042511
class FixtureExecutionPayload(FixtureHeader):
24052512
"""
@@ -2608,6 +2715,13 @@ class FixtureBlock:
26082715
to_json=True,
26092716
),
26102717
)
2718+
forkchoice_updated: Optional[FixtureEngineForkchoiceUpdated] = field(
2719+
default=None,
2720+
json_encoder=JSONEncoder.Field(
2721+
name="forkchoiceUpdated",
2722+
to_json=True,
2723+
),
2724+
)
26112725
new_payload: Optional[FixtureEngineNewPayload] = field(
26122726
default=None,
26132727
json_encoder=JSONEncoder.Field(

src/ethereum_test_tools/spec/blockchain_test.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
EmptyTrieRoot,
1919
Environment,
2020
FixtureBlock,
21+
FixtureEngineForkchoiceUpdated,
2122
FixtureEngineNewPayload,
2223
FixtureHeader,
2324
Hash,
@@ -207,8 +208,15 @@ def make_block(
207208
withdrawals=env.withdrawals,
208209
)
209210

211+
forkchoice_updated: FixtureEngineForkchoiceUpdated | None = None
210212
new_payload: FixtureEngineNewPayload | None = None
211213
if not self.base_test_config.disable_hive:
214+
forkchoice_updated = FixtureEngineForkchoiceUpdated.from_fixture_header(
215+
fork=fork,
216+
header=header,
217+
withdrawals=env.withdrawals,
218+
)
219+
212220
new_payload = FixtureEngineNewPayload.from_fixture_header(
213221
fork=fork,
214222
header=header,
@@ -222,6 +230,7 @@ def make_block(
222230
return (
223231
FixtureBlock(
224232
rlp=rlp,
233+
forkchoice_updated=forkchoice_updated,
225234
new_payload=new_payload,
226235
block_header=header,
227236
block_number=Number(header.number),
@@ -237,6 +246,7 @@ def make_block(
237246
return (
238247
FixtureBlock(
239248
rlp=rlp,
249+
forkchoice_updated=forkchoice_updated,
240250
new_payload=new_payload,
241251
expected_exception=block.exception,
242252
block_number=Number(header.number),

src/ethereum_test_tools/spec/state_test.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
EmptyTrieRoot,
1717
Environment,
1818
FixtureBlock,
19+
FixtureEngineForkchoiceUpdated,
1920
FixtureEngineNewPayload,
2021
FixtureHeader,
2122
Hash,
@@ -178,8 +179,15 @@ def make_blocks(
178179
withdrawals=env.withdrawals,
179180
)
180181

182+
forkchoice_updated: FixtureEngineForkchoiceUpdated | None = None
181183
new_payload: FixtureEngineNewPayload | None = None
182184
if not self.base_test_config.disable_hive:
185+
forkchoice_updated = FixtureEngineForkchoiceUpdated.from_fixture_header(
186+
fork=fork,
187+
header=header,
188+
withdrawals=env.withdrawals,
189+
)
190+
183191
new_payload = FixtureEngineNewPayload.from_fixture_header(
184192
fork=fork,
185193
header=header,
@@ -192,6 +200,7 @@ def make_blocks(
192200
[
193201
FixtureBlock(
194202
rlp=block,
203+
forkchoice_updated=forkchoice_updated,
195204
new_payload=new_payload,
196205
block_header=header,
197206
txs=txs,

0 commit comments

Comments
 (0)