Skip to content

Commit 80c7410

Browse files
committed
fix(fw): Requests spec update
1 parent dba9a5c commit 80c7410

File tree

4 files changed

+54
-56
lines changed

4 files changed

+54
-56
lines changed

src/ethereum_test_specs/blockchain.py

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -160,16 +160,6 @@ def validate_withdrawals_root(cls, value):
160160
return Withdrawal.list_root(value)
161161
return value
162162

163-
@field_validator("requests_hash", mode="before")
164-
@classmethod
165-
def validate_requests_hash(cls, value):
166-
"""
167-
Helper validator to convert a list of requests into the requests hash.
168-
"""
169-
if isinstance(value, list):
170-
return Requests(root=value).hash
171-
return value
172-
173163
def apply(self, target: FixtureHeader) -> FixtureHeader:
174164
"""
175165
Produces a fixture header copy with the set values from the modifier.
@@ -361,7 +351,9 @@ def make_genesis(
361351
if env.withdrawals is not None
362352
else None,
363353
parent_beacon_block_root=env.parent_beacon_block_root,
364-
requests_hash=Requests(root=[]).hash if fork.header_requests_required(0, 0) else None,
354+
requests_hash=Requests(max_request_type=fork.max_request_type(0, 0))
355+
if fork.header_requests_required(0, 0)
356+
else None,
365357
fork=fork,
366358
)
367359

@@ -381,7 +373,7 @@ def generate_block_data(
381373
previous_env: Environment,
382374
previous_alloc: Alloc,
383375
eips: Optional[List[int]] = None,
384-
) -> Tuple[FixtureHeader, List[Transaction], Alloc, Environment]:
376+
) -> Tuple[FixtureHeader, List[Transaction], Alloc, Environment, List[Bytes] | None]:
385377
"""
386378
Generate common block data for both make_fixture and make_hive_fixture.
387379
"""
@@ -475,23 +467,25 @@ def generate_block_data(
475467
assert (
476468
transition_tool_output.result.requests is not None
477469
), "Requests are required for this block"
478-
requests = transition_tool_output.result.requests
470+
requests = Requests(requests_list=transition_tool_output.result.requests)
479471

480-
if requests is not None and requests.hash != header.requests_hash:
472+
if requests is not None and Hash(requests) != header.requests_hash:
481473
raise Exception(
482-
f"Requests root in header does not match the requests root in the transition tool "
474+
"Requests root in header does not match the requests root in the transition tool "
483475
"output: "
484-
f"{header.requests_hash} != {requests.hash}"
476+
f"{header.requests_hash} != {Hash(requests)}"
485477
)
486478

487479
if block.requests is not None:
488-
header.requests_hash = Requests(root=[Bytes(r) for r in block.requests]).hash
480+
requests = Requests(requests_list=block.requests)
481+
header.requests_hash = Hash(requests)
489482

490483
return (
491484
header,
492485
txs,
493486
transition_tool_output.alloc,
494487
env,
488+
requests.requests_list if requests is not None else None,
495489
)
496490

497491
def network_info(self, fork: Fork, eips: Optional[List[int]] = None):
@@ -536,7 +530,7 @@ def make_fixture(
536530
# This is the most common case, the RLP needs to be constructed
537531
# based on the transactions to be included in the block.
538532
# Set the environment according to the block to execute.
539-
header, txs, new_alloc, new_env = self.generate_block_data(
533+
header, txs, new_alloc, new_env, requests = self.generate_block_data(
540534
t8n=t8n,
541535
fork=fork,
542536
block=block,
@@ -611,7 +605,7 @@ def make_hive_fixture(
611605
head_hash = genesis.header.block_hash
612606

613607
for block in self.blocks:
614-
header, txs, new_alloc, new_env = self.generate_block_data(
608+
header, txs, new_alloc, new_env, requests = self.generate_block_data(
615609
t8n=t8n, fork=fork, block=block, previous_env=env, previous_alloc=alloc, eips=eips
616610
)
617611
if block.rlp is None:
@@ -647,7 +641,7 @@ def make_hive_fixture(
647641
# Most clients require the header to start the sync process, so we create an empty
648642
# block on top of the last block of the test to send it as new payload and trigger the
649643
# sync process.
650-
sync_header, _, _, _ = self.generate_block_data(
644+
sync_header, _, _, _, requests = self.generate_block_data(
651645
t8n=t8n,
652646
fork=fork,
653647
block=Block(),

src/ethereum_test_tools/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
DepositRequest,
4444
Environment,
4545
Removable,
46+
Requests,
4647
Storage,
4748
TestParameterGroup,
4849
Transaction,
@@ -124,6 +125,7 @@
124125
"ReferenceSpec",
125126
"ReferenceSpecTypes",
126127
"Removable",
128+
"Requests",
127129
"EOA",
128130
"StateTest",
129131
"StateTestFiller",

src/ethereum_test_types/types.py

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from abc import abstractmethod
66
from dataclasses import dataclass
77
from functools import cached_property
8-
from typing import Any, ClassVar, Dict, Generic, List, Literal, Sequence, Tuple
8+
from typing import Any, ClassVar, Dict, Generic, List, Literal, Sequence, SupportsBytes, Tuple
99

1010
from coincurve.keys import PrivateKey, PublicKey
1111
from ethereum import rlp as eth_rlp
@@ -18,9 +18,7 @@
1818
ConfigDict,
1919
Field,
2020
PrivateAttr,
21-
RootModel,
2221
computed_field,
23-
field_validator,
2422
model_serializer,
2523
model_validator,
2624
)
@@ -1200,49 +1198,53 @@ def __bytes__(self) -> bytes:
12001198
return bytes(self.source_address) + bytes(self.source_pubkey) + bytes(self.target_pubkey)
12011199

12021200

1203-
class Requests(RootModel[List[Bytes]]):
1201+
def requests_list_to_bytes(requests_list: List[RequestBase] | Bytes | SupportsBytes) -> Bytes:
1202+
"""
1203+
Converts a list of requests to bytes.
1204+
"""
1205+
if not isinstance(requests_list, list):
1206+
return Bytes(requests_list)
1207+
return Bytes(b"".join([bytes(r) for r in requests_list]))
1208+
1209+
1210+
class Requests:
12041211
"""
12051212
Requests for the transition tool.
12061213
"""
12071214

1208-
root: List[Bytes] = Field(default_factory=list)
1215+
requests_list: List[Bytes]
12091216

1210-
@field_validator("root", mode="before")
1211-
@classmethod
1212-
def validate_root(cls, value):
1217+
def __init__(
1218+
self,
1219+
*requests: RequestBase,
1220+
max_request_type: int | None = None,
1221+
requests_list: List[List[RequestBase] | Bytes] | None = None,
1222+
):
12131223
"""
1214-
Helper validator flatten lists contained in the root.
1224+
Initializes the requests object.
12151225
"""
1216-
if isinstance(value, list):
1217-
for i, r in enumerate(value):
1218-
if isinstance(r, list):
1219-
value[i] = b"".join(r)
1220-
return value
1226+
if requests_list is not None:
1227+
assert len(requests) == 0, "requests must be empty if list is provided"
1228+
self.requests_list = []
1229+
for rl in requests_list:
1230+
self.requests_list.append(requests_list_to_bytes(rl))
1231+
return
12211232

1222-
def __bytes__(self) -> bytes:
1223-
"""
1224-
Returns the requests as bytes.
1225-
"""
1226-
return b"".join(r for r in self.root)
1233+
assert max_request_type is not None, "max_request_type must be provided"
12271234

1228-
@cached_property
1229-
def hash(self) -> Hash:
1235+
requests_lists: List[List[RequestBase]] = [[] for _ in range(max_request_type + 1)]
1236+
for r in requests:
1237+
requests_lists[r.type].append(r)
1238+
1239+
self.requests_list = [
1240+
requests_list_to_bytes(requests_list) for requests_list in requests_lists
1241+
]
1242+
1243+
def __bytes__(self) -> bytes:
12301244
"""
1231-
Returns the root hash of the requests.
1245+
Returns the requests hash.
12321246
"""
12331247
s: bytes = b""
1234-
for r in self.root:
1248+
for r in self.requests_list:
12351249
s = s + r.sha256()
12361250
return Bytes(s).sha256()
1237-
1238-
@classmethod
1239-
def from_list(cls, *requests: RequestBase, max_type_index: int) -> "Requests":
1240-
"""
1241-
Creates a Requests object from a single list of request objects, automatically
1242-
creating lists for each request type, up to the given max_type_index.
1243-
"""
1244-
root: List[List[RequestBase]] = [[] for _ in range(max_type_index + 1)]
1245-
for r in requests:
1246-
root[r.type].append(r)
1247-
1248-
return cls(root=root) # type: ignore

src/evm_transition_tool/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class Result(CamelModel):
8888
excess_blob_gas: HexNumber | None = Field(None, alias="currentExcessBlobGas")
8989
blob_gas_used: HexNumber | None = None
9090
requests_hash: Hash | None = None
91-
requests: Requests | None = None
91+
requests: List[Bytes] | None = None
9292

9393

9494
class TransitionToolInput(CamelModel):

0 commit comments

Comments
 (0)