Cleanup ExitCache (#1091)

* Cleanup `ExitCache`

Minor suggested cleanups after familiarising myself with the `ExitCache`.

* Remove "validators exiting/exited at a given epoch" comment in favour of the notion of exit epoch (less wishy-washy).
* Remove "or zero if not known" comment. The number of validators with that exit epoch is known, even in the case where it's zero.
* Rename `epoch` to `exit_epoch` for consistency and clarity.
* Rename `exits_per_epoch` to `exit_epoch_counts` for precision and clarity.
* Remove seemingly unnecessary complexity with `force_build`.
* Consider renaming `ExitCache` to `ExitEpochCache` for clarity.

* Update exit_cache.rs
This commit is contained in:
Justin 2020-05-18 03:59:03 +01:00 committed by GitHub
parent b6408805a2
commit ed2f0b797c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -3,41 +3,33 @@ use safe_arith::SafeArith;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
/// Map from exit epoch to the number of validators known to be exiting/exited at that epoch. /// Map from exit epoch to the number of validators with that exit epoch.
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct ExitCache { pub struct ExitCache {
initialized: bool, initialized: bool,
exits_per_epoch: HashMap<Epoch, u64>, exit_epoch_counts: HashMap<Epoch, u64>,
} }
impl ExitCache { impl ExitCache {
/// Ensure the cache is built, and do nothing if it's already initialized. /// Build the cache if not initialized.
pub fn build( pub fn build(
&mut self, &mut self,
validators: &[Validator], validators: &[Validator],
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), BeaconStateError> { ) -> Result<(), BeaconStateError> {
if self.initialized { if self.initialized {
Ok(()) return Ok(())
} else {
self.force_build(validators, spec)
}
} }
/// Add all validators with a non-trivial exit epoch to the cache.
pub fn force_build(
&mut self,
validators: &[Validator],
spec: &ChainSpec,
) -> Result<(), BeaconStateError> {
self.initialized = true; self.initialized = true;
// Add all validators with a non-default exit epoch to the cache.
validators validators
.iter() .iter()
.filter(|validator| validator.exit_epoch != spec.far_future_epoch) .filter(|validator| validator.exit_epoch != spec.far_future_epoch)
.try_for_each(|validator| self.record_validator_exit(validator.exit_epoch)) .try_for_each(|validator| self.record_validator_exit(validator.exit_epoch))
} }
/// Check that the cache is initialized and return an error if it isn't. /// Check that the cache is initialized and return an error if it is not.
pub fn check_initialized(&self) -> Result<(), BeaconStateError> { pub fn check_initialized(&self) -> Result<(), BeaconStateError> {
if self.initialized { if self.initialized {
Ok(()) Ok(())
@ -46,28 +38,26 @@ impl ExitCache {
} }
} }
/// Record the exit of a single validator in the cache. /// Record the exit epoch of a validator. Must be called only once per exiting validator.
///
/// Must only be called once per exiting validator.
pub fn record_validator_exit(&mut self, exit_epoch: Epoch) -> Result<(), BeaconStateError> { pub fn record_validator_exit(&mut self, exit_epoch: Epoch) -> Result<(), BeaconStateError> {
self.check_initialized()?; self.check_initialized()?;
self.exits_per_epoch self.exit_epoch_counts
.entry(exit_epoch) .entry(exit_epoch)
.or_insert(0) .or_insert(0)
.increment()?; .increment()?;
Ok(()) Ok(())
} }
/// Get the greatest epoch for which validator exits are known. /// Get the largest exit epoch with a non-zero exit epoch count.
pub fn max_epoch(&self) -> Result<Option<Epoch>, BeaconStateError> { pub fn max_epoch(&self) -> Result<Option<Epoch>, BeaconStateError> {
self.check_initialized()?; self.check_initialized()?;
Ok(self.exits_per_epoch.keys().max().cloned()) Ok(self.exit_epoch_counts.keys().max().cloned())
} }
/// Get the number of validators exiting/exited at a given epoch, or zero if not known. /// Get number of validators with the given exit epoch. (Return 0 for the default exit epoch.)
pub fn get_churn_at(&self, epoch: Epoch) -> Result<u64, BeaconStateError> { pub fn get_churn_at(&self, exit_epoch: Epoch) -> Result<u64, BeaconStateError> {
self.check_initialized()?; self.check_initialized()?;
Ok(self.exits_per_epoch.get(&epoch).cloned().unwrap_or(0)) Ok(self.exit_epoch_counts.get(&exit_epoch).cloned().unwrap_or(0))
} }
} }