From c451ae763c975058cde26f4a50b5e1d1c9665163 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 24 Mar 2026 12:43:19 +1100 Subject: [PATCH] Use BTreeMap for state.validators pending updates (#9017) Closes: - https://github.com/sigp/lighthouse/issues/9003 Milhouse `List`s use a map in front of the binary tree to cache updates. Ever since we adopted Milhouse, we've been using `VecMap`, which is essentially `Vec>`. Turns out, when you've got 2M indices and only 2 non-`None` entries (changes), this is inefficient. Milhouse is generic in the choice of map (`U: UpdateMap`) and has always supported `BTreeMap`, so this PR switches us over to `BTreeMap`. In previous benchmarks (years ago) it had been slower than `VecMap`, but now it is vastly superior. Co-Authored-By: Michael Sproul --- .../src/per_epoch_processing/epoch_processing_summary.rs | 6 +++--- consensus/types/src/state/beacon_state.rs | 6 ++++-- consensus/types/src/state/mod.rs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/consensus/state_processing/src/per_epoch_processing/epoch_processing_summary.rs b/consensus/state_processing/src/per_epoch_processing/epoch_processing_summary.rs index a818e08775..3c043a65f2 100644 --- a/consensus/state_processing/src/per_epoch_processing/epoch_processing_summary.rs +++ b/consensus/state_processing/src/per_epoch_processing/epoch_processing_summary.rs @@ -4,8 +4,8 @@ use milhouse::List; use std::sync::Arc; use types::{ BeaconStateError, Epoch, EthSpec, ParticipationFlags, ProgressiveBalancesCache, SyncCommittee, - Validator, consts::altair::{TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX}, + state::Validators, }; /// Provides a summary of validator participation during the epoch. @@ -26,7 +26,7 @@ pub enum EpochProcessingSummary { #[derive(PartialEq, Debug)] pub struct ParticipationEpochSummary { /// Copy of the validator registry prior to mutation. - validators: List, + validators: Validators, /// Copy of the participation flags for the previous epoch. previous_epoch_participation: List, /// Copy of the participation flags for the current epoch. @@ -37,7 +37,7 @@ pub struct ParticipationEpochSummary { impl ParticipationEpochSummary { pub fn new( - validators: List, + validators: Validators, previous_epoch_participation: List, current_epoch_participation: List, previous_epoch: Epoch, diff --git a/consensus/types/src/state/beacon_state.rs b/consensus/types/src/state/beacon_state.rs index 3f8fa4cfff..9c7b8285d4 100644 --- a/consensus/types/src/state/beacon_state.rs +++ b/consensus/types/src/state/beacon_state.rs @@ -14,6 +14,7 @@ use serde::{Deserialize, Deserializer, Serialize}; use ssz::{Decode, DecodeError, Encode, ssz_encode}; use ssz_derive::{Decode, Encode}; use ssz_types::{BitVector, FixedVector}; +use std::collections::BTreeMap; use superstruct::superstruct; use swap_or_not_shuffle::compute_shuffled_index; use test_random_derive::TestRandom; @@ -58,7 +59,8 @@ pub const CACHED_EPOCHS: usize = 3; const MAX_RANDOM_BYTE: u64 = (1 << 8) - 1; const MAX_RANDOM_VALUE: u64 = (1 << 16) - 1; -pub type Validators = List::ValidatorRegistryLimit>; +pub type Validators = + List::ValidatorRegistryLimit, BTreeMap>; pub type Balances = List::ValidatorRegistryLimit>; #[derive(Debug, PartialEq, Clone)] @@ -453,7 +455,7 @@ where // Registry #[compare_fields(as_iter)] #[test_random(default)] - pub validators: List, + pub validators: Validators, #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")] #[compare_fields(as_iter)] #[test_random(default)] diff --git a/consensus/types/src/state/mod.rs b/consensus/types/src/state/mod.rs index 309796d359..321c66671a 100644 --- a/consensus/types/src/state/mod.rs +++ b/consensus/types/src/state/mod.rs @@ -17,7 +17,7 @@ pub use balance::Balance; pub use beacon_state::{ BeaconState, BeaconStateAltair, BeaconStateBase, BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, BeaconStateElectra, BeaconStateError, BeaconStateFulu, BeaconStateGloas, - BeaconStateHash, BeaconStateRef, CACHED_EPOCHS, + BeaconStateHash, BeaconStateRef, CACHED_EPOCHS, Validators, }; pub use committee_cache::{ CommitteeCache, compute_committee_index_in_epoch, compute_committee_range_in_epoch,