Repository navigation
fix(beacon): read SLOT_DURATION_MS when a network config omits SECONDS_PER_SLOT - #691
MegaRedHand wants to merge 7 commits into
Conversation
…S_PER_SLOT Configs generated by kurtosis' ethereum-genesis-generator carry only SLOT_DURATION_MS, since consensus-specs dropped SECONDS_PER_SLOT. Config's container-level serde default filled in mainnet's 12 seconds and derive_genesis_fields then overwrote the file's millisecond value, so a 6 s devnet silently ran on a 12 s clock. ConfigFile now records whether the file had SLOT_DURATION_MS and no SECONDS_PER_SLOT. In that case the millisecond value is authoritative and seconds_per_slot is derived from it; a value that is zero or not a whole number of seconds is a startup error naming SLOT_DURATION_MS. A file with SECONDS_PER_SLOT, and every built-in network, behaves as before.
🤖 Kimi Code ReviewI'll review this PR which adds support for Overall AssessmentThe PR is well-structured with good test coverage and clear documentation. However, I found several issues ranging from minor correctness problems to a potential consensus-critical bug. Critical Issues1. Integer Division Truncation Risk in
|
| Path | Validates slot_duration_ms whole seconds? |
|---|---|
dir.rs |
Yes (InvalidSlotDurationMs error) |
built_in.rs |
No |
Problem: built_in.rs at line 71-73 calls derive_genesis_fields with slot_duration_only but never validates slot_duration_ms:
// built_in.rs:71-73
let slot_duration_only = parsed.slot_duration_only;
let mut config = parsed.config;
super::derive_genesis_fields(&mut config, genesis.genesis_time, slot_duration_only);If a built-in network definition somehow carries an invalid SLOT_DURATION_MS, it passes through unchecked.
Recommendation: Add the same validation in built_in.rs or extract validation into derive_genesis_fields itself.
Code Quality Issues
4. Test Helper Panic Message (bin/ethlambda/src/network/dir.rs:350)
assert_ne!(replaced, text, "config no longer carries SLOT_DURATION_MS");Problem: The panic message is backwards. When assert_ne! fails, it means replaced == text, i.e., the replacement didn't happen because the original text didn't contain SLOT_DURATION_MS: 12000. The message should say "config must contain SLOT_DURATION_MS: 12000 to replace".
5. Magic Number Duplication
The value 1_000 appears in:
dir.rs:136(slot_duration_ms % 1_000)mod.rs:239(config.seconds_per_slot = config.slot_duration_ms / 1_000)mod.rs:241(config.slot_duration_ms = config.seconds_per_slot * 1_000)
Consider a const MS_PER_SECOND: u64 = 1_000;.
6. Test Coverage Gap: built_in.rs Path
No tests verify the BuiltInNetwork path with slot_duration_only: true. The validation gap in Point 3 would be caught by even a basic test.
Minor Suggestions
7. Documentation Clarity (`bin/ethlambda/src/network/mod.rs:224-240)
The doc comment says "The caller must have checked it is a non-zero multiple of 1000" but this is only true for the slot_duration_only: true branch. Consider making this explicit:
/// # Panics
/// If `slot_duration_only` is `true` and `config.slot_duration_ms` is not a non-zero
/// multiple of 1000. The `dir.rs` loader enforces this; do not call with unchecked input.
Positive Notes
- Good test coverage for the
NetworkDirpath with three distinct cases (only ms, invalid ms, neither key) - Clear documentation of the Kurtosis use case and why the raw key set matters
- Backward compatibility maintained — existing
SECONDS_PER_SLOTconfigs work unchanged - Explicit error variant
InvalidSlotDurationMswith descriptive message
Summary
| Priority | Item | Location |
|---|---|---|
| High | Add validation in built_in.rs or derive_genesis_fields |
built_in.rs:71-73, mod.rs:238 |
| Medium | Fix misleading panic message | dir.rs:350 |
| Medium | Add debug assertion for division safety | mod.rs:239 |
| Low | Consider warning on conflicting keys | config_file.rs:50 |
| Low | Extract MS_PER_SECOND constant |
multiple |
| Low | Add built_in.rs test coverage |
built_in.rs |
Automated review by Kimi (Moonshot AI) · kimi-k2.6 · custom prompt
🤖 Claude Code ReviewReview: PR 691, read
|
🤖 Codex Code ReviewLooks good overall: the change is narrowly scoped to config loading, closes a real correctness gap for generated configs that omit
One small thing to consider:
Aside from that, I don’t see bugs, security issues, or performance regressions in this diff. Automated review by OpenAI Codex · gpt-5.4 · custom prompt |
…_MS disagree When both keys are present either could be the stale one, and letting SECONDS_PER_SLOT win hid the mistake. They must now agree, otherwise startup fails naming both keys and both values. The rule moves into ConfigFile::parse (reconcile_slot_time), so built-in networks and loaded directories share it instead of dir.rs owning part of it. The devnet fixtures carried a deliberate 6 / 12000 pair to prove seconds won; they now carry 6 / 6000.
🗒️ Description / Motivation
ethlambda beacon --network <dir>ignored a config'sSLOT_DURATION_MS.derive_genesis_fieldsalways setslot_duration_ms = seconds_per_slot * 1000, andConfig's container-level serdedefaultfills a missingSECONDS_PER_SLOTwith mainnet's 12.The
config.yamlthat kurtosis' ethereum-package generates (ethereum-genesis-generator v6.2.7) carries onlySLOT_DURATION_MS, since consensus-specs droppedSECONDS_PER_SLOT. So any kurtosis devnet withseconds_per_slot != 12ran ethlambda on a 12-second clock with no error.What Changed
The slot-time rule now lives in one place,
reconcile_slot_timeinnetwork/config_file.rs, called fromConfigFile::parse. Built-in networks and loaded directories both parse through it. It reads the raw key set to tell an absent key from one holding the default:SECONDS_PER_SLOT * 1000must equalSLOT_DURATION_MS; otherwise startup fails naming both keys and valuesSLOT_DURATION_MSseconds_per_slotis derived from itSECONDS_PER_SLOTslot_duration_msderived from it (as before)network/mod.rs:derive_genesis_fieldsnow only setsgenesis_time.devnetanddevnet-electracarried a deliberate 6 / 12000 pair to prove seconds won; they now carry 6 / 6000.Correctness / Behavior Guarantees
SECONDS_PER_SLOTsilently won.Config's shape is unchanged.Tests Added / Run
config_file.rs:slot_time_keys_are_reconciled_whichever_are_present(all four combinations)dir.rs:a_config_with_only_slot_duration_ms_is_read_from_it,a_slot_duration_ms_that_is_not_whole_seconds_is_rejected_naming_the_field,a_config_with_neither_slot_key_keeps_the_mainnet_default,disagreeing_slot_keys_are_rejected_naming_both_keys_and_valuesRan
cargo fmt --all,cargo test -p ethlambda --profile release-fast --bins(231 passed) andcargo clippy --locked -p ethlambda --all-targets -- -D warnings. The workspace-widemake lint/make testwere not run locally; CI covers them.Related Issues / PRs