1+ //! Provides the `ParticipationCache`, a custom Lighthouse cache which attempts to reduce CPU and
2+ //! memory usage by:
3+ //!
4+ //! - Caching a map of `validator_index -> participation_flags` for all active validators in the
5+ //! previous and current epochs.
6+ //! - Caching the total balances of:
7+ //! - All active validators.
8+ //! - All active validators matching each of the three "timely" flags.
9+ //! - Caching the "eligible" validators.
10+ //!
11+ //! Additionally, this cache is returned from the `altair::process_epoch` function and can be used
12+ //! to get useful summaries about the validator participation in an epoch.
13+
114use safe_arith:: { ArithError , SafeArith } ;
215use std:: collections:: HashMap ;
316use types:: {
@@ -8,34 +21,56 @@ use types::{
821 BeaconState , BeaconStateError , ChainSpec , Epoch , EthSpec , ParticipationFlags , RelativeEpoch ,
922} ;
1023
24+ /// A balance which will never be below the specified `minimum`.
25+ ///
26+ /// This is an attempt to ensure the `EFFECTIVE_BALANCE_INCREMENT` minimum is always respected.
1127#[ derive( PartialEq , Debug , Clone , Copy ) ]
1228struct Balance {
1329 raw : u64 ,
1430 minimum : u64 ,
1531}
1632
1733impl Balance {
34+ /// Initialize the balance to `0`, or the given `minimum`.
1835 pub fn zero ( minimum : u64 ) -> Self {
1936 Self { raw : 0 , minimum }
2037 }
2138
39+ /// Returns the balance with respect to the initialization `minimum`.
2240 pub fn get ( & self ) -> u64 {
2341 std:: cmp:: max ( self . raw , self . minimum )
2442 }
2543
44+ /// Add-assign to the balance.
2645 pub fn safe_add_assign ( & mut self , other : u64 ) -> Result < ( ) , ArithError > {
2746 self . raw . safe_add_assign ( other)
2847 }
2948}
3049
50+ /// Caches the participation values for one epoch (either the previous or current).
3151#[ derive( PartialEq , Debug ) ]
32- struct EpochParticipation {
52+ struct SingleEpochParticipationCache {
53+ /// Maps an active validator index to their participation flags.
54+ ///
55+ /// To reiterate, only active validator indices are stored in this map.
56+ ///
57+ /// ## Note
58+ ///
59+ /// It would be ideal to maintain a reference to the `BeaconState` here rather than copying the
60+ /// `ParticipationFlags`, however that would cause us to run into mutable reference limitations
61+ /// upstream.
3362 unslashed_participating_indices : HashMap < usize , ParticipationFlags > ,
63+ /// Stores the sum of the balances for all validators in `self.unslashed_participating_indices`
64+ /// for all flags in `NUM_FLAG_INDICES`.
65+ ///
66+ /// A flag balance is only incremented if a validator is that flag set.
3467 total_flag_balances : [ Balance ; NUM_FLAG_INDICES ] ,
68+ /// Stores the sum of all balances of all validators in `self.unslashed_participating_indices`
69+ /// (regardless of which flags are set).
3570 total_active_balance : Balance ,
3671}
3772
38- impl EpochParticipation {
73+ impl SingleEpochParticipationCache {
3974 pub fn new ( hashmap_len : usize , spec : & ChainSpec ) -> Self {
4075 let zero_balance = Balance :: zero ( spec. effective_balance_increment ) ;
4176
@@ -46,20 +81,32 @@ impl EpochParticipation {
4681 }
4782 }
4883
84+ /// Process an **active** validator.
85+ ///
86+ /// ## Errors
87+ ///
88+ /// - The provided `state` **must** be Altair, otherwise an error will be returned.
89+ ///
90+ /// ## Warning
91+ ///
92+ /// - It is a logic error to provide an inactive validator to this function.
4993 pub fn process_active_validator < T : EthSpec > (
5094 & mut self ,
5195 val_index : usize ,
5296 state : & BeaconState < T > ,
5397 epoch_participation : & [ ParticipationFlags ] ,
5498 ) -> Result < ( ) , BeaconStateError > {
5599 let val_balance = state. get_effective_balance ( val_index) ?;
100+
101+ // All active validator increase the total active balance.
56102 self . total_active_balance . safe_add_assign ( val_balance) ?;
57103
58104 if state. get_validator ( val_index) ?. slashed {
59105 return Ok ( ( ) ) ;
60106 }
61107
62- // Iterate through all the flags and increment total balances.
108+ // Iterate through all the flags and increment the total flag balances for whichever flags
109+ // are set for `val_index`.
63110 self . total_flag_balances
64111 . iter_mut ( )
65112 . enumerate ( )
@@ -87,16 +134,25 @@ impl EpochParticipation {
87134 }
88135}
89136
137+ /// Maintains a cache to be used during `altair::process_epoch`.
90138#[ derive( PartialEq , Debug ) ]
91139pub struct ParticipationCache {
92140 current_epoch : Epoch ,
93- current_epoch_participation : EpochParticipation ,
141+ /// Caches information about active validators pertaining to `self.current_epoch`.
142+ current_epoch_participation : SingleEpochParticipationCache ,
94143 previous_epoch : Epoch ,
95- previous_epoch_participation : EpochParticipation ,
144+ /// Caches information about active validators pertaining to `self.previous_epoch`.
145+ previous_epoch_participation : SingleEpochParticipationCache ,
146+ /// Caches the result of the `get_eligible_validator_indices` function.
96147 eligible_indices : Vec < usize > ,
97148}
98149
99150impl ParticipationCache {
151+ /// Instantiate `Self`, returning a cache that is fully initialized and ready-to-go.
152+ ///
153+ /// ## Errors
154+ ///
155+ /// - The provided `state` **must** be an Altair state, otherwise an error will be returned.
100156 pub fn new < T : EthSpec > (
101157 state : & BeaconState < T > ,
102158 spec : & ChainSpec ,
@@ -112,10 +168,10 @@ impl ParticipationCache {
112168 . len ( ) ;
113169
114170 let mut current_epoch_participation =
115- EpochParticipation :: new ( num_current_epoch_active_vals, spec) ;
171+ SingleEpochParticipationCache :: new ( num_current_epoch_active_vals, spec) ;
116172 let mut previous_epoch_participation =
117- EpochParticipation :: new ( num_previous_epoch_active_vals, spec) ;
118- let mut eligible_indices = Vec :: with_capacity ( state . validators ( ) . len ( ) ) ;
173+ SingleEpochParticipationCache :: new ( num_previous_epoch_active_vals, spec) ;
174+ let mut eligible_indices = Vec :: with_capacity ( num_previous_epoch_active_vals ) ;
119175
120176 for ( val_index, val) in state. validators ( ) . iter ( ) . enumerate ( ) {
121177 if val. is_active_at ( current_epoch) {
@@ -139,8 +195,6 @@ impl ParticipationCache {
139195 }
140196 }
141197
142- eligible_indices. shrink_to_fit ( ) ;
143-
144198 Ok ( Self {
145199 current_epoch,
146200 current_epoch_participation,
@@ -150,6 +204,7 @@ impl ParticipationCache {
150204 } )
151205 }
152206
207+ /// Equivalent to the specification `get_eligible_validator_indices` function.
153208 pub fn eligible_validator_indices ( & self ) -> & [ usize ] {
154209 & self . eligible_indices
155210 }
@@ -182,6 +237,7 @@ impl ParticipationCache {
182237 self . current_epoch_participation . total_active_balance . get ( )
183238 }
184239
240+ /// Equivalent to the `get_unslashed_participating_indices` function in the specification.
185241 pub fn get_unslashed_participating_indices (
186242 & self ,
187243 flag_index : usize ,
@@ -254,12 +310,20 @@ impl ParticipationCache {
254310 }
255311}
256312
313+ /// Imitates the return value of the `get_unslashed_participating_indices` in the
314+ /// specification.
315+ ///
316+ /// This struct exists to help make the Lighthouse code read more like the specification.
257317pub struct UnslashedParticipatingIndices < ' a > {
258- participation : & ' a EpochParticipation ,
318+ participation : & ' a SingleEpochParticipationCache ,
259319 flag_index : usize ,
260320}
261321
262322impl < ' a > UnslashedParticipatingIndices < ' a > {
323+ /// Returns `Ok(true)` if the given `val_index` is:
324+ ///
325+ /// - An active validator.
326+ /// - Has `self.flag_index` set.
263327 pub fn contains ( & self , val_index : usize ) -> Result < bool , ArithError > {
264328 self . participation
265329 . unslashed_participating_indices
@@ -268,6 +332,11 @@ impl<'a> UnslashedParticipatingIndices<'a> {
268332 . unwrap_or ( Ok ( false ) )
269333 }
270334
335+ /// Returns the sum of all balances of validators which have `self.flag_index` set.
336+ ///
337+ /// ## Notes
338+ ///
339+ /// Respects the `EFFECTIVE_BALANCE_INCREMENT` minimum.
271340 pub fn total_balance ( & self ) -> Result < u64 , BeaconStateError > {
272341 self . participation
273342 . total_flag_balances
0 commit comments