fix: support new annotated_validators.yaml lean-quickstart format#277
fix: support new annotated_validators.yaml lean-quickstart format#277MegaRedHand wants to merge 5 commits intoposeidon1-migrationfrom
annotated_validators.yaml lean-quickstart format#277Conversation
🤖 Kimi Code ReviewThe PR refactors validator key loading to support Security & Correctness
Code Quality
Logic Validation
Consensus Safety
Recommendation: Address the absolute path consideration if the YAML source is ever untrusted; otherwise the PR is sound and ready for merge. Automated review by Kimi (Moonshot AI) · kimi-k2.5 · custom prompt |
🤖 Claude Code ReviewNow I have full context. Let me write the review. PR #277 Review:
|
🤖 Codex Code Review
No fork-choice, justification/finalization, STF, attestation-processing, XMSS verification, or SSZ logic is touched here; the risk is isolated to validator key/config loading. I could not run Automated review by OpenAI Codex · gpt-5.4 · custom prompt |
Greptile SummarySwitches The implementation is clean: Confidence Score: 5/5Safe to merge; the only finding is a trivial visibility annotation on a module-private helper. No P0 or P1 issues found. The single comment is a P2 style suggestion (removing No files require special attention.
|
| Filename | Overview |
|---|---|
| bin/ethlambda/src/main.rs | Rewrites validator key loading to consume lean-quickstart's native two-entry-per-validator YAML format; new logic groups entries by index, routes via filename substring to attestation/proposal slots, and validates pubkey_hex for hex/length only (documented limitation). |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["annotated_validators.yaml\n(2 entries per validator)"] --> B["read_validator_keys()"]
B --> C["Lookup node_id\nBTreeMap<String, Vec<AnnotatedValidator>>"]
C -->|not found| ERR1["Error: node_id not found"]
C -->|found| D["Iterate Vec<AnnotatedValidator>"]
D --> E["classify_role(privkey_file)"]
E -->|contains 'attester'| F["ValidatorKeyRole::Attestation"]
E -->|contains 'proposer'| G["ValidatorKeyRole::Proposal"]
E -->|neither / both| ERR2["Error: ambiguous filename"]
F --> H["grouped BTreeMap<u64, RoleSlots>"]
G --> H
H -->|duplicate role| ERR3["Error: duplicate role entry"]
H --> I["For each (idx, RoleSlots)"]
I -->|missing attestation| ERR4["Error: missing attester entry"]
I -->|missing proposal| ERR5["Error: missing proposer entry"]
I --> J["load_key(att_path)\nload_key(prop_path)"]
J --> K["HashMap<u64, ValidatorKeyPair>"]
Prompt To Fix All With AI
This is a comment left during a code review.
Path: bin/ethlambda/src/main.rs
Line: 255
Comment:
**Unnecessary `pub` visibility on module-private function**
`deser_pubkey_hex` is only referenced by the `#[serde(deserialize_with = "...")]` attribute on `AnnotatedValidator`, which is in the same module. In a binary crate there is no external caller, and `pub` adds no value here — the function would work identically without it.
```suggestion
fn deser_pubkey_hex<'de, D>(d: D) -> Result<ValidatorPubkeyBytes, D::Error>
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "compat: load annotated_validators.yaml i..." | Re-trigger Greptile
| privkey_file: PathBuf, | ||
| } | ||
|
|
||
| pub fn deser_pubkey_hex<'de, D>(d: D) -> Result<ValidatorPubkeyBytes, D::Error> |
There was a problem hiding this comment.
Unnecessary
pub visibility on module-private function
deser_pubkey_hex is only referenced by the #[serde(deserialize_with = "...")] attribute on AnnotatedValidator, which is in the same module. In a binary crate there is no external caller, and pub adds no value here — the function would work identically without it.
| pub fn deser_pubkey_hex<'de, D>(d: D) -> Result<ValidatorPubkeyBytes, D::Error> | |
| fn deser_pubkey_hex<'de, D>(d: D) -> Result<ValidatorPubkeyBytes, D::Error> |
Prompt To Fix With AI
This is a comment left during a code review.
Path: bin/ethlambda/src/main.rs
Line: 255
Comment:
**Unnecessary `pub` visibility on module-private function**
`deser_pubkey_hex` is only referenced by the `#[serde(deserialize_with = "...")]` attribute on `AnnotatedValidator`, which is in the same module. In a binary crate there is no external caller, and `pub` adds no value here — the function would work identically without it.
```suggestion
fn deser_pubkey_hex<'de, D>(d: D) -> Result<ValidatorPubkeyBytes, D::Error>
```
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
The lean-quickstart devnet4 generator (generate-genesis.sh:655-672, DUAL_KEY_MODE=true branch) emits two entries per validator with `pubkey_hex` + `privkey_file` fields, distinguished by `attester` / `proposer` substring in the filename. zeam and lantern already parse this layout. ethlambda was the only client requiring an explicit `attestation_privkey_file` + `proposal_privkey_file` schema, forcing operators to hand-rewrite the file after every regeneration. Switch the loader to consume the generator's native output: - AnnotatedValidator now models one role-specific entry (single privkey_file + pubkey_hex). - read_validator_keys groups entries per validator index and routes by filename substring, matching zeam (pkgs/cli/src/node.zig:540) and lantern (client_keys.c:606). - pubkey_hex is parsed for hex-format validation (52-byte hex) but not cross-checked against the loaded secret key. Deriving the pubkey would require either an upstream leanSig accessor (no public_key() exists today on GeneralizedXMSSSecretKey) or burning an XMSS one-time slot per startup. ValidatorKeyPair, KeyManager, and BlockChain::spawn signatures unchanged.
7358311 to
61dc50b
Compare
The lean-quickstart devnet4 generator (generate-genesis.sh:655-672, DUAL_KEY_MODE=true branch) emits two entries per validator with
pubkey_hex+privkey_filefields, distinguished byattester/proposersubstring in the filename. zeam and lantern already parse this layout. ethlambda was the only client requiring an explicitattestation_privkey_file+proposal_privkey_fileschema, forcing operators to hand-rewrite the file after every regeneration.Switch the loader to consume the generator's native output:
ValidatorKeyPair, KeyManager, and BlockChain::spawn signatures unchanged.
This PR also updates the lean-multisig version to the latest
devnet4commit and thelog_inv_rateaggregation parameter to 2 (which is what other clients use).It also adds a limit to the number of attestation data objects per block (leanEthereum/leanSpec#536)