@@ -9,7 +9,7 @@ Not to be confused with Ethereum consensus clients AKA Beacon Chain clients AKA
99** Rust version:** 1.92.0 (edition 2024)
1010** Test fixtures release:** Download latest production fixtures from leanSpec releases
1111
12- ## Codebase Structure (10 crates)
12+ ## Codebase Structure (12 workspace crates)
1313
1414```
1515bin/ethlambda/ # Entry point, CLI, orchestration
@@ -18,17 +18,24 @@ crates/
1818 blockchain/ # State machine actor (GenServer pattern)
1919 ├─ src/lib.rs # BlockChain actor, tick events, validator duties
2020 ├─ src/store.rs # Fork choice store, block/attestation processing
21+ ├─ src/block_builder.rs # Block assembly (pre-built at previous slot's interval 4)
22+ ├─ src/aggregation.rs # Interval-2 signature aggregation worker
23+ ├─ src/reaggregate.rs # Re-aggregation of block-borne votes on import
24+ ├─ src/sync_status.rs # Sync-gate tracker (suppresses duties while syncing)
2125 ├─ src/key_manager.rs # Validator key management and signing
2226 ├─ src/metrics.rs # Blockchain-level Prometheus metrics
23- ├─ fork_choice/ # LMD GHOST implementation (3SF-mini)
24- └─ state_transition/ # STF: process_slots, process_block, attestations
27+ ├─ fork_choice/ # [crate] LMD GHOST implementation (3SF-mini)
28+ └─ state_transition/ # [crate] STF: process_slots, process_block, attestations
29+ ├─ src/justified_slots_ops.rs # Relative-index helpers for justified_slots
2530 └─ src/metrics.rs # State transition timing + counters
2631 common/
2732 ├─ types/ # Core types (State, Block, Attestation, Checkpoint)
2833 ├─ crypto/ # XMSS aggregation (leansig wrapper)
29- └─ metrics/ # Prometheus re-exports, TimingGuard, gather utilities
34+ ├─ metrics/ # Prometheus re-exports, TimingGuard, gather utilities
35+ └─ test-fixtures/ # Spec-fixture loading (prod dep of rpc's Hive test driver)
3036 net/
31- ├─ p2p/ # libp2p: gossipsub + req-resp (Status, BlocksByRoot)
37+ ├─ api/ # Actor protocol traits wiring BlockChain ↔ P2P
38+ ├─ p2p/ # libp2p: gossipsub + req-resp (Status, BlocksByRoot, BlocksByRange)
3239 │ ├─ src/gossipsub/ # Topic encoding, message handling
3340 │ ├─ src/req_resp/ # Request/response codec and handlers
3441 │ └─ src/metrics.rs # Peer connection/disconnection tracking
@@ -56,12 +63,14 @@ Interval 4: Accept accumulated attestations; build the NEXT slot's block and pub
5663
5764### Attestation Pipeline
5865```
59- Gossip → Signature verification → new_attestations (pending)
60- ↓ (interval 4)
61- promote → known_attestations (fork choice active)
66+ Gossip → Signature verification → new_payloads (pending)
67+ ↓ (intervals 0/ 4)
68+ promote → known_payloads (fork choice active)
6269 ↓
6370Fork choice head update
6471```
72+ (Store buffer fields are ` new_payloads ` /` known_payloads ` ; the accessors are named
73+ ` extract_latest_new_attestations ` /` extract_latest_known_attestations ` .)
6574
6675### State Transition Phases
67761 . ** process_slots()** : Advance through empty slots, update historical roots
@@ -105,7 +114,7 @@ let byte: u8 = code.into();
105114
106115### Ownership for Large Structures
107116``` rust
108- // Prefer taking ownership to avoid cloning large data (signatures ~3KB )
117+ // Prefer taking ownership to avoid cloning large data (signatures ~2.5KB )
109118pub fn insert_signed_block (& mut self , root : H256 , signed_block : SignedBlock ) { ... }
110119
111120// Add .clone() at call site if needed - makes cost explicit
@@ -252,7 +261,7 @@ actual_slot = finalized_slot + 1 + relative_index
252261
253262** XMSS (eXtended Merkle Signature Scheme):**
254263- Post-quantum signature scheme
255- - 52-byte public keys, 3112 -byte signatures
264+ - 52-byte public keys, 2536 -byte signatures ( ` SIGNATURE_SIZE ` in ` common/types/src/signature.rs ` )
256265- Epoch-based to prevent reuse
257266- Aggregation via leanVM (previously leanMultisig) for efficiency
258267
@@ -268,11 +277,11 @@ actual_slot = finalized_slot + 1 + relative_index
268277 - Topic: ` /leanconsensus/{fork_digest}/{block|aggregation|attestation_N}/ssz_snappy `
269278 - ` fork_digest ` is a 4-byte hex string (no ` 0x ` prefix); currently the dummy ` 12345678 ` agreed across clients
270279 - Mesh size: 8 (6-12 bounds), heartbeat: 700ms
271- - ** Req/Resp** : Status, BlocksByRoot (snappy frame compression + varint length)
280+ - ** Req/Resp** : Status, BlocksByRoot, BlocksByRange (snappy frame compression + varint length)
272281
273282### Retry Strategy on Block Requests
274- - Exponential backoff: 10ms, 40ms, 160ms, 640ms, 2560ms
275- - Max 5 attempts, random peer selection on retry
283+ - Exponential backoff: doubling from ` INITIAL_BACKOFF_MS ` (5ms → 2560ms)
284+ - Max ` MAX_FETCH_RETRIES ` (10) attempts, random peer selection on retry
276285
277286### Message IDs
278287- 20-byte truncated SHA256 of: domain (valid/invalid snappy) + topic + data
@@ -301,9 +310,9 @@ GENESIS_VALIDATORS:
301310### Test Categories
3023111. **Unit tests**: Embedded in source files
3033122. **Spec tests**: From ` leanSpec/fixtures/consensus/`
304- - ` forkchoice_spectests.rs` (uses `on_block_without_verification`)
305- - ` signature_spectests.rs`
306- - ` stf_spectests.rs` (state transition)
313+ - ` crates/blockchain/tests/ forkchoice_spectests.rs` (uses `on_block_without_verification` via `spec_test_runner `)
314+ - ` crates/blockchain/tests/ signature_spectests.rs`
315+ - ` crates/blockchain/state_transition/tests/ stf_spectests.rs` (state transition)
307316
308317# ## Running Tests
309318` ` ` bash
@@ -316,7 +325,7 @@ cargo test -p ethlambda-blockchain --test forkchoice_spectests -- --test-threads
316325
317326# ## Aggregator Flag Required for Finalization
318327- At least one node **must** be started with `--is-aggregator` to finalize blocks
319- - Without this flag, attestations pass signature verification and are logged as "Attestation processed", but the signature is never stored for aggregation (` store.rs:368 `), so blocks are always built with `attestation_count=0`
328+ - Without this flag, attestations pass signature verification and are logged as "Attestation processed", but the signature is never stored for aggregation (the `is_aggregator` gate in `on_gossip_attestation`, ` store.rs`), so blocks are always built with `attestation_count=0`
320329- The attestation pipeline : gossip → verify signature → store gossip signature (only if `is_aggregator`) → aggregate at interval 2 → promote to known → pack into blocks
321330- **Symptom**: `justified_slot=0` and `finalized_slot=0` indefinitely despite healthy block production and attestation gossip
322331
@@ -368,7 +377,7 @@ and are consumed during the tick pipeline (promotion at intervals 0/4,
368377aggregation at interval 2).
369378
370379# ## State Root Computation
371- - Always computed via `tree_hash_root ()` after full state transition
380+ - Always computed via `hash_tree_root ()` after full state transition
372381- Must match proposer's pre-computed `block.state_root`
373382
374383# ## Finalization Checks
@@ -383,8 +392,8 @@ aggregation at interval 2).
383392
384393**Critical:**
385394- `leansig` : XMSS signatures (leanEthereum project)
386- - `ethereum_ssz ` : SSZ serialization
387- - `tree_hash ` : Merkle tree hashing
395+ - `libssz` / `libssz-derive` / `libssz-types ` : SSZ serialization
396+ - `libssz-merkle ` : Merkle tree hashing (`hash_tree_root()`)
388397- `spawned-concurrency` : Actor model
389398- `libp2p` : P2P networking (custom LambdaClass fork)
390399- `vergen-git2` : Build-time git commit/branch info embedded in binary
@@ -397,6 +406,7 @@ aggregation at interval 2).
397406
398407**Specs:** `leanSpec/src/lean_spec/` (Python reference implementation)
399408**Devnet:** `lean-quickstart` (github.com/blockblaz/lean-quickstart)
409+ **Docs:** `docs/` — `rpc.md`, `metrics.md`, `checkpoint_sync.md`, `3sf_mini.md`, `lmd_ghost.md` (mdbook via `make docs`)
400410**Releases:** See `RELEASE.md` for release process documentation
401411
402412# # Other implementations
0 commit comments