Skip to content

Commit 3bbb42a

Browse files
committed
address reviews
1 parent 351d603 commit 3bbb42a

7 files changed

Lines changed: 86 additions & 205 deletions

File tree

packages/testing/src/execution_testing/ssz/__init__.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@
1313
MAX_EXTRA_DATA_BYTES,
1414
MAX_TXS_PER_PAYLOAD,
1515
MAX_WITHDRAWALS_PER_PAYLOAD,
16-
Address,
17-
Bloom,
18-
Bytes4,
19-
Bytes8,
20-
Bytes32,
21-
Bytes48,
22-
Hash32,
23-
Root,
24-
VersionedHash,
2516
)
2617
from .containers import (
2718
BUILT_PAYLOAD_BY_FORK,
@@ -97,6 +88,17 @@
9788
deterministic_seed,
9889
get_random_ssz_object,
9990
)
91+
from .ssz_types import (
92+
Address,
93+
Bloom,
94+
Bytes4,
95+
Bytes8,
96+
Bytes32,
97+
Bytes48,
98+
Hash32,
99+
Root,
100+
VersionedHash,
101+
)
100102

101103
ViewT = TypeVar("ViewT", bound=View)
102104

@@ -285,8 +287,6 @@ def _opt_bytes(value: bytes | None) -> bytes | None:
285287
"PayloadAttributesPrague",
286288
"PayloadAttributesShanghai",
287289
"PayloadStatus",
288-
"REFERENCE_SPEC_GIT_PATH",
289-
"REFERENCE_SPEC_VERSION",
290290
"RandomizationMode",
291291
"Root",
292292
"VersionedHash",
Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"""SSZ size limits and byte-vector aliases for the REST+SSZ Engine API."""
2-
3-
from remerkleable.byte_arrays import ByteVector
1+
"""SSZ size limits for the REST+SSZ Engine API."""
42

53
# Payload / envelope limits.
64
MAX_BYTES_PER_TX = 2**30
@@ -36,39 +34,3 @@
3634
MAX_CLIENT_VERSIONS = 4
3735
MAX_CAPABILITY_NAME_LENGTH = 64
3836
MAX_CAPABILITIES = 64
39-
40-
41-
class Hash32(ByteVector[32]):
42-
"""A 32-byte hash (`Hash32`, `Root` and `Bytes32` share this layout)."""
43-
44-
45-
class Bytes32(ByteVector[32]):
46-
"""A 32-byte fixed vector."""
47-
48-
49-
class Root(ByteVector[32]):
50-
"""A 32-byte merkle root."""
51-
52-
53-
class Address(ByteVector[20]):
54-
"""A 20-byte execution-layer address."""
55-
56-
57-
class Bloom(ByteVector[BYTES_PER_LOGS_BLOOM]):
58-
"""A 256-byte logs bloom filter."""
59-
60-
61-
class VersionedHash(ByteVector[32]):
62-
"""An EIP-4844 versioned blob hash."""
63-
64-
65-
class Bytes8(ByteVector[8]):
66-
"""An 8-byte value (e.g. `payload_id`)."""
67-
68-
69-
class Bytes4(ByteVector[4]):
70-
"""A 4-byte value (e.g. a client commit hash)."""
71-
72-
73-
class Bytes48(ByteVector[48]):
74-
"""A 48-byte value (KZG commitments and proofs)."""

