mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-18 05:18:30 +00:00
Single-pass epoch processing (#4483)
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
use self::committee_cache::get_active_validator_indices;
|
||||
use self::exit_cache::ExitCache;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::validator::ValidatorTrait;
|
||||
use crate::*;
|
||||
@@ -29,7 +28,9 @@ pub use self::committee_cache::{
|
||||
CommitteeCache,
|
||||
};
|
||||
pub use crate::beacon_state::balance::Balance;
|
||||
pub use crate::beacon_state::exit_cache::ExitCache;
|
||||
pub use crate::beacon_state::progressive_balances_cache::*;
|
||||
pub use crate::beacon_state::slashings_cache::SlashingsCache;
|
||||
use crate::epoch_cache::EpochCache;
|
||||
use crate::historical_summary::HistoricalSummary;
|
||||
pub use eth_spec::*;
|
||||
@@ -44,6 +45,7 @@ mod exit_cache;
|
||||
mod iter;
|
||||
mod progressive_balances_cache;
|
||||
mod pubkey_cache;
|
||||
mod slashings_cache;
|
||||
mod tests;
|
||||
|
||||
pub const CACHED_EPOCHS: usize = 3;
|
||||
@@ -103,6 +105,10 @@ pub enum Error {
|
||||
},
|
||||
RelativeEpochError(RelativeEpochError),
|
||||
ExitCacheUninitialized,
|
||||
SlashingsCacheUninitialized {
|
||||
initialized_slot: Option<Slot>,
|
||||
latest_block_slot: Slot,
|
||||
},
|
||||
CommitteeCacheUninitialized(Option<RelativeEpoch>),
|
||||
SyncCommitteeCacheUninitialized,
|
||||
BlsError(bls::Error),
|
||||
@@ -153,6 +159,7 @@ pub enum Error {
|
||||
TotalActiveBalanceDiffUninitialized,
|
||||
MissingImmutableValidator(usize),
|
||||
IndexNotSupported(usize),
|
||||
InvalidFlagIndex(usize),
|
||||
MerkleTreeError(merkle_proof::MerkleTreeError),
|
||||
}
|
||||
|
||||
@@ -449,6 +456,12 @@ where
|
||||
#[test_random(default)]
|
||||
#[metastruct(exclude)]
|
||||
pub exit_cache: ExitCache,
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
#[ssz(skip_serializing, skip_deserializing)]
|
||||
#[tree_hash(skip_hashing)]
|
||||
#[test_random(default)]
|
||||
#[metastruct(exclude)]
|
||||
pub slashings_cache: SlashingsCache,
|
||||
/// Epoch cache of values that are useful for block processing that are static over an epoch.
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
#[ssz(skip_serializing, skip_deserializing)]
|
||||
@@ -516,6 +529,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
],
|
||||
pubkey_cache: PubkeyCache::default(),
|
||||
exit_cache: ExitCache::default(),
|
||||
slashings_cache: SlashingsCache::default(),
|
||||
epoch_cache: EpochCache::default(),
|
||||
})
|
||||
}
|
||||
@@ -1301,6 +1315,57 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn mutable_validator_fields(
|
||||
&mut self,
|
||||
) -> Result<
|
||||
(
|
||||
&mut Validators<T>,
|
||||
&mut Balances<T>,
|
||||
&VList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
&VList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
&mut VList<u64, T::ValidatorRegistryLimit>,
|
||||
&mut ProgressiveBalancesCache,
|
||||
&mut ExitCache,
|
||||
&mut EpochCache,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
match self {
|
||||
BeaconState::Base(_) => Err(Error::IncorrectStateVariant),
|
||||
BeaconState::Altair(state) => Ok((
|
||||
&mut state.validators,
|
||||
&mut state.balances,
|
||||
&state.previous_epoch_participation,
|
||||
&state.current_epoch_participation,
|
||||
&mut state.inactivity_scores,
|
||||
&mut state.progressive_balances_cache,
|
||||
&mut state.exit_cache,
|
||||
&mut state.epoch_cache,
|
||||
)),
|
||||
BeaconState::Merge(state) => Ok((
|
||||
&mut state.validators,
|
||||
&mut state.balances,
|
||||
&state.previous_epoch_participation,
|
||||
&state.current_epoch_participation,
|
||||
&mut state.inactivity_scores,
|
||||
&mut state.progressive_balances_cache,
|
||||
&mut state.exit_cache,
|
||||
&mut state.epoch_cache,
|
||||
)),
|
||||
BeaconState::Capella(state) => Ok((
|
||||
&mut state.validators,
|
||||
&mut state.balances,
|
||||
&state.previous_epoch_participation,
|
||||
&state.current_epoch_participation,
|
||||
&mut state.inactivity_scores,
|
||||
&mut state.progressive_balances_cache,
|
||||
&mut state.exit_cache,
|
||||
&mut state.epoch_cache,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the balance of a single validator.
|
||||
pub fn get_balance_mut(&mut self, validator_index: usize) -> Result<&mut u64, Error> {
|
||||
self.balances_mut()
|
||||
@@ -1400,7 +1465,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
epoch: Epoch,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Epoch, Error> {
|
||||
Ok(epoch.safe_add(1)?.safe_add(spec.max_seed_lookahead)?)
|
||||
Ok(spec.compute_activation_exit_epoch(epoch)?)
|
||||
}
|
||||
|
||||
/// Return the churn limit for the current epoch (number of validators who can leave per epoch).
|
||||
@@ -1574,6 +1639,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
self.build_all_committee_caches(spec)?;
|
||||
self.update_pubkey_cache()?;
|
||||
self.build_exit_cache(spec)?;
|
||||
self.build_slashings_cache()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1594,6 +1660,20 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Build the slashings cache if it needs to be built.
|
||||
pub fn build_slashings_cache(&mut self) -> Result<(), Error> {
|
||||
let latest_block_slot = self.latest_block_header().slot;
|
||||
if !self.slashings_cache().is_initialized(latest_block_slot) {
|
||||
*self.slashings_cache_mut() = SlashingsCache::new(latest_block_slot, self.validators());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn slashings_cache_is_initialized(&self) -> bool {
|
||||
let latest_block_slot = self.latest_block_header().slot;
|
||||
self.slashings_cache().is_initialized(latest_block_slot)
|
||||
}
|
||||
|
||||
/// Drop all caches on the state.
|
||||
pub fn drop_all_caches(&mut self) -> Result<(), Error> {
|
||||
self.drop_total_active_balance_cache();
|
||||
@@ -1603,6 +1683,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
self.drop_pubkey_cache();
|
||||
self.drop_progressive_balances_cache();
|
||||
*self.exit_cache_mut() = ExitCache::default();
|
||||
*self.slashings_cache_mut() = SlashingsCache::default();
|
||||
*self.epoch_cache_mut() = EpochCache::default();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ macro_rules! full_to_compact {
|
||||
progressive_balances_cache: $s.progressive_balances_cache.clone(),
|
||||
pubkey_cache: $s.pubkey_cache.clone(),
|
||||
exit_cache: $s.exit_cache.clone(),
|
||||
slashings_cache: $s.slashings_cache.clone(),
|
||||
epoch_cache: $s.epoch_cache.clone(),
|
||||
|
||||
// Variant-specific fields
|
||||
@@ -114,6 +115,7 @@ macro_rules! compact_to_full {
|
||||
progressive_balances_cache: $inner.progressive_balances_cache,
|
||||
pubkey_cache: $inner.pubkey_cache,
|
||||
exit_cache: $inner.exit_cache,
|
||||
slashings_cache: $inner.slashings_cache,
|
||||
epoch_cache: $inner.epoch_cache,
|
||||
|
||||
// Variant-specific fields
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
use crate::beacon_state::balance::Balance;
|
||||
use crate::{BeaconState, BeaconStateError, ChainSpec, Epoch, EthSpec};
|
||||
use crate::{
|
||||
consts::altair::{
|
||||
NUM_FLAG_INDICES, TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX,
|
||||
TIMELY_TARGET_FLAG_INDEX,
|
||||
},
|
||||
BeaconState, BeaconStateError, ChainSpec, Epoch, EthSpec, ParticipationFlags,
|
||||
};
|
||||
use arbitrary::Arbitrary;
|
||||
use safe_arith::SafeArith;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
@@ -17,21 +23,110 @@ pub struct ProgressiveBalancesCache {
|
||||
#[derive(Debug, PartialEq, Arbitrary, Clone)]
|
||||
struct Inner {
|
||||
pub current_epoch: Epoch,
|
||||
pub previous_epoch_target_attesting_balance: Balance,
|
||||
pub current_epoch_target_attesting_balance: Balance,
|
||||
pub previous_epoch_cache: EpochTotalBalances,
|
||||
pub current_epoch_cache: EpochTotalBalances,
|
||||
}
|
||||
|
||||
/// Caches the participation values for one epoch (either the previous or current).
|
||||
#[derive(PartialEq, Debug, Clone, Arbitrary)]
|
||||
pub struct EpochTotalBalances {
|
||||
/// Stores the sum of the balances for all validators in `self.unslashed_participating_indices`
|
||||
/// for all flags in `NUM_FLAG_INDICES`.
|
||||
///
|
||||
/// A flag balance is only incremented if a validator is in that flag set.
|
||||
pub total_flag_balances: [Balance; NUM_FLAG_INDICES],
|
||||
}
|
||||
|
||||
impl EpochTotalBalances {
|
||||
pub fn new(spec: &ChainSpec) -> Self {
|
||||
let zero_balance = Balance::zero(spec.effective_balance_increment);
|
||||
|
||||
Self {
|
||||
total_flag_balances: [zero_balance; NUM_FLAG_INDICES],
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the total balance of attesters who have `flag_index` set.
|
||||
pub fn total_flag_balance(&self, flag_index: usize) -> Result<u64, BeaconStateError> {
|
||||
self.total_flag_balances
|
||||
.get(flag_index)
|
||||
.map(Balance::get)
|
||||
.ok_or(BeaconStateError::InvalidFlagIndex(flag_index))
|
||||
}
|
||||
|
||||
/// Returns the raw total balance of attesters who have `flag_index` set.
|
||||
pub fn total_flag_balance_raw(&self, flag_index: usize) -> Result<Balance, BeaconStateError> {
|
||||
self.total_flag_balances
|
||||
.get(flag_index)
|
||||
.copied()
|
||||
.ok_or(BeaconStateError::InvalidFlagIndex(flag_index))
|
||||
}
|
||||
|
||||
pub fn on_new_attestation(
|
||||
&mut self,
|
||||
flag_index: usize,
|
||||
validator_effective_balance: u64,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
let balance = self
|
||||
.total_flag_balances
|
||||
.get_mut(flag_index)
|
||||
.ok_or(BeaconStateError::InvalidFlagIndex(flag_index))?;
|
||||
balance.safe_add_assign(validator_effective_balance)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn on_slashing(
|
||||
&mut self,
|
||||
participation_flags: ParticipationFlags,
|
||||
validator_effective_balance: u64,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
for flag_index in 0..NUM_FLAG_INDICES {
|
||||
if participation_flags.has_flag(flag_index)? {
|
||||
self.total_flag_balances
|
||||
.get_mut(flag_index)
|
||||
.ok_or(BeaconStateError::InvalidFlagIndex(flag_index))?
|
||||
.safe_sub_assign(validator_effective_balance)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn on_effective_balance_change(
|
||||
&mut self,
|
||||
current_epoch_participation_flags: ParticipationFlags,
|
||||
old_effective_balance: u64,
|
||||
new_effective_balance: u64,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
for flag_index in 0..NUM_FLAG_INDICES {
|
||||
if current_epoch_participation_flags.has_flag(flag_index)? {
|
||||
let total = self
|
||||
.total_flag_balances
|
||||
.get_mut(flag_index)
|
||||
.ok_or(BeaconStateError::InvalidFlagIndex(flag_index))?;
|
||||
if new_effective_balance > old_effective_balance {
|
||||
total
|
||||
.safe_add_assign(new_effective_balance.safe_sub(old_effective_balance)?)?;
|
||||
} else {
|
||||
total
|
||||
.safe_sub_assign(old_effective_balance.safe_sub(new_effective_balance)?)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ProgressiveBalancesCache {
|
||||
pub fn initialize(
|
||||
&mut self,
|
||||
current_epoch: Epoch,
|
||||
previous_epoch_target_attesting_balance: Balance,
|
||||
current_epoch_target_attesting_balance: Balance,
|
||||
previous_epoch_cache: EpochTotalBalances,
|
||||
current_epoch_cache: EpochTotalBalances,
|
||||
) {
|
||||
self.inner = Some(Inner {
|
||||
current_epoch,
|
||||
previous_epoch_target_attesting_balance,
|
||||
current_epoch_target_attesting_balance,
|
||||
previous_epoch_cache,
|
||||
current_epoch_cache,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,24 +134,31 @@ impl ProgressiveBalancesCache {
|
||||
self.inner.is_some()
|
||||
}
|
||||
|
||||
pub fn is_initialized_at(&self, epoch: Epoch) -> bool {
|
||||
self.inner
|
||||
.as_ref()
|
||||
.map_or(false, |inner| inner.current_epoch == epoch)
|
||||
}
|
||||
|
||||
/// When a new target attestation has been processed, we update the cached
|
||||
/// `current_epoch_target_attesting_balance` to include the validator effective balance.
|
||||
/// If the epoch is neither the current epoch nor the previous epoch, an error is returned.
|
||||
pub fn on_new_target_attestation(
|
||||
pub fn on_new_attestation(
|
||||
&mut self,
|
||||
epoch: Epoch,
|
||||
flag_index: usize,
|
||||
validator_effective_balance: u64,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
let cache = self.get_inner_mut()?;
|
||||
|
||||
if epoch == cache.current_epoch {
|
||||
cache
|
||||
.current_epoch_target_attesting_balance
|
||||
.safe_add_assign(validator_effective_balance)?;
|
||||
.current_epoch_cache
|
||||
.on_new_attestation(flag_index, validator_effective_balance)?;
|
||||
} else if epoch.safe_add(1)? == cache.current_epoch {
|
||||
cache
|
||||
.previous_epoch_target_attesting_balance
|
||||
.safe_add_assign(validator_effective_balance)?;
|
||||
.previous_epoch_cache
|
||||
.on_new_attestation(flag_index, validator_effective_balance)?;
|
||||
} else {
|
||||
return Err(BeaconStateError::ProgressiveBalancesCacheInconsistent);
|
||||
}
|
||||
@@ -68,21 +170,17 @@ impl ProgressiveBalancesCache {
|
||||
/// validator's effective balance to exclude the validator weight.
|
||||
pub fn on_slashing(
|
||||
&mut self,
|
||||
is_previous_epoch_target_attester: bool,
|
||||
is_current_epoch_target_attester: bool,
|
||||
previous_epoch_participation: ParticipationFlags,
|
||||
current_epoch_participation: ParticipationFlags,
|
||||
effective_balance: u64,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
let cache = self.get_inner_mut()?;
|
||||
if is_previous_epoch_target_attester {
|
||||
cache
|
||||
.previous_epoch_target_attesting_balance
|
||||
.safe_sub_assign(effective_balance)?;
|
||||
}
|
||||
if is_current_epoch_target_attester {
|
||||
cache
|
||||
.current_epoch_target_attesting_balance
|
||||
.safe_sub_assign(effective_balance)?;
|
||||
}
|
||||
cache
|
||||
.previous_epoch_cache
|
||||
.on_slashing(previous_epoch_participation, effective_balance)?;
|
||||
cache
|
||||
.current_epoch_cache
|
||||
.on_slashing(current_epoch_participation, effective_balance)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -90,22 +188,16 @@ impl ProgressiveBalancesCache {
|
||||
/// its share of the target attesting balance in the cache.
|
||||
pub fn on_effective_balance_change(
|
||||
&mut self,
|
||||
is_current_epoch_target_attester: bool,
|
||||
current_epoch_participation: ParticipationFlags,
|
||||
old_effective_balance: u64,
|
||||
new_effective_balance: u64,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
let cache = self.get_inner_mut()?;
|
||||
if is_current_epoch_target_attester {
|
||||
if new_effective_balance > old_effective_balance {
|
||||
cache
|
||||
.current_epoch_target_attesting_balance
|
||||
.safe_add_assign(new_effective_balance.safe_sub(old_effective_balance)?)?;
|
||||
} else {
|
||||
cache
|
||||
.current_epoch_target_attesting_balance
|
||||
.safe_sub_assign(old_effective_balance.safe_sub(new_effective_balance)?)?;
|
||||
}
|
||||
}
|
||||
cache.current_epoch_cache.on_effective_balance_change(
|
||||
current_epoch_participation,
|
||||
old_effective_balance,
|
||||
new_effective_balance,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -114,25 +206,53 @@ impl ProgressiveBalancesCache {
|
||||
pub fn on_epoch_transition(&mut self, spec: &ChainSpec) -> Result<(), BeaconStateError> {
|
||||
let cache = self.get_inner_mut()?;
|
||||
cache.current_epoch.safe_add_assign(1)?;
|
||||
cache.previous_epoch_target_attesting_balance =
|
||||
cache.current_epoch_target_attesting_balance;
|
||||
cache.current_epoch_target_attesting_balance =
|
||||
Balance::zero(spec.effective_balance_increment);
|
||||
cache.previous_epoch_cache = std::mem::replace(
|
||||
&mut cache.current_epoch_cache,
|
||||
EpochTotalBalances::new(spec),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn previous_epoch_flag_attesting_balance(
|
||||
&self,
|
||||
flag_index: usize,
|
||||
) -> Result<u64, BeaconStateError> {
|
||||
self.get_inner()?
|
||||
.previous_epoch_cache
|
||||
.total_flag_balance(flag_index)
|
||||
}
|
||||
|
||||
pub fn current_epoch_flag_attesting_balance(
|
||||
&self,
|
||||
flag_index: usize,
|
||||
) -> Result<u64, BeaconStateError> {
|
||||
self.get_inner()?
|
||||
.current_epoch_cache
|
||||
.total_flag_balance(flag_index)
|
||||
}
|
||||
|
||||
pub fn previous_epoch_source_attesting_balance(&self) -> Result<u64, BeaconStateError> {
|
||||
self.previous_epoch_flag_attesting_balance(TIMELY_SOURCE_FLAG_INDEX)
|
||||
}
|
||||
|
||||
pub fn previous_epoch_target_attesting_balance(&self) -> Result<u64, BeaconStateError> {
|
||||
Ok(self
|
||||
.get_inner()?
|
||||
.previous_epoch_target_attesting_balance
|
||||
.get())
|
||||
self.previous_epoch_flag_attesting_balance(TIMELY_TARGET_FLAG_INDEX)
|
||||
}
|
||||
|
||||
pub fn previous_epoch_head_attesting_balance(&self) -> Result<u64, BeaconStateError> {
|
||||
self.previous_epoch_flag_attesting_balance(TIMELY_HEAD_FLAG_INDEX)
|
||||
}
|
||||
|
||||
pub fn current_epoch_source_attesting_balance(&self) -> Result<u64, BeaconStateError> {
|
||||
self.current_epoch_flag_attesting_balance(TIMELY_SOURCE_FLAG_INDEX)
|
||||
}
|
||||
|
||||
pub fn current_epoch_target_attesting_balance(&self) -> Result<u64, BeaconStateError> {
|
||||
Ok(self
|
||||
.get_inner()?
|
||||
.current_epoch_target_attesting_balance
|
||||
.get())
|
||||
self.current_epoch_flag_attesting_balance(TIMELY_TARGET_FLAG_INDEX)
|
||||
}
|
||||
|
||||
pub fn current_epoch_head_attesting_balance(&self) -> Result<u64, BeaconStateError> {
|
||||
self.current_epoch_flag_attesting_balance(TIMELY_HEAD_FLAG_INDEX)
|
||||
}
|
||||
|
||||
fn get_inner_mut(&mut self) -> Result<&mut Inner, BeaconStateError> {
|
||||
@@ -158,7 +278,7 @@ pub enum ProgressiveBalancesMode {
|
||||
/// Enable the usage of progressive cache, with checks against the `ParticipationCache` and falls
|
||||
/// back to the existing calculation if there is a balance mismatch.
|
||||
Checked,
|
||||
/// Enable the usage of progressive cache, with checks against the `ParticipationCache`. Errors
|
||||
/// Enable the usage of progressive cache, with checks against the `ParticipationCache`. BeaconStateErrors
|
||||
/// if there is a balance mismatch. Used in testing only.
|
||||
Strict,
|
||||
/// Enable the usage of progressive cache, with no comparative checks against the
|
||||
|
||||
63
consensus/types/src/beacon_state/slashings_cache.rs
Normal file
63
consensus/types/src/beacon_state/slashings_cache.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
use crate::{BeaconStateError, Slot, Validator};
|
||||
use arbitrary::Arbitrary;
|
||||
use rpds::HashTrieSetSync as HashTrieSet;
|
||||
|
||||
/// Persistent (cheap to clone) cache of all slashed validator indices.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Arbitrary)]
|
||||
pub struct SlashingsCache {
|
||||
latest_block_slot: Option<Slot>,
|
||||
#[arbitrary(default)]
|
||||
slashed_validators: HashTrieSet<usize>,
|
||||
}
|
||||
|
||||
impl SlashingsCache {
|
||||
/// Initialize a new cache for the given list of validators.
|
||||
pub fn new<'a, V, I>(latest_block_slot: Slot, validators: V) -> Self
|
||||
where
|
||||
V: IntoIterator<Item = &'a Validator, IntoIter = I>,
|
||||
I: ExactSizeIterator + Iterator<Item = &'a Validator>,
|
||||
{
|
||||
let slashed_validators = validators
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, validator)| validator.slashed().then_some(i))
|
||||
.collect();
|
||||
Self {
|
||||
latest_block_slot: Some(latest_block_slot),
|
||||
slashed_validators,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_initialized(&self, slot: Slot) -> bool {
|
||||
self.latest_block_slot == Some(slot)
|
||||
}
|
||||
|
||||
pub fn check_initialized(&self, latest_block_slot: Slot) -> Result<(), BeaconStateError> {
|
||||
if self.is_initialized(latest_block_slot) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(BeaconStateError::SlashingsCacheUninitialized {
|
||||
initialized_slot: self.latest_block_slot,
|
||||
latest_block_slot,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record_validator_slashing(
|
||||
&mut self,
|
||||
block_slot: Slot,
|
||||
validator_index: usize,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
self.check_initialized(block_slot)?;
|
||||
self.slashed_validators.insert_mut(validator_index);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_slashed(&self, validator_index: usize) -> bool {
|
||||
self.slashed_validators.contains(&validator_index)
|
||||
}
|
||||
|
||||
pub fn update_latest_block_slot(&mut self, latest_block_slot: Slot) {
|
||||
self.latest_block_slot = Some(latest_block_slot);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::application_domain::{ApplicationDomain, APPLICATION_DOMAIN_BUILDER};
|
||||
use crate::*;
|
||||
use int_to_bytes::int_to_bytes4;
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use serde::{Deserializer, Serialize, Serializer};
|
||||
use serde_derive::Deserialize;
|
||||
use serde_utils::quoted_u64::MaybeQuoted;
|
||||
@@ -285,12 +286,17 @@ impl ChainSpec {
|
||||
}
|
||||
|
||||
/// For a given `BeaconState`, return the inactivity penalty quotient associated with its variant.
|
||||
// FIXME(sproul): delete once unused
|
||||
pub fn inactivity_penalty_quotient_for_state<T: EthSpec>(&self, state: &BeaconState<T>) -> u64 {
|
||||
match state {
|
||||
BeaconState::Base(_) => self.inactivity_penalty_quotient,
|
||||
BeaconState::Altair(_) => self.inactivity_penalty_quotient_altair,
|
||||
BeaconState::Merge(_) => self.inactivity_penalty_quotient_bellatrix,
|
||||
BeaconState::Capella(_) => self.inactivity_penalty_quotient_bellatrix,
|
||||
self.inactivity_penalty_quotient_for_fork(state.fork_name_unchecked())
|
||||
}
|
||||
|
||||
pub fn inactivity_penalty_quotient_for_fork(&self, fork_name: ForkName) -> u64 {
|
||||
match fork_name {
|
||||
ForkName::Base => self.inactivity_penalty_quotient,
|
||||
ForkName::Altair => self.inactivity_penalty_quotient_altair,
|
||||
ForkName::Merge => self.inactivity_penalty_quotient_bellatrix,
|
||||
ForkName::Capella => self.inactivity_penalty_quotient_bellatrix,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,6 +464,10 @@ impl ChainSpec {
|
||||
Hash256::from(domain)
|
||||
}
|
||||
|
||||
pub fn compute_activation_exit_epoch(&self, epoch: Epoch) -> Result<Epoch, ArithError> {
|
||||
epoch.safe_add(1)?.safe_add(self.max_seed_lookahead)
|
||||
}
|
||||
|
||||
#[allow(clippy::integer_arithmetic)]
|
||||
pub const fn attestation_subnet_prefix_bits(&self) -> u32 {
|
||||
let attestation_subnet_count_bits = self.attestation_subnet_count.ilog2();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{ActivationQueue, BeaconStateError, Epoch, EthSpec, Hash256, Slot};
|
||||
use safe_arith::ArithError;
|
||||
use crate::{ActivationQueue, BeaconStateError, ChainSpec, Epoch, EthSpec, Hash256, Slot};
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Cache of values which are uniquely determined at the start of an epoch.
|
||||
@@ -18,10 +18,16 @@ struct Inner {
|
||||
/// Unique identifier for this cache, which can be used to check its validity before use
|
||||
/// with any `BeaconState`.
|
||||
key: EpochCacheKey,
|
||||
/// Base reward for every validator in this epoch.
|
||||
/// Effective balance for every validator in this epoch.
|
||||
effective_balances: Vec<u64>,
|
||||
/// Base rewards for every effective balance increment (currently 0..32 ETH).
|
||||
///
|
||||
/// Keyed by `effective_balance / effective_balance_increment`.
|
||||
base_rewards: Vec<u64>,
|
||||
/// Validator activation queue.
|
||||
activation_queue: ActivationQueue,
|
||||
/// Effective balance increment.
|
||||
effective_balance_increment: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, arbitrary::Arbitrary)]
|
||||
@@ -35,6 +41,7 @@ pub enum EpochCacheError {
|
||||
IncorrectEpoch { cache: Epoch, state: Epoch },
|
||||
IncorrectDecisionBlock { cache: Hash256, state: Hash256 },
|
||||
ValidatorIndexOutOfBounds { validator_index: usize },
|
||||
EffectiveBalanceOutOfBounds { effective_balance_eth: usize },
|
||||
InvalidSlot { slot: Slot },
|
||||
Arith(ArithError),
|
||||
BeaconState(BeaconStateError),
|
||||
@@ -56,14 +63,18 @@ impl From<ArithError> for EpochCacheError {
|
||||
impl EpochCache {
|
||||
pub fn new(
|
||||
key: EpochCacheKey,
|
||||
effective_balances: Vec<u64>,
|
||||
base_rewards: Vec<u64>,
|
||||
activation_queue: ActivationQueue,
|
||||
spec: &ChainSpec,
|
||||
) -> EpochCache {
|
||||
Self {
|
||||
inner: Some(Arc::new(Inner {
|
||||
key,
|
||||
effective_balances,
|
||||
base_rewards,
|
||||
activation_queue,
|
||||
effective_balance_increment: spec.effective_balance_increment,
|
||||
})),
|
||||
}
|
||||
}
|
||||
@@ -93,16 +104,34 @@ impl EpochCache {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_base_reward(&self, validator_index: usize) -> Result<u64, EpochCacheError> {
|
||||
pub fn get_effective_balance(&self, validator_index: usize) -> Result<u64, EpochCacheError> {
|
||||
self.inner
|
||||
.as_ref()
|
||||
.ok_or(EpochCacheError::CacheNotInitialized)?
|
||||
.base_rewards
|
||||
.effective_balances
|
||||
.get(validator_index)
|
||||
.copied()
|
||||
.ok_or(EpochCacheError::ValidatorIndexOutOfBounds { validator_index })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_base_reward(&self, validator_index: usize) -> Result<u64, EpochCacheError> {
|
||||
let inner = self
|
||||
.inner
|
||||
.as_ref()
|
||||
.ok_or(EpochCacheError::CacheNotInitialized)?;
|
||||
let effective_balance = self.get_effective_balance(validator_index)?;
|
||||
let effective_balance_eth =
|
||||
effective_balance.safe_div(inner.effective_balance_increment)? as usize;
|
||||
inner
|
||||
.base_rewards
|
||||
.get(effective_balance_eth)
|
||||
.copied()
|
||||
.ok_or(EpochCacheError::EffectiveBalanceOutOfBounds {
|
||||
effective_balance_eth,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn activation_queue(&self) -> Result<&ActivationQueue, EpochCacheError> {
|
||||
let inner = self
|
||||
.inner
|
||||
|
||||
Reference in New Issue
Block a user