Skip to content

Commit

Permalink
Mutate state via mini beacon state in epoch processing
Browse files Browse the repository at this point in the history
  • Loading branch information
realbigsean committed May 3, 2022
1 parent 5cae2f9 commit 6c7ab85
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 54 deletions.
1 change: 1 addition & 0 deletions beacon_node/store/src/partial_beacon_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ macro_rules! impl_try_into_beacon_state {
pubkey_cache: <_>::default(),
exit_cache: <_>::default(),
tree_hash_cache: <_>::default(),
previous_epoch_participation_cache: <_>::default(),

// Variant-specific fields
$(
Expand Down
14 changes: 8 additions & 6 deletions consensus/state_processing/src/per_epoch_processing/altair.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use itertools::min;
use super::{EpochProcessingSummary, Error, process_registry_updates, process_slashings};
use crate::per_epoch_processing::{
effective_balance_updates::process_effective_balance_updates,
Expand All @@ -10,7 +11,7 @@ pub use types::beacon_state::participation_cache::ParticipationCache;
pub use participation_flag_updates::process_participation_flag_updates;
pub use rewards_and_penalties::process_rewards_and_penalties;
pub use sync_committee_updates::process_sync_committee_updates;
use types::{BeaconState, ChainSpec, EthSpec, RelativeEpoch};
use types::{BeaconState, ChainSpec, EthSpec, MiniBeaconState, RelativeEpoch};
use types::beacon_state::participation_cache::CurrentEpochParticipationCache;

pub mod inactivity_updates;
Expand All @@ -26,7 +27,8 @@ pub fn process_epoch<T: EthSpec>(

state.build_committee_cache(RelativeEpoch::Next, spec)?;

let participation_cache = process_justifiable(state, spec)?;
let (mini_beacon_state, participation_cache) = process_justifiable(state, spec)?;
state.update_justifiable(mini_beacon_state);

let sync_committee = state.current_sync_committee()?.clone();

Expand Down Expand Up @@ -74,8 +76,8 @@ pub fn process_epoch<T: EthSpec>(
})
}

pub fn process_justifiable<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainSpec) -> Result<ParticipationCache, Error> {
// Ensure the committee caches are built.
pub fn process_justifiable<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainSpec) -> Result<(MiniBeaconState<T>, ParticipationCache), Error> {
// Ensure the committee caches are built.
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
state.build_committee_cache(RelativeEpoch::Current, spec)?;

Expand All @@ -87,7 +89,7 @@ pub fn process_justifiable<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainS
let participation_cache = ParticipationCache::new(prev_participation_cache, current_participation_cache);

// Justification and finalization.
process_justification_and_finalization(state, &participation_cache)?;
let mini_beacon_state = process_justification_and_finalization(state, &participation_cache)?;

Ok(participation_cache)
Ok((mini_beacon_state, participation_cache))
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ use crate::per_epoch_processing::weigh_justification_and_finalization;
use crate::per_epoch_processing::Error;
use safe_arith::SafeArith;
use types::consts::altair::TIMELY_TARGET_FLAG_INDEX;
use types::{BeaconState, EthSpec};
use types::{BeaconState, EthSpec, MiniBeaconState};
use types::beacon_state::participation_cache::CurrentEpochParticipationCache;

/// Update the justified and finalized checkpoints for matching target attestations.
pub fn process_justification_and_finalization<T: EthSpec>(
state: &mut BeaconState<T>,
state: &BeaconState<T>,
participation_cache: &ParticipationCache,
) -> Result<(), Error> {
) -> Result<MiniBeaconState<T>, Error> {
if state.current_epoch() <= T::genesis_epoch().safe_add(1)? {
return Ok(());
return Ok(MiniBeaconState {
current_justified_checkpoint: state.current_justified_checkpoint(),
previous_justified_checkpoint: state.previous_justified_checkpoint(),
justification_bits: state.justification_bits().clone(),
finalized_checkpoint: state.finalized_checkpoint(),
});
}

let previous_epoch = state.previous_epoch();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ pub fn process_justification_and_finalization<T: EthSpec>(
return Ok(());
}

weigh_justification_and_finalization(
let mini_beacon_state = weigh_justification_and_finalization(
state,
total_balances.current_epoch(),
total_balances.previous_epoch_target_attesters(),
total_balances.current_epoch_target_attesters(),
)
)?;
state.update_justifiable(mini_beacon_state);

Ok(())
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,50 @@
use crate::per_epoch_processing::Error;
use safe_arith::SafeArith;
use std::ops::Range;
use types::{BeaconState, Checkpoint, EthSpec};
use types::{BeaconState, Checkpoint, EthSpec, MiniBeaconState};

/// Update the justified and finalized checkpoints for matching target attestations.
#[allow(clippy::if_same_then_else)] // For readability and consistency with spec.
pub fn weigh_justification_and_finalization<T: EthSpec>(
state: &mut BeaconState<T>,
state: &BeaconState<T>,
total_active_balance: u64,
previous_target_balance: u64,
current_target_balance: u64,
) -> Result<(), Error> {
) -> Result<MiniBeaconState<T>, Error> {
let previous_epoch = state.previous_epoch();
let current_epoch = state.current_epoch();

let old_previous_justified_checkpoint = state.previous_justified_checkpoint();
let old_current_justified_checkpoint = state.current_justified_checkpoint();

let mut mini_beacon_state = MiniBeaconState {
current_justified_checkpoint: state.current_justified_checkpoint(),
previous_justified_checkpoint: state.previous_justified_checkpoint(),
justification_bits: state.justification_bits().clone(),
finalized_checkpoint: state.finalized_checkpoint(),
};

// Process justifications
*state.previous_justified_checkpoint_mut() = state.current_justified_checkpoint();
state.justification_bits_mut().shift_up(1)?;
mini_beacon_state.previous_justified_checkpoint = mini_beacon_state.current_justified_checkpoint;
mini_beacon_state.justification_bits.shift_up(1)?;

if previous_target_balance.safe_mul(3)? >= total_active_balance.safe_mul(2)? {
*state.current_justified_checkpoint_mut() = Checkpoint {
mini_beacon_state.current_justified_checkpoint = Checkpoint {
epoch: previous_epoch,
root: *state.get_block_root_at_epoch(previous_epoch)?,
};
state.justification_bits_mut().set(1, true)?;
mini_beacon_state.justification_bits.set(1, true)?;
}
// If the current epoch gets justified, fill the last bit.
if current_target_balance.safe_mul(3)? >= total_active_balance.safe_mul(2)? {
*state.current_justified_checkpoint_mut() = Checkpoint {
mini_beacon_state.current_justified_checkpoint = Checkpoint {
epoch: current_epoch,
root: *state.get_block_root_at_epoch(current_epoch)?,
};
state.justification_bits_mut().set(0, true)?;
mini_beacon_state.justification_bits.set(0, true)?;
}

let bits = state.justification_bits().clone();
let bits = mini_beacon_state.justification_bits.clone();
let all_bits_set = |range: Range<usize>| -> Result<bool, Error> {
for i in range {
if !bits.get(i).map_err(Error::InvalidJustificationBit)? {
Expand All @@ -50,21 +57,21 @@ pub fn weigh_justification_and_finalization<T: EthSpec>(
// The 2nd/3rd/4th most recent epochs are all justified, the 2nd using the 4th as source.
if all_bits_set(1..4)? && old_previous_justified_checkpoint.epoch.safe_add(3)? == current_epoch
{
*state.finalized_checkpoint_mut() = old_previous_justified_checkpoint;
mini_beacon_state.finalized_checkpoint = old_previous_justified_checkpoint;
}
// The 2nd/3rd most recent epochs are both justified, the 2nd using the 3rd as source.
if all_bits_set(1..3)? && old_previous_justified_checkpoint.epoch.safe_add(2)? == current_epoch
{
*state.finalized_checkpoint_mut() = old_previous_justified_checkpoint;
mini_beacon_state.finalized_checkpoint = old_previous_justified_checkpoint;
}
// The 1st/2nd/3rd most recent epochs are all justified, the 1st using the 3nd as source.
if all_bits_set(0..3)? && old_current_justified_checkpoint.epoch.safe_add(2)? == current_epoch {
*state.finalized_checkpoint_mut() = old_current_justified_checkpoint;
mini_beacon_state.finalized_checkpoint = old_current_justified_checkpoint;
}
// The 1st/2nd most recent epochs are both justified, the 1st using the 2nd as source.
if all_bits_set(0..2)? && old_current_justified_checkpoint.epoch.safe_add(1)? == current_epoch {
*state.finalized_checkpoint_mut() = old_current_justified_checkpoint;
mini_beacon_state.finalized_checkpoint = old_current_justified_checkpoint;
}

Ok(())
Ok(mini_beacon_state)
}
32 changes: 25 additions & 7 deletions consensus/types/src/beacon_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ where
#[tree_hash(skip_hashing)]
#[test_random(default)]
#[derivative(Clone(clone_with = "clone_default"))]
pub previous_epoch_participation_cache: PreviousParticipationCache,
pub previous_epoch_participation_cache: Option<PreviousParticipationCache>,
}

impl<T: EthSpec> Clone for BeaconState<T> {
Expand Down Expand Up @@ -1359,16 +1359,24 @@ impl<T: EthSpec> BeaconState<T> {
self.drop_pubkey_cache();
self.drop_tree_hash_cache();
*self.exit_cache_mut() = ExitCache::default();
*self.previous_epoch_participation_cache_mut() = None;
Ok(())
}

pub fn get_previous_epoch_participation_cache(&mut self, spec: &ChainSpec) -> Result<&PreviousParticipationCache, BeaconStateError> {
if self.previous_epoch_participation_cache().previous_epoch() == self.slot().epoch(T::slots_per_epoch()) - 1 {
Ok(&self.previous_epoch_participation_cache())
pub fn get_previous_epoch_participation_cache(&mut self, spec: &ChainSpec) -> Result<PreviousParticipationCache, BeaconStateError> {
if let Some(cache) = self.previous_epoch_participation_cache() {
if cache.initialized_epoch() == self.current_epoch() {
Ok(cache.clone())
} else {
// rebuild cache
let cache = PreviousParticipationCache::new(self, spec)?;
*self.previous_epoch_participation_cache_mut() = Some(cache.clone());
Ok(cache)
}
} else {
//rebuild cache
*self.previous_epoch_participation_cache_mut() = PreviousParticipationCache::new(self, spec)?;
Ok(&self.previous_epoch_participation_cache())
let cache = PreviousParticipationCache::new(self, spec)?;
*self.previous_epoch_participation_cache_mut() = Some(cache.clone());
Ok(cache)
}
}

Expand Down Expand Up @@ -1655,6 +1663,16 @@ impl<T: EthSpec> BeaconState<T> {
};
Ok(sync_committee)
}

pub fn update_justifiable(
&mut self,
mini_beacon_state: MiniBeaconState<T>,
) {
*self.current_justified_checkpoint_mut() = mini_beacon_state.current_justified_checkpoint;
*self.previous_justified_checkpoint_mut() = mini_beacon_state.previous_justified_checkpoint;
*self.finalized_checkpoint_mut() = mini_beacon_state.finalized_checkpoint;
*self.justification_bits_mut() = mini_beacon_state.justification_bits;
}
}

impl From<RelativeEpochError> for Error {
Expand Down
16 changes: 9 additions & 7 deletions consensus/types/src/beacon_state/participation_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,9 @@ impl SingleEpochParticipationCache {
}

/// Maintains a cache to be used during `altair::process_epoch`.
#[derive(PartialEq, Default, Debug)]
#[derive(Clone, PartialEq, Default, Debug)]
pub struct PreviousParticipationCache {
initialized_epoch: Epoch,
previous_epoch: Epoch,
/// Caches information about active validators pertaining to `self.previous_epoch`.
previous_epoch_participation: SingleEpochParticipationCache,
Expand Down Expand Up @@ -230,14 +231,15 @@ impl PreviousParticipationCache {
}

Ok(Self {
initialized_epoch: state.current_epoch(),
previous_epoch,
previous_epoch_participation,
eligible_indices,
})
}

pub fn previous_epoch(&self) -> Epoch {
self.previous_epoch
pub fn initialized_epoch(&self) -> Epoch {
self.initialized_epoch
}
}

Expand Down Expand Up @@ -331,13 +333,13 @@ pub struct ParticipationCache {
}

impl ParticipationCache {
pub fn new(prev_cache: &PreviousParticipationCache, current_cache: CurrentEpochParticipationCache) -> ParticipationCache {
pub fn new(prev_cache: PreviousParticipationCache, current_cache: CurrentEpochParticipationCache) -> ParticipationCache {
ParticipationCache {
current_epoch: current_cache.current_epoch,
current_epoch_participation: current_cache.current_epoch_participation,
previous_epoch: prev_cache.previous_epoch,
previous_epoch_participation: prev_cache.previous_epoch_participation.clone(),
eligible_indices: prev_cache.eligible_indices.clone(),
previous_epoch_participation: prev_cache.previous_epoch_participation,
eligible_indices: prev_cache.eligible_indices,
}
}

Expand All @@ -361,7 +363,7 @@ impl ParticipationCache {
};

Ok(UnslashedParticipatingIndices {
participation: &self.previous_epoch_participation,
participation,
flag_index,
})
}
Expand Down
8 changes: 8 additions & 0 deletions consensus/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,11 @@ pub use bls::{
};
pub use ssz_types::{typenum, typenum::Unsigned, BitList, BitVector, FixedVector, VariableList};
pub use superstruct::superstruct;


pub struct MiniBeaconState<T: EthSpec> {
pub current_justified_checkpoint: Checkpoint,
pub previous_justified_checkpoint: Checkpoint,
pub justification_bits: BitVector<T::JustificationBitsLength>,
pub finalized_checkpoint: Checkpoint,
}
34 changes: 23 additions & 11 deletions testing/ef_tests/src/cases/epoch_processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use state_processing::EpochProcessingError;
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
use types::{BeaconState, ChainSpec, EthSpec, ForkName};
use types::participation_cache::{CurrentEpochParticipationCache, PreviousParticipationCache};

#[derive(Debug, Clone, Default, Deserialize)]
pub struct Metadata {
Expand Down Expand Up @@ -95,10 +96,14 @@ impl<E: EthSpec> EpochTransition<E> for JustificationAndFinalization {
)
}
BeaconState::Altair(_) | BeaconState::Merge(_) => {
altair::process_justification_and_finalization(
let prev_participation_cache = state.get_previous_epoch_participation_cache(spec)?;
let current_participation_cache = CurrentEpochParticipationCache::new(state, spec)?;
let mini_beacon_state = altair::process_justification_and_finalization(
state,
&altair::ParticipationCache::new(state, spec).unwrap(),
)
&altair::ParticipationCache::new(prev_participation_cache, current_participation_cache),
)?;
state.update_justifiable(mini_beacon_state);
Ok(())
}
}
}
Expand All @@ -113,9 +118,11 @@ impl<E: EthSpec> EpochTransition<E> for RewardsAndPenalties {
base::process_rewards_and_penalties(state, &mut validator_statuses, spec)
}
BeaconState::Altair(_) | BeaconState::Merge(_) => {
let prev_participation_cache = state.get_previous_epoch_participation_cache(spec)?;
let current_participation_cache = CurrentEpochParticipationCache::new(state, spec)?;
altair::process_rewards_and_penalties(
state,
&altair::ParticipationCache::new(state, spec).unwrap(),
&altair::ParticipationCache::new(prev_participation_cache, current_participation_cache),
spec,
)
}
Expand All @@ -142,10 +149,11 @@ impl<E: EthSpec> EpochTransition<E> for Slashings {
)?;
}
BeaconState::Altair(_) | BeaconState::Merge(_) => {
let prev_participation_cache = PreviousParticipationCache::new(state, spec)?;
let current_participation_cache = CurrentEpochParticipationCache::new(state, spec)?;
process_slashings(
state,
altair::ParticipationCache::new(state, spec)
.unwrap()
altair::ParticipationCache::new(prev_participation_cache, current_participation_cache)
.current_epoch_total_active_balance(),
spec,
)?;
Expand Down Expand Up @@ -210,11 +218,15 @@ impl<E: EthSpec> EpochTransition<E> for InactivityUpdates {
fn run(state: &mut BeaconState<E>, spec: &ChainSpec) -> Result<(), EpochProcessingError> {
match state {
BeaconState::Base(_) => Ok(()),
BeaconState::Altair(_) | BeaconState::Merge(_) => altair::process_inactivity_updates(
state,
&altair::ParticipationCache::new(state, spec).unwrap(),
spec,
),
BeaconState::Altair(_) | BeaconState::Merge(_) => {
let prev_participation_cache = PreviousParticipationCache::new(state, spec)?;
let current_participation_cache = CurrentEpochParticipationCache::new(state, spec)?;
altair::process_inactivity_updates(
state,
&altair::ParticipationCache::new(prev_participation_cache, current_participation_cache),
spec,
)
},
}
}
}
Expand Down
Loading

0 comments on commit 6c7ab85

Please sign in to comment.