Merge remote-tracking branch 'origin/unstable' into tree-states

This commit is contained in:
Michael Sproul
2023-07-03 15:01:21 +10:00
115 changed files with 3678 additions and 548 deletions

View File

@@ -15,7 +15,7 @@ integer-sqrt = "0.1.5"
itertools = "0.10.0"
ethereum_ssz = "0.5.0"
ethereum_ssz_derive = "0.5.0"
ssz_types = "0.5.0"
ssz_types = "0.5.3"
merkle_proof = { path = "../merkle_proof" }
safe_arith = { path = "../safe_arith" }
tree_hash = "0.5.0"

View File

@@ -7,6 +7,7 @@ mod slash_validator;
pub mod altair;
pub mod base;
pub mod update_progressive_balances_cache;
pub use deposit_data_tree::DepositDataTree;
pub use get_attestation_participation::get_attestation_participation_flag_indices;

View File

@@ -1,3 +1,4 @@
use crate::common::update_progressive_balances_cache::update_progressive_balances_on_slashing;
use crate::{
common::{decrease_balance, increase_balance, initiate_validator_exit},
per_block_processing::errors::BlockProcessingError,
@@ -43,6 +44,8 @@ pub fn slash_validator<T: EthSpec>(
.safe_div(spec.min_slashing_penalty_quotient_for_state(state))?,
)?;
update_progressive_balances_on_slashing(state, slashed_index)?;
// Apply proposer and whistleblower rewards
let proposer_index = ctxt.get_proposer_index(state, spec)? as usize;
let whistleblower_index = opt_whistleblower_index.unwrap_or(proposer_index);

View File

@@ -0,0 +1,147 @@
/// A collection of all functions that mutates the `ProgressiveBalancesCache`.
use crate::metrics::{
PARTICIPATION_CURR_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL,
PARTICIPATION_PREV_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL,
};
use crate::per_epoch_processing::altair::ParticipationCache;
use crate::{BlockProcessingError, EpochProcessingError};
use lighthouse_metrics::set_gauge;
use std::borrow::Cow;
use types::consts::altair::TIMELY_TARGET_FLAG_INDEX;
use types::{
is_progressive_balances_enabled, BeaconState, BeaconStateError, ChainSpec, Epoch, EthSpec,
ParticipationFlags, ProgressiveBalancesCache, VList,
};
/// Initializes the `ProgressiveBalancesCache` cache using balance values from the
/// `ParticipationCache`. If the optional `&ParticipationCache` is not supplied, it will be computed
/// from the `BeaconState`.
pub fn initialize_progressive_balances_cache<E: EthSpec>(
state: &mut BeaconState<E>,
maybe_participation_cache: Option<&ParticipationCache>,
spec: &ChainSpec,
) -> Result<(), BeaconStateError> {
if !is_progressive_balances_enabled(state)
|| state.progressive_balances_cache().is_initialized()
{
return Ok(());
}
let participation_cache = match maybe_participation_cache {
Some(cache) => Cow::Borrowed(cache),
None => {
state.build_total_active_balance_cache_at(state.current_epoch(), spec)?;
Cow::Owned(
ParticipationCache::new(state, spec)
.map_err(|e| BeaconStateError::ParticipationCacheError(format!("{e:?}")))?,
)
}
};
let previous_epoch_target_attesting_balance = participation_cache
.previous_epoch_target_attesting_balance_raw()
.map_err(|e| BeaconStateError::ParticipationCacheError(format!("{e:?}")))?;
let current_epoch_target_attesting_balance = participation_cache
.current_epoch_target_attesting_balance_raw()
.map_err(|e| BeaconStateError::ParticipationCacheError(format!("{e:?}")))?;
let current_epoch = state.current_epoch();
state.progressive_balances_cache_mut().initialize(
current_epoch,
previous_epoch_target_attesting_balance,
current_epoch_target_attesting_balance,
);
update_progressive_balances_metrics(state.progressive_balances_cache())?;
Ok(())
}
/// Updates the `ProgressiveBalancesCache` when a new target attestation has been processed.
pub fn update_progressive_balances_on_attestation<T: EthSpec>(
state: &mut BeaconState<T>,
epoch: Epoch,
validator_index: usize,
) -> Result<(), BlockProcessingError> {
if is_progressive_balances_enabled(state) {
let validator = state.get_validator(validator_index)?;
if !validator.slashed() {
let validator_effective_balance = validator.effective_balance();
state
.progressive_balances_cache_mut()
.on_new_target_attestation(epoch, validator_effective_balance)?;
}
}
Ok(())
}
/// Updates the `ProgressiveBalancesCache` when a target attester has been slashed.
pub fn update_progressive_balances_on_slashing<T: EthSpec>(
state: &mut BeaconState<T>,
validator_index: usize,
) -> Result<(), BlockProcessingError> {
if is_progressive_balances_enabled(state) {
let previous_epoch_participation = state.previous_epoch_participation()?;
let is_previous_epoch_target_attester =
is_target_attester_in_epoch::<T>(previous_epoch_participation, validator_index)?;
let current_epoch_participation = state.current_epoch_participation()?;
let is_current_epoch_target_attester =
is_target_attester_in_epoch::<T>(current_epoch_participation, validator_index)?;
let validator_effective_balance = state.get_effective_balance(validator_index)?;
state.progressive_balances_cache_mut().on_slashing(
is_previous_epoch_target_attester,
is_current_epoch_target_attester,
validator_effective_balance,
)?;
}
Ok(())
}
/// Updates the `ProgressiveBalancesCache` on epoch transition.
pub fn update_progressive_balances_on_epoch_transition<T: EthSpec>(
state: &mut BeaconState<T>,
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(())
}
fn is_target_attester_in_epoch<T: EthSpec>(
epoch_participation: &VList<ParticipationFlags, T::ValidatorRegistryLimit>,
validator_index: usize,
) -> Result<bool, BlockProcessingError> {
let participation_flags = epoch_participation
.get(validator_index)
.ok_or(BeaconStateError::UnknownValidator(validator_index))?;
participation_flags
.has_flag(TIMELY_TARGET_FLAG_INDEX)
.map_err(|e| e.into())
}

View File

@@ -92,7 +92,7 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
}
// Now that we have our validators, initialize the caches (including the committees)
state.build_all_caches(spec)?;
state.build_caches(spec)?;
// Set genesis validators root for domain separation and chain versioning
*state.genesis_validators_root_mut() = state.update_validators_tree_hash_cache()?;
@@ -115,7 +115,7 @@ pub fn process_activations<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
) -> Result<(), Error> {
let (validators, balances) = state.validators_and_balances_mut();
let (validators, balances, _) = state.validators_and_balances_and_progressive_balances_mut();
let mut validators_iter = validators.iter_cow();
while let Some((index, validator)) = validators_iter.next_cow() {
let validator = validator.to_mut();

View File

@@ -30,4 +30,15 @@ lazy_static! {
"beacon_state_processing_process_epoch",
"Time required for process_epoch",
);
/*
* Participation Metrics (progressive balances)
*/
pub static ref PARTICIPATION_PREV_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL: Result<IntGauge> = try_create_int_gauge(
"beacon_participation_prev_epoch_target_attesting_gwei_progressive_total",
"Progressive total effective balance (gwei) of validators who attested to the target in the previous epoch"
);
pub static ref PARTICIPATION_CURR_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL: Result<IntGauge> = try_create_int_gauge(
"beacon_participation_curr_epoch_target_attesting_gwei_progressive_total",
"Progressive total effective balance (gwei) of validators who attested to the target in the current epoch"
);
}

View File

@@ -41,6 +41,9 @@ mod verify_proposer_slashing;
use crate::common::decrease_balance;
use crate::StateProcessingStrategy;
use crate::common::update_progressive_balances_cache::{
initialize_progressive_balances_cache, update_progressive_balances_metrics,
};
use crate::epoch_cache::initialize_epoch_cache;
#[cfg(feature = "arbitrary-fuzz")]
use arbitrary::Arbitrary;
@@ -117,6 +120,7 @@ pub fn per_block_processing<T: EthSpec, Payload: AbstractExecPayload<T>>(
// Build epoch cache if it hasn't already been built, or if it is no longer valid
initialize_epoch_cache(state, state.current_epoch(), spec)?;
initialize_progressive_balances_cache(state, None, spec)?;
let verify_signatures = match block_signature_strategy {
BlockSignatureStrategy::VerifyBulk => {
@@ -186,6 +190,10 @@ pub fn per_block_processing<T: EthSpec, Payload: AbstractExecPayload<T>>(
)?;
}
if is_progressive_balances_enabled(state) {
update_progressive_balances_metrics(state.progressive_balances_cache())?;
}
Ok(())
}

View File

@@ -1,6 +1,8 @@
use super::signature_sets::Error as SignatureSetError;
use crate::per_epoch_processing::altair::participation_cache;
use crate::{ContextError, EpochCacheError};
use merkle_proof::MerkleTreeError;
use participation_cache::Error as ParticipationCacheError;
use safe_arith::ArithError;
use ssz::DecodeError;
use types::*;
@@ -85,6 +87,7 @@ pub enum BlockProcessingError {
found: Hash256,
},
WithdrawalCredentialsInvalid,
ParticipationCacheError(ParticipationCacheError),
}
impl From<BeaconStateError> for BlockProcessingError {
@@ -154,6 +157,12 @@ impl From<BlockOperationError<HeaderInvalid>> for BlockProcessingError {
}
}
impl From<ParticipationCacheError> for BlockProcessingError {
fn from(e: ParticipationCacheError) -> Self {
BlockProcessingError::ParticipationCacheError(e)
}
}
/// A conversion that consumes `self` and adds an `index` variable to resulting struct.
///
/// Used here to allow converting an error into an upstream error that points to the object that

View File

@@ -97,6 +97,8 @@ pub mod base {
pub mod altair {
use super::*;
use crate::common::update_progressive_balances_cache::update_progressive_balances_on_attestation;
use types::consts::altair::TIMELY_TARGET_FLAG_INDEX;
pub fn process_attestations<T: EthSpec>(
state: &mut BeaconState<T>,
@@ -165,6 +167,14 @@ pub mod altair {
validator_participation.add_flag(flag_index)?;
proposer_reward_numerator
.safe_add_assign(state.get_base_reward(index)?.safe_mul(weight)?)?;
if flag_index == TIMELY_TARGET_FLAG_INDEX {
update_progressive_balances_on_attestation(
state,
data.target.epoch,
index,
)?;
}
}
}
}
@@ -238,6 +248,7 @@ pub fn process_attester_slashings<T: EthSpec>(
Ok(())
}
/// Wrapper function to handle calling the correct version of `process_attestations` based on
/// the fork.
pub fn process_attestations<T: EthSpec, Payload: AbstractExecPayload<T>>(

View File

@@ -1,4 +1,7 @@
use super::{process_registry_updates, process_slashings, EpochProcessingSummary, Error};
use crate::common::update_progressive_balances_cache::{
initialize_progressive_balances_cache, update_progressive_balances_on_epoch_transition,
};
use crate::epoch_cache::initialize_epoch_cache;
use crate::per_epoch_processing::{
effective_balance_updates::process_effective_balance_updates,
@@ -34,6 +37,7 @@ pub fn process_epoch<T: EthSpec>(
// Pre-compute participating indices and total balances.
let mut participation_cache = ParticipationCache::new(state, spec)?;
let sync_committee = state.current_sync_committee()?.clone();
initialize_progressive_balances_cache::<T>(state, Some(&participation_cache), spec)?;
// Justification and finalization.
let justification_and_finalization_state =
@@ -60,7 +64,7 @@ pub fn process_epoch<T: EthSpec>(
process_eth1_data_reset(state)?;
// Update effective balances with hysteresis (lag).
process_effective_balance_updates(state, spec)?;
process_effective_balance_updates(state, Some(&participation_cache), spec)?;
// Reset slashings
process_slashings_reset(state)?;
@@ -80,6 +84,8 @@ pub fn process_epoch<T: EthSpec>(
state.advance_caches(spec)?;
initialize_epoch_cache(state, state.next_epoch()?, spec)?;
update_progressive_balances_on_epoch_transition(state, spec)?;
Ok(EpochProcessingSummary::Altair {
participation_cache,
sync_committee,

View File

@@ -19,12 +19,12 @@ use types::{
NUM_FLAG_INDICES, TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX,
TIMELY_TARGET_FLAG_INDEX,
},
BeaconState, BeaconStateError, ChainSpec, Epoch, EthSpec, ParticipationFlags, RelativeEpoch,
Unsigned, Validator,
Balance, BeaconState, BeaconStateError, ChainSpec, Epoch, EthSpec, ParticipationFlags,
RelativeEpoch, Unsigned, Validator,
};
use vec_map::VecMap;
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub enum Error {
InvalidFlagIndex(usize),
NoUnslashedParticipatingIndices,
@@ -47,34 +47,8 @@ impl From<ArithError> for Error {
}
}
/// A balance which will never be below the specified `minimum`.
///
/// This is an effort to ensure the `EFFECTIVE_BALANCE_INCREMENT` minimum is always respected.
#[derive(PartialEq, Debug, Clone, Copy)]
struct Balance {
raw: u64,
minimum: u64,
}
impl Balance {
/// Initialize the balance to `0`, or the given `minimum`.
pub fn zero(minimum: u64) -> Self {
Self { raw: 0, minimum }
}
/// Returns the balance with respect to the initialization `minimum`.
pub fn get(&self) -> u64 {
std::cmp::max(self.raw, self.minimum)
}
/// Add-assign to the balance.
pub fn safe_add_assign(&mut self, other: u64) -> Result<(), ArithError> {
self.raw.safe_add_assign(other)
}
}
/// Caches the participation values for one epoch (either the previous or current).
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone)]
struct SingleEpochParticipationCache {
/// Stores the sum of the balances for all validators in `self.unslashed_participating_indices`
/// for all flags in `NUM_FLAG_INDICES`.
@@ -104,6 +78,14 @@ impl SingleEpochParticipationCache {
.ok_or(Error::InvalidFlagIndex(flag_index))
}
/// Returns the raw total balance of attesters who have `flag_index` set.
fn total_flag_balance_raw(&self, flag_index: usize) -> Result<Balance, Error> {
self.total_flag_balances
.get(flag_index)
.copied()
.ok_or(Error::InvalidFlagIndex(flag_index))
}
/// Process an **active** validator, reading from the `epoch_participation` with respect to the
/// `relative_epoch`.
///
@@ -170,7 +152,7 @@ impl ValidatorInfo {
}
/// Single `HashMap` for validator info relevant to `process_epoch`.
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
struct ValidatorInfoCache {
info: Vec<Option<ValidatorInfo>>,
}
@@ -184,7 +166,7 @@ impl ValidatorInfoCache {
}
/// Maintains a cache to be used during `altair::process_epoch`.
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone)]
pub struct ParticipationCache {
current_epoch: Epoch,
/// Caches information about active validators pertaining to `self.current_epoch`.
@@ -381,6 +363,11 @@ impl ParticipationCache {
.total_flag_balance(TIMELY_TARGET_FLAG_INDEX)
}
pub fn current_epoch_target_attesting_balance_raw(&self) -> Result<Balance, Error> {
self.current_epoch_participation
.total_flag_balance_raw(TIMELY_TARGET_FLAG_INDEX)
}
pub fn previous_epoch_total_active_balance(&self) -> u64 {
self.previous_epoch_participation.total_active_balance.get()
}
@@ -389,6 +376,11 @@ impl ParticipationCache {
self.previous_epoch_flag_attesting_balance(TIMELY_TARGET_FLAG_INDEX)
}
pub fn previous_epoch_target_attesting_balance_raw(&self) -> Result<Balance, Error> {
self.previous_epoch_participation
.total_flag_balance_raw(TIMELY_TARGET_FLAG_INDEX)
}
pub fn previous_epoch_source_attesting_balance(&self) -> Result<u64, Error> {
self.previous_epoch_flag_attesting_balance(TIMELY_SOURCE_FLAG_INDEX)
}

View File

@@ -56,7 +56,7 @@ pub fn process_epoch<T: EthSpec>(
process_eth1_data_reset(state)?;
// Update effective balances with hysteresis (lag).
process_effective_balance_updates(state, spec)?;
process_effective_balance_updates(state, None, spec)?;
// Reset slashings
process_slashings_reset(state)?;

View File

@@ -11,6 +11,9 @@ use crate::per_epoch_processing::{
};
use types::{BeaconState, ChainSpec, EthSpec, RelativeEpoch};
use crate::common::update_progressive_balances_cache::{
initialize_progressive_balances_cache, update_progressive_balances_on_epoch_transition,
};
use crate::epoch_cache::initialize_epoch_cache;
pub use historical_summaries_update::process_historical_summaries_update;
@@ -30,6 +33,7 @@ pub fn process_epoch<T: EthSpec>(
// Pre-compute participating indices and total balances.
let mut participation_cache = ParticipationCache::new(state, spec)?;
let sync_committee = state.current_sync_committee()?.clone();
initialize_progressive_balances_cache(state, Some(&participation_cache), spec)?;
// Justification and finalization.
let justification_and_finalization_state =
@@ -56,7 +60,7 @@ pub fn process_epoch<T: EthSpec>(
process_eth1_data_reset(state)?;
// Update effective balances with hysteresis (lag).
process_effective_balance_updates(state, spec)?;
process_effective_balance_updates(state, Some(&participation_cache), spec)?;
// Reset slashings
process_slashings_reset(state)?;
@@ -76,6 +80,8 @@ pub fn process_epoch<T: EthSpec>(
state.advance_caches(spec)?;
initialize_epoch_cache(state, state.next_epoch()?, spec)?;
update_progressive_balances_on_epoch_transition(state, spec)?;
Ok(EpochProcessingSummary::Altair {
participation_cache,
sync_committee,

View File

@@ -1,11 +1,13 @@
use super::errors::EpochProcessingError;
use crate::per_epoch_processing::altair::ParticipationCache;
use safe_arith::SafeArith;
use types::beacon_state::BeaconState;
use types::chain_spec::ChainSpec;
use types::{BeaconStateError, EthSpec};
use types::{BeaconStateError, EthSpec, ProgressiveBalancesCache};
pub fn process_effective_balance_updates<T: EthSpec>(
state: &mut BeaconState<T>,
maybe_participation_cache: Option<&ParticipationCache>,
spec: &ChainSpec,
) -> Result<(), EpochProcessingError> {
// Compute new total active balance for the next epoch as a side-effect of iterating the
@@ -18,7 +20,8 @@ pub fn process_effective_balance_updates<T: EthSpec>(
.safe_div(spec.hysteresis_quotient)?;
let downward_threshold = hysteresis_increment.safe_mul(spec.hysteresis_downward_multiplier)?;
let upward_threshold = hysteresis_increment.safe_mul(spec.hysteresis_upward_multiplier)?;
let (validators, balances) = state.validators_and_balances_mut();
let (validators, balances, progressive_balances_cache) =
state.validators_and_balances_and_progressive_balances_mut();
let mut validators_iter = validators.iter_cow();
while let Some((index, validator)) = validators_iter.next_cow() {
@@ -44,7 +47,18 @@ pub fn process_effective_balance_updates<T: EthSpec>(
}
if new_effective_balance != validator.effective_balance() {
let old_effective_balance = validator.effective_balance();
validator.to_mut().mutable.effective_balance = new_effective_balance;
if let Some(participation_cache) = maybe_participation_cache {
update_progressive_balances(
participation_cache,
progressive_balances_cache,
index,
old_effective_balance,
new_effective_balance,
)?;
}
}
}
@@ -52,3 +66,22 @@ pub fn process_effective_balance_updates<T: EthSpec>(
Ok(())
}
fn update_progressive_balances(
participation_cache: &ParticipationCache,
progressive_balances_cache: &mut ProgressiveBalancesCache,
index: usize,
old_effective_balance: u64,
new_effective_balance: u64,
) -> Result<(), EpochProcessingError> {
if old_effective_balance != new_effective_balance {
let is_current_epoch_target_attester =
participation_cache.is_current_epoch_timely_target_attester(index)?;
progressive_balances_cache.on_effective_balance_change(
is_current_epoch_target_attester,
old_effective_balance,
new_effective_balance,
)?;
}
Ok(())
}

View File

@@ -63,7 +63,7 @@ pub fn per_slot_processing<T: EthSpec>(
// Additionally build all caches so that all valid states that are advanced always have
// committee caches built, and we don't have to worry about initialising them at higher
// layers.
state.build_all_caches(spec)?;
state.build_caches(spec)?;
}
Ok(summary)

View File

@@ -1,3 +1,4 @@
use crate::common::update_progressive_balances_cache::initialize_progressive_balances_cache;
use crate::common::{get_attestation_participation_flag_indices, get_attesting_indices};
use std::mem;
use std::sync::Arc;
@@ -101,6 +102,7 @@ pub fn upgrade_to_altair<E: EthSpec>(
next_sync_committee: temp_sync_committee, // not read
// Caches
total_active_balance: pre.total_active_balance,
progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache),
committee_caches: mem::take(&mut pre.committee_caches),
pubkey_cache: mem::take(&mut pre.pubkey_cache),
exit_cache: mem::take(&mut pre.exit_cache),
@@ -110,6 +112,8 @@ pub fn upgrade_to_altair<E: EthSpec>(
// Fill in previous epoch participation from the pre state's pending attestations.
translate_participation(&mut post, &pre.previous_epoch_attestations, spec)?;
initialize_progressive_balances_cache(&mut post, None, spec)?;
// Fill in sync committees
// Note: A duplicate committee is assigned for the current and next committee at the fork
// boundary

View File

@@ -64,6 +64,7 @@ pub fn upgrade_to_capella<E: EthSpec>(
historical_summaries: VList::default(),
// Caches
total_active_balance: pre.total_active_balance,
progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache),
committee_caches: mem::take(&mut pre.committee_caches),
pubkey_cache: mem::take(&mut pre.pubkey_cache),
exit_cache: mem::take(&mut pre.exit_cache),

View File

@@ -60,6 +60,7 @@ pub fn upgrade_to_bellatrix<E: EthSpec>(
latest_execution_payload_header: <ExecutionPayloadHeaderMerge<E>>::default(),
// Caches
total_active_balance: pre.total_active_balance,
progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache),
committee_caches: mem::take(&mut pre.committee_caches),
pubkey_cache: mem::take(&mut pre.pubkey_cache),
exit_cache: mem::take(&mut pre.exit_cache),