perf(beacon): walk the registry once in epoch steps 1-3 instead of per-index reads - #630
Draft
MegaRedHand wants to merge 2 commits into
Draft
MegaRedHand wants to merge 2 commits into
MegaRedHand wants to merge 2 commits into
Conversation
…r-index reads Justification, inactivity updates and rewards built index Vecs, then did a tree descent (state.validator(i)) per participant and a binary search per eligible validator, and the pulled-up-tip check repeats justification on every imported block. Each of those reads is a tree walk; the registry's iter() is a leaf-slice walk. Every spec function keeps its shape and signature, but now iterates validators().iter().enumerate() and indexes the flat participation and score lists by position. New helpers compute the unslashed participating balance and the total active balance (plus base reward per increment) in one pass without an index Vec; the public get_total_active_balance and get_base_reward_per_increment are untouched. The previous implementations are kept as a test-only reference, and randomized tests (altair and electra, short lists, off-grid balances, scores near the top of the range, leaking epochs) compare outputs, errors and post-step state against it.
…erf/beacon-epoch-participation-a
This was referenced Sep 30, 2026
This was referenced Oct 2, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One of three alternative implementations of the same follow-up to lambdaclass/ethlambda_private#37 (epoch participation without per-index registry reads): (a) this PR, (b) #632, (c) #633. They are meant to be compared, and at most one of (a) and (b) should merge; (c) is stacked on (b).
Motivation
Since lambdaclass/ethlambda_private#37 the registry is a persistent Merkle tree, so
state.validator(i)is a tree descent rather than an array index, whilevalidators().iter()walks leaf slices.Epoch steps 1-3 (justification, inactivity updates, rewards) built index
Vecs, then did one descent per participant and one binary search per eligible validator. The pulled-up-tip check in fork choice repeats justification on every imported block, so part of that cost is paid per block, not per epoch.Change: option (a), iterator passes, spec-shaped
Every spec function keeps its shape and signature. Each now walks
validators().iter().enumerate()and indexes the flat participation and inactivity-score lists by position:get_unslashed_participating_indicesis one pass, no descents.get_unslashed_participating_balance, plus crate-internal one-pass versions of the total active balance and the base reward per increment. The publicget_total_active_balanceandget_base_reward_per_incrementare untouched.Vec.get_flag_index_deltasandget_inactivity_penalty_deltasdecide eligibility and participation inline, with the leak flag computed once.process_inactivity_updatesmakes one immutable pass, then one pass over the scores.process_rewards_and_penaltiesis unchanged: it still builds eight deltaVecs and does 8Nget_mut. That is the known remaining cost of this option.Testing
u64::MAX, epochs 0, 1 and 2, and leaking epochs.-D warningsand theethlambda-state-transitionlib tests pass.epoch_processing,rewards,sanity,finality,random,fork_choiceandtransitionpass on both presets.Benchmark (all three options)
ethlambda benchmark import replayon ethlambda-5:cargo build --release, mainnet corpus of 128 blocks (slots 15279073..=15279200, 4 epoch-start blocks), legs interleavedbase a b cfor two rounds. Base against base: 0.996. Every leg imported all 128 blocks.stf, epoch-start block (mean of 4)stfp50, other blocksstfvs base (ratio of totals)get_headp50get_headrises asstffalls, although no option touches the head computation. This is probably contention with the background state writer, as seen in earlier import benchmarks; it is not verified. Block wall time still falls.Moved
beacon-chain-integrationlives on this repo.beacon-chain-integration@c79fabd5, merged into the branch.