Skip to content

Commit 0b7d33e

Browse files
tcoratgerThomas Coratgerclaude
authored
refactor(ssz): depend on the released SSZ specification (#1205)
The SSZ specification was extracted into its own repository and released as eth-ssz-specs 0.1.0. leanSpec now imports it instead of carrying a copy. Deleted: the nine-module vendored package, the merkleization module, their mirrored unit tests, and the two consensus vector modules whose cases the upstream release ships verbatim (merkleization boundaries and the decode-failure smoke test). The generic cases in the basic-types vectors go the same way; the field-element and attestation-subnet cases stay, since upstream cannot express them. Kept, in a new module for the shapes the SSZ package leaves to the protocol: - The struct base, frozen and camelCase. Fork choice keeps one state per block root and hands it to every branch below, so a writable state would let one branch rewrite history for its siblings. The SSZ shapes are mutable, so each leanSpec base restates the freeze. The key casing is what cross-client test vectors carry. - The byte widths, declared against the SSZ byte vector, as the consensus specs declare theirs. The 32-byte one is the root type itself: a separate vector of that width would be its sibling, and SSZ refuses equality between siblings, so every check of a stored root against a computed one would raise. Two behaviors needed porting rather than renaming: - The KoalaBear field element now rides on the 32-bit unsigned integer. That is what packs eight elements to a leaf; a type outside the unsigned integers takes a leaf each, and every XMSS key, signature and registry root would move. A test pins the packing. - The sequence decoder builds its result past validation, so the validator registry stopped meeting its position rule on the wire. A registry read off the wire is re-checked, which keeps two clients from disagreeing on whether a malformed registry is valid. Every consensus byte is unchanged: the serialized payloads and Merkle roots in all surviving vectors are identical to what the vendored code produced. The one JSON difference is that a bare field element now renders as a decimal string, the way every other integer already did, instead of a Python repr. Co-authored-by: Thomas Coratger <thomas.coratger@ethereum.org> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 0588c2d commit 0b7d33e

171 files changed

Lines changed: 564 additions & 9059 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/agents/code-tester.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The fork specs under `src/lean_spec/spec/forks/` are tested EXCLUSIVELY through
1717

1818
- There is NO `tests/spec/forks/` tree, and you must never create one.
1919
- For ANY fork behavior — fork choice, state transition, block production, validator duties, aggregation, the containers, slot/interval math, the fork registry or protocol — write or update a consensus test-vector fixture (`state_transition`, `fork_choice`, `ssz`, `slot_clock`, `verify_signatures`, etc.), never a pytest.
20-
- Mirrored pytest unit tests apply only to NON-fork modules (`node/`, `spec/crypto/`, `spec/ssz/`, and similar).
20+
- Mirrored pytest unit tests apply only to NON-fork modules (`node/`, `spec/crypto/`, and similar).
2121
- If asked to "add tests" for a fork container or function (for example a new container under `spec/forks/lstar/containers/`), produce a consensus vector fixture, not a pytest under `tests/`.
2222

2323
## Auto-Invoke Skills

.claude/rules/code-style.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ paths:
2424
Bad:
2525
```python
2626
def process(data):
27-
from lean_spec.spec.crypto.merkleization import hash_tree_root
27+
from ssz import hash_tree_root
2828
return hash_tree_root(data)
2929
```
3030

3131
Good:
3232
```python
33-
from lean_spec.spec.crypto.merkleization import hash_tree_root
33+
from ssz import hash_tree_root
3434

3535
def process(data):
3636
return hash_tree_root(data)

.claude/skills/audit/SKILL.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ orchestrator sharded the tree only so the work parallelizes.
8585
2. **Shard.** Split the in-scope tree into coherent subsystems so agents run in parallel.
8686
The natural shards:
8787
- `src/lean_spec/spec/crypto/` (XMSS, hashing, signatures, aggregation)
88-
- `src/lean_spec/spec/ssz/`
8988
- `src/lean_spec/spec/forks/` (state transition, fork choice, containers, validator
9089
duties, aggregation)
9190
- `src/lean_spec/node/networking/` (gossipsub, reqresp, quic, discovery)

.claude/skills/test/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Pass additional arguments after `--`:
1919

2020
- `/test -- -v` - Verbose output
2121
- `/test -- -k "test_serialize"` - Run matching tests
22-
- `/test -- tests/spec/ssz/` - Run specific test directory
22+
- `/test -- tests/spec/crypto/` - Run specific test directory
2323

2424
## Examples
2525

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ subspecifications that the Lean Ethereum protocol relies on.
9696
- A test file must never test a type that lives in a different source module. For example, tests
9797
for `SlotClock` (in `node/chain/clock.py`) belong in `tests/node/chain/test_clock.py`,
9898
never in an unrelated test module.
99-
- This mirroring covers non-fork modules only (`node/`, `spec/crypto/`, `spec/ssz/`, etc.). The
99+
- This mirroring covers non-fork modules only (`node/`, `spec/crypto/`, etc.). The
100100
fork specs under `src/lean_spec/spec/forks/` are exempt — see the forks-are-vectors rule below.
101101
- **CRITICAL - FORKS ARE TESTED BY VECTORS, NOT PYTESTS**: This is a STRICT requirement. The fork
102102
specs under `src/lean_spec/spec/forks/` are tested exclusively through consensus test vectors

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ just test
8888
│ └── spec/ # Protocol specifications
8989
│ ├── crypto/ # Cryptographic subspecs (poseidon, koalabear, xmss, ...)
9090
│ ├── forks/ # Fork specifications (tested via consensus vectors)
91-
│ ├── ssz/ # SSZ serialization
91+
│ ├── ssz_types.py # The SSZ shapes leanSpec declares itself
9292
│ └── observability/ # Observability spec
9393
├── tests/ # Test suite
9494
│ ├── consensus/ # Consensus test vectors

packages/testing/src/consensus_testing/genesis.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""Consensus layer genesis state, block, and anchor construction for tests."""
22

3+
from ssz import Uint64, hash_tree_root
4+
35
from consensus_testing.keys import XmssKeyManager
4-
from lean_spec.spec.crypto.merkleization import hash_tree_root
56
from lean_spec.spec.forks import Checkpoint, Interval, Slot, ValidatorIndex
67
from lean_spec.spec.forks.lstar import Store
78
from lean_spec.spec.forks.lstar.containers import (
@@ -16,7 +17,7 @@
1617
Validators,
1718
)
1819
from lean_spec.spec.forks.lstar.spec import LstarSpec
19-
from lean_spec.spec.ssz import Bytes52, Uint64
20+
from lean_spec.spec.ssz_types import Bytes52
2021

2122

2223
def build_genesis_state(

packages/testing/src/consensus_testing/keys.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
from pathlib import Path
1313
from typing import ClassVar, Literal
1414

15+
from ssz import hash_tree_root
16+
1517
from lean_spec.config import LEAN_ENV
1618
from lean_spec.spec.crypto.koalabear import Fp
17-
from lean_spec.spec.crypto.merkleization import hash_tree_root
1819
from lean_spec.spec.crypto.xmss.constants import TARGET_CONFIG
1920
from lean_spec.spec.crypto.xmss.containers import (
2021
PublicKey,
@@ -39,7 +40,7 @@
3940
AttestationData,
4041
SingleMessageAggregate,
4142
)
42-
from lean_spec.spec.ssz import Bytes32
43+
from lean_spec.spec.ssz_types import Bytes32
4344

4445
KeyRole = Literal["attestation", "proposal"]
4546
"""Discriminator for which signing role's key to load from a validator key pair."""

packages/testing/src/consensus_testing/keys_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from pathlib import Path
1616

1717
import click
18+
from ssz import Uint64
1819

1920
from consensus_testing.keys import (
2021
LEAN_ENV_TO_SCHEMES,
@@ -24,7 +25,6 @@
2425
from lean_spec.spec.crypto.xmss.containers import ValidatorKeyPair
2526
from lean_spec.spec.crypto.xmss.interface import GeneralizedXmssScheme
2627
from lean_spec.spec.forks import Slot
27-
from lean_spec.spec.ssz import Uint64
2828

2929
KEY_DOWNLOAD_URLS = {
3030
"test": "https://github.com/leanEthereum/leansig-test-keys/releases/download/latest/test_scheme.tar.gz",

packages/testing/src/consensus_testing/mocks.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from types import MappingProxyType
99
from typing import cast
1010

11+
from ssz import Uint64, hash_tree_root
12+
1113
from lean_spec.node.chain.clock import SlotClock
1214
from lean_spec.node.networking import PeerId
1315
from lean_spec.node.networking.peer import PeerInfo
@@ -17,7 +19,6 @@
1719
from lean_spec.node.sync.block_cache import BlockCache
1820
from lean_spec.node.sync.peer_manager import PeerManager
1921
from lean_spec.node.sync.service import SyncService
20-
from lean_spec.spec.crypto.merkleization import hash_tree_root
2122
from lean_spec.spec.forks import (
2223
Checkpoint,
2324
RejectionReason,
@@ -34,7 +35,7 @@
3435
State,
3536
)
3637
from lean_spec.spec.forks.lstar.spec import LstarSpec
37-
from lean_spec.spec.ssz import Bytes32, Uint64
38+
from lean_spec.spec.ssz_types import Bytes32
3839

3940

4041
@dataclass

0 commit comments

Comments
 (0)