packages/testing/src/execution_testing/ssz/containers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
MAX_EXTRA_DATA_BYTES,
3131
MAX_TXS_PER_PAYLOAD,
3232
MAX_WITHDRAWALS_PER_PAYLOAD,
33+
)
34+
from .ssz_types import (
3335
Address,
3436
Bloom,
3537
Bytes4,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""Byte-vector type aliases for the REST+SSZ Engine API."""
2+
3+
from remerkleable.byte_arrays import ByteVector
4+
5+
from .constants import BYTES_PER_LOGS_BLOOM
6+
7+
8+
class Hash32(ByteVector[32]):
9+
"""A 32-byte hash (`Hash32`, `Root` and `Bytes32` share this layout)."""
10+
11+
12+
class Bytes32(ByteVector[32]):
13+
"""A 32-byte fixed vector."""
14+
15+
16+
class Root(ByteVector[32]):
17+
"""A 32-byte merkle root."""
18+
19+
20+
class Address(ByteVector[20]):
21+
"""A 20-byte execution-layer address."""
22+
23+
24+
class Bloom(ByteVector[BYTES_PER_LOGS_BLOOM]):
25+
"""A 256-byte logs bloom filter."""
26+
27+
28+
class VersionedHash(ByteVector[32]):
29+
"""An EIP-4844 versioned blob hash."""
30+
31+
32+
class Bytes8(ByteVector[8]):
33+
"""An 8-byte value (e.g. `payload_id`)."""
34+
35+
36+
class Bytes4(ByteVector[4]):
37+
"""A 4-byte value (e.g. a client commit hash)."""
38+
39+
40+
class Bytes48(ByteVector[48]):
41+
"""A 48-byte value (KZG commitments and proofs)."""

packages/testing/src/execution_testing/ssz/tests/test_containers.py

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Round-trip and structural tests for the SSZ containers."""
22

3+
from remerkleable.basic import uint64, uint256
4+
35
from .. import decode_bytes, encode_bytes, hash_tree_root
46
from ..containers import (
57
EXECUTION_PAYLOAD_BY_FORK,
@@ -8,6 +10,7 @@
810
ExecutionPayloadEnvelopeAmsterdam,
911
Withdrawal,
1012
)
13+
from ..ssz_types import Address, Bloom, Bytes32, Hash32, Root
1114

1215
TRANSACTIONS = [
1316
bytes.fromhex("02f86b01"),
@@ -18,43 +21,43 @@
1821

1922
def _withdrawal() -> Withdrawal:
2023
return Withdrawal(
21-
index=7,
22-
validator_index=42,
23-
address=bytes.fromhex("11" * 20),
24-
amount=32_000_000_000,
24+
index=uint64(7),
25+
validator_index=uint64(42),
26+
address=Address(bytes.fromhex("11" * 20)),
27+
amount=uint64(32_000_000_000),
2528
)
2629

2730

28-
def _max_payload() -> ExecutionPayloadAmsterdam:
29-
"""The maximal (Amsterdam) payload: populated, carrying every field."""
31+
def _random_payload() -> ExecutionPayloadAmsterdam:
32+
"""A fully-populated payload carrying every field of the latest fork."""
3033
return ExecutionPayloadAmsterdam(
31-
parent_hash=bytes.fromhex("aa" * 32),
32-
fee_recipient=bytes.fromhex("bb" * 20),
33-
state_root=bytes.fromhex("cc" * 32),
34-
receipts_root=bytes.fromhex("dd" * 32),
35-
logs_bloom=bytes.fromhex("00" * 256),
36-
prev_randao=bytes.fromhex("ee" * 32),
37-
block_number=21_000_000,
38-
gas_limit=30_000_000,
39-
gas_used=21_000,
40-
timestamp=1_700_000_000,
34+
parent_hash=Hash32(bytes.fromhex("aa" * 32)),
35+
fee_recipient=Address(bytes.fromhex("bb" * 20)),
36+
state_root=Hash32(bytes.fromhex("cc" * 32)),
37+
receipts_root=Hash32(bytes.fromhex("dd" * 32)),
38+
logs_bloom=Bloom(bytes.fromhex("00" * 256)),
39+
prev_randao=Bytes32(bytes.fromhex("ee" * 32)),
40+
block_number=uint64(21_000_000),
41+
gas_limit=uint64(30_000_000),
42+
gas_used=uint64(21_000),
43+
timestamp=uint64(1_700_000_000),
4144
extra_data=bytes.fromhex("dead"),
42-
base_fee_per_gas=10**18,
43-
block_hash=bytes.fromhex("ff" * 32),
45+
base_fee_per_gas=uint256(10**18),
46+
block_hash=Hash32(bytes.fromhex("ff" * 32)),
4447
transactions=list(TRANSACTIONS),
4548
withdrawals=[_withdrawal()],
46-
blob_gas_used=131_072,
47-
excess_blob_gas=0,
49+
blob_gas_used=uint64(131_072),
50+
excess_blob_gas=uint64(0),
4851
block_access_list=bytes.fromhex("c0de"),
49-
slot_number=9_999,
52+
slot_number=uint64(9_999),
5053
)
5154

5255

5356
def _max_envelope() -> ExecutionPayloadEnvelopeAmsterdam:
54-
"""The maximal (Amsterdam) envelope wrapping :func:`_max_payload`."""
57+
"""A fully-populated envelope wrapping :func:`_random_payload`."""
5558
return ExecutionPayloadEnvelopeAmsterdam(
56-
payload=_max_payload(),
57-
parent_beacon_block_root=bytes.fromhex("12" * 32),
59+
payload=_random_payload(),
60+
parent_beacon_block_root=Root(bytes.fromhex("12" * 32)),
5861
execution_requests=[bytes.fromhex("00aa"), bytes.fromhex("01bbcc")],
5962
)
6063

@@ -68,7 +71,7 @@ def test_withdrawal_round_trip() -> None:
6871

6972
def test_payload_round_trip() -> None:
7073
"""An execution payload survives encode -> decode unchanged."""
71-
value = _max_payload()
74+
value = _random_payload()
7275
raw = encode_bytes(value)
7376
assert decode_bytes(ExecutionPayloadAmsterdam, raw) == value
7477

@@ -93,11 +96,11 @@ def test_transactions_two_level_offsets() -> None:
9396
Transactions of differing lengths round-trip exactly, and reordering them
9497
changes the root -- the inner offset table is order- and length-sensitive.
9598
"""
96-
value = _max_payload()
99+
value = _random_payload()
97100
decoded = decode_bytes(ExecutionPayloadAmsterdam, encode_bytes(value))
98101
assert [bytes(tx) for tx in decoded.transactions] == TRANSACTIONS
99102

100-
reordered = _max_payload()
103+
reordered = _random_payload()
101104
reordered.transactions = list(reversed(TRANSACTIONS))
102105
assert hash_tree_root(reordered) != hash_tree_root(value)
103106

packages/testing/src/execution_testing/ssz/tests/test_engine_containers.py

Lines changed: 0 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,14 @@
1010
EXECUTION_PAYLOAD_BODY_BY_FORK,
1111
FORKCHOICE_UPDATE_BY_FORK,
1212
PAYLOAD_ATTRIBUTES_BY_FORK,
13-
BlobAndProofV1,
14-
BlobAndProofV2,
15-
BlobCellsAndProofs,
16-
BlobsBundleV1,
17-
BlobsBundleV2,
18-
BlobsV1Request,
19-
BlobsV1Response,
20-
BlobsV4Request,
21-
BlobV1Entry,
22-
BlobV4Entry,
23-
BodiesByHashRequest,
24-
BodiesResponse,
25-
BodyEntry,
26-
CapabilitiesResponse,
27-
ClientVersion,
2813
ExecutionPayloadEnvelopeAmsterdam,
2914
ExecutionPayloadEnvelopeParis,
30-
ForkchoiceState,
31-
ForkchoiceUpdateResponse,
32-
IdentityResponse,
3315
PayloadStatus,
3416
)
3517

3618
_FORKS = ["Paris", "Shanghai", "Cancun", "Prague", "Osaka", "Amsterdam"]
3719

3820

39-
def _fields(cls: object) -> list:
40-
return list(cls.fields().keys())
41-
42-
4321
def test_new_registries_cover_forks_in_order() -> None:
4422
"""Every new per-fork registry spans Paris..Amsterdam."""
4523
for reg in (
@@ -51,111 +29,6 @@ def test_new_registries_cover_forks_in_order() -> None:
5129
assert list(reg) == _FORKS
5230

5331

54-
def test_payload_attributes_field_deltas() -> None:
55-
"""PayloadAttributes grows by the fields each fork added."""
56-
expected = ["timestamp", "prev_randao", "suggested_fee_recipient"]
57-
additions = {
58-
"Paris": [],
59-
"Shanghai": ["withdrawals"],
60-
"Cancun": ["parent_beacon_block_root"],
61-
"Prague": [],
62-
"Osaka": [],
63-
"Amsterdam": ["slot_number", "target_gas_limit"],
64-
}
65-
for fork, cls in PAYLOAD_ATTRIBUTES_BY_FORK.items():
66-
expected = expected + additions[fork]
67-
assert _fields(cls) == expected, fork
68-
69-
70-
def test_execution_payload_body_field_deltas() -> None:
71-
"""ExecutionPayloadBody grows transactions -> withdrawals -> BAL."""
72-
expected = ["transactions"]
73-
additions = {
74-
"Paris": [],
75-
"Shanghai": ["withdrawals"],
76-
"Cancun": [],
77-
"Prague": [],
78-
"Osaka": [],
79-
"Amsterdam": ["block_access_list"],
80-
}
81-
for fork, cls in EXECUTION_PAYLOAD_BODY_BY_FORK.items():
82-
expected = expected + additions[fork]
83-
assert _fields(cls) == expected, fork
84-
85-
86-
def test_built_payload_field_order() -> None:
87-
"""
88-
BuiltPayload field order per fork.
89-
"""
90-
expected = {
91-
"Paris": ["payload", "block_value"],
92-
"Shanghai": ["payload", "block_value", "should_override_builder"],
93-
"Cancun": [
94-
"payload",
95-
"block_value",
96-
"blobs_bundle",
97-
"should_override_builder",
98-
],
99-
"Prague": [
100-
"payload",
101-
"block_value",
102-
"blobs_bundle",
103-
"execution_requests",
104-
"should_override_builder",
105-
],
106-
}
107-
expected["Osaka"] = expected["Prague"]
108-
expected["Amsterdam"] = expected["Prague"]
109-
for fork, cls in BUILT_PAYLOAD_BY_FORK.items():
110-
assert _fields(cls) == expected[fork], fork
111-
112-
113-
def test_forkchoice_update_field_order() -> None:
114-
"""ForkchoiceUpdate gains custody_columns only at Amsterdam."""
115-
for fork, cls in FORKCHOICE_UPDATE_BY_FORK.items():
116-
base = ["forkchoice_state", "payload_attributes"]
117-
if fork == "Amsterdam":
118-
base = base + ["custody_columns"]
119-
assert _fields(cls) == base, fork
120-
121-
122-
def test_single_container_field_orders() -> None:
123-
"""Exact field order for the fork-independent containers."""
124-
assert _fields(ForkchoiceState) == [
125-
"head_block_hash",
126-
"safe_block_hash",
127-
"finalized_block_hash",
128-
]
129-
assert _fields(PayloadStatus) == [
130-
"status",
131-
"latest_valid_hash",
132-
"validation_error",
133-
]
134-
assert _fields(ForkchoiceUpdateResponse) == [
135-
"payload_status",
136-
"payload_id",
137-
]
138-
assert _fields(BlobsBundleV1) == ["commitments", "proofs", "blobs"]
139-
assert _fields(BlobsBundleV2) == ["commitments", "proofs", "blobs"]
140-
assert _fields(BlobAndProofV1) == ["blob", "proof"]
141-
assert _fields(BlobAndProofV2) == ["blob", "proofs"]
142-
assert _fields(BlobCellsAndProofs) == ["blob_cells", "proofs"]
143-
assert _fields(BodiesByHashRequest) == ["block_hashes"]
144-
assert _fields(BodyEntry) == ["available", "body"]
145-
assert _fields(BodiesResponse) == ["entries"]
146-
assert _fields(BlobsV1Request) == ["versioned_hashes"]
147-
assert _fields(BlobV1Entry) == ["available", "contents"]
148-
assert _fields(BlobsV1Response) == ["entries"]
149-
assert _fields(BlobsV4Request) == [
150-
"versioned_hashes",
151-
"indices_bitarray",
152-
]
153-
assert _fields(BlobV4Entry) == ["available", "contents"]
154-
assert _fields(ClientVersion) == ["code", "name", "version", "commit"]
155-
assert _fields(IdentityResponse) == ["versions"]
156-
assert _fields(CapabilitiesResponse) == ["capabilities"]
157-
158-
15932
def test_payload_status_optional_encoding_matches_spec_examples() -> None:
16033
"""
16134
The ``Optional``/``String`` wire shape tests.

0 commit comments

Comments
 (0)