Skip to content

Commit c6c1688

Browse files
Devnet4: dual-key validators, block signing, and type migration (#233) (incl. #275 #277)
## Motivation Implements devnet4 ([leanSpec#449](leanEthereum/leanSpec#449)): separate attestation and proposal keys for validators, replacing the single-key model and removing the proposer attestation wrapper. ## Description ### Phase 1: Types (#230) - `Validator` gains `attestation_pubkey` + `proposal_pubkey` (replaces single `pubkey`) - `SignedBlockWithAttestation` → `SignedBlock`, `BlockWithAttestation` deleted - Genesis config updated to dual-key YAML format ### Phase 2: Key manager + block proposal (#231) - `ValidatorKeyPair` with separate attestation/proposal secret keys - Block proposal signs `hash_tree_root(block)` with proposal key (no proposer attestation) - All validators now attest at interval 1 (proposer no longer skipped) ### Phase 3: Store + verification (#232) - Signature verification uses `get_attestation_pubkey()` / `get_proposal_pubkey()` as appropriate - Removed ~40 lines of proposer attestation handling from `on_block_core` - Storage reads/writes `SignedBlock` directly ### Phase 4: Network + tests (#233) - Type rename cascade across all network layer files - Test harness updated: removed `ProposerAttestation`, simplified `build_signed_block()` - Added proposal signing metrics - leanSpec bumped to 9c30436 (dual-key test fixtures) - Skipped `test_reorg_with_slot_gaps` (fixture relies on gossip proposer attestation state) ## Supersedes Closes #230, closes #231, closes #232 ## Blockers - **lean-quickstart**: needs devnet4 genesis config support for manual devnet testing --------- Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com>
1 parent 23bb6f5 commit c6c1688

34 files changed

Lines changed: 2308 additions & 1949 deletions

File tree

.claude/skills/devnet-log-review/references/CLIENT_LOG_PATTERNS.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ ethlambda_p2p: Published block to gossipsub slot=X proposer=Y
5454
```
5555
ethlambda_blockchain: Published attestation slot=X validator_id=Y
5656
ethlambda_p2p::gossipsub::handler: Received new attestation from gossipsub, sending for processing slot=X validator=Y
57-
ethlambda_blockchain: Skipping attestation for proposer slot=X (expected: proposers don't attest to their own slot)
5857
```
5958

6059
### Block Processing

CLAUDE.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ crates/
4848
### Tick-Based Validator Duties (4-second slots, 5 intervals per slot)
4949
```
5050
Interval 0: Block proposal → accept attestations if proposal exists
51-
Interval 1: Vote propagation (no action)
51+
Interval 1: Attestation production (all validators, including proposer)
5252
Interval 2: Aggregation (aggregators create proofs from gossip signatures)
5353
Interval 3: Safe target update (fork choice)
5454
Interval 4: Accept accumulated attestations
@@ -106,7 +106,7 @@ let byte: u8 = code.into();
106106
### Ownership for Large Structures
107107
```rust
108108
// Prefer taking ownership to avoid cloning large data (signatures ~3KB)
109-
pub fn insert_signed_block(&mut self, root: H256, signed_block: SignedBlockWithAttestation) { ... }
109+
pub fn insert_signed_block(&mut self, root: H256, signed_block: SignedBlock) { ... }
110110

111111
// Add .clone() at call site if needed - makes cost explicit
112112
store.insert_signed_block(block_root, signed_block.clone());
@@ -310,8 +310,8 @@ Both servers are spawned as independent `tokio::spawn` tasks from `main.rs`. Bin
310310
```yaml
311311
GENESIS_TIME: 1770407233
312312
GENESIS_VALIDATORS:
313-
- "cd323f232b34ab26d6db7402c886e74ca81cfd3a..." # 52-byte XMSS pubkeys (hex)
314-
- "b7b0f72e24801b02bda64073cb4de6699a416b37..."
313+
- attestation_pubkey: "cd323f232b34ab26d6db7402c886e74ca81cfd3a..." # 52-byte XMSS pubkeys (hex)
314+
proposal_pubkey: "b7b0f72e24801b02bda64073cb4de6699a416b37..."
315315
```
316316
- Validator indices are assigned sequentially (0, 1, 2, ...) based on array order
317317
- All genesis state fields (checkpoints, justified_slots, etc.) initialize to zero/empty defaults
@@ -363,7 +363,7 @@ cargo test -p ethlambda-blockchain --test forkchoice_spectests -- --test-threads
363363
|-------|-------------|---------|
364364
| `BlockHeaders` | H256 → BlockHeader | Block headers by root |
365365
| `BlockBodies` | H256 → BlockBody | Block bodies (empty for genesis) |
366-
| `BlockSignatures` | H256 → BlockSignaturesWithAttestation | Signatures (absent for genesis) |
366+
| `BlockSignatures` | H256 → BlockSignatures | Signatures (absent for genesis) |
367367
| `States` | H256 → State | Beacon states by root |
368368
| `LatestKnownAttestations` | u64 → AttestationData | Fork-choice-active attestations |
369369
| `LatestNewAttestations` | u64 → AttestationData | Pending (pre-promotion) attestations |

0 commit comments

Comments
 (0)