/// A collection of all functions that mutates the `ProgressiveBalancesCache`. use crate::metrics::{ self, PARTICIPATION_CURR_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL, PARTICIPATION_PREV_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL, }; use crate::{BlockProcessingError, EpochProcessingError}; use metrics::set_gauge; use tracing::instrument; use types::{ BeaconState, BeaconStateError, ChainSpec, Epoch, EpochTotalBalances, EthSpec, ParticipationFlags, ProgressiveBalancesCache, Validator, is_progressive_balances_enabled, }; /// Initializes the `ProgressiveBalancesCache` if it is unbuilt. #[instrument(skip_all, level = "debug")] pub fn initialize_progressive_balances_cache( state: &mut BeaconState, spec: &ChainSpec, ) -> Result<(), BeaconStateError> { if !is_progressive_balances_enabled(state) || state.progressive_balances_cache().is_initialized() { return Ok(()); } let _timer = metrics::start_timer(&metrics::BUILD_PROGRESSIVE_BALANCES_CACHE_TIME); // Calculate the total flag balances for previous & current epoch in a single iteration. // This calculates `get_total_balance(unslashed_participating_indices(..))` for each flag in // the current and previous epoch. let current_epoch = state.current_epoch(); let previous_epoch = state.previous_epoch(); let mut previous_epoch_cache = EpochTotalBalances::new(spec); let mut current_epoch_cache = EpochTotalBalances::new(spec); for ((validator, current_epoch_flags), previous_epoch_flags) in state .validators() .iter() .zip(state.current_epoch_participation()?) .zip(state.previous_epoch_participation()?) { // Exclude slashed validators. We are calculating *unslashed* participating totals. if validator.slashed { continue; } // Update current epoch flag balances. if validator.is_active_at(current_epoch) { update_flag_total_balances(&mut current_epoch_cache, *current_epoch_flags, validator)?; } // Update previous epoch flag balances. if validator.is_active_at(previous_epoch) { update_flag_total_balances( &mut previous_epoch_cache, *previous_epoch_flags, validator, )?; } } state.progressive_balances_cache_mut().initialize( current_epoch, previous_epoch_cache, current_epoch_cache, ); update_progressive_balances_metrics(state.progressive_balances_cache())?; Ok(()) } /// During the initialization of the progressive balances for a single epoch, add /// `validator.effective_balance` to the flag total, for each flag present in `participation_flags`. /// /// Pre-conditions: /// /// - `validator` must not be slashed /// - the `participation_flags` must be for `validator` in the same epoch as the `total_balances` fn update_flag_total_balances( total_balances: &mut EpochTotalBalances, participation_flags: ParticipationFlags, validator: &Validator, ) -> Result<(), BeaconStateError> { for (flag, balance) in total_balances.total_flag_balances.iter_mut().enumerate() { if participation_flags.has_flag(flag)? { balance.safe_add_assign(validator.effective_balance)?; } } Ok(()) } /// Updates the `ProgressiveBalancesCache` when a new target attestation has been processed. pub fn update_progressive_balances_on_attestation( state: &mut BeaconState, epoch: Epoch, flag_index: usize, validator_effective_balance: u64, validator_slashed: bool, ) -> Result<(), BlockProcessingError> { if is_progressive_balances_enabled(state) { state.progressive_balances_cache_mut().on_new_attestation( epoch, validator_slashed, flag_index, validator_effective_balance, )?; } Ok(()) } /// Updates the `ProgressiveBalancesCache` when a target attester has been slashed. pub fn update_progressive_balances_on_slashing( state: &mut BeaconState, validator_index: usize, validator_effective_balance: u64, ) -> Result<(), BlockProcessingError> { if is_progressive_balances_enabled(state) { let previous_epoch_participation = *state .previous_epoch_participation()? .get(validator_index) .ok_or(BeaconStateError::UnknownValidator(validator_index))?; let current_epoch_participation = *state .current_epoch_participation()? .get(validator_index) .ok_or(BeaconStateError::UnknownValidator(validator_index))?; state.progressive_balances_cache_mut().on_slashing( previous_epoch_participation, current_epoch_participation, validator_effective_balance, )?; } Ok(()) } /// Updates the `ProgressiveBalancesCache` on epoch transition. pub fn update_progressive_balances_on_epoch_transition( state: &mut BeaconState, spec: &ChainSpec, ) -> Result<(), EpochProcessingError> { if is_progressive_balances_enabled(state) { state .progressive_balances_cache_mut() .on_epoch_transition(spec)?; update_progressive_balances_metrics(state.progressive_balances_cache())?; } Ok(()) } pub fn update_progressive_balances_metrics( cache: &ProgressiveBalancesCache, ) -> Result<(), BeaconStateError> { set_gauge( &PARTICIPATION_PREV_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL, cache.previous_epoch_target_attesting_balance()? as i64, ); set_gauge( &PARTICIPATION_CURR_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL, cache.current_epoch_target_attesting_balance()? as i64, ); Ok(()) }