mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-19 13:58:28 +00:00
Use CoW
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -2886,6 +2886,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"state_processing",
|
||||
"store",
|
||||
"tree_hash",
|
||||
"types",
|
||||
"validator_dir",
|
||||
@@ -3657,6 +3658,7 @@ dependencies = [
|
||||
"eth2_ssz",
|
||||
"itertools",
|
||||
"parking_lot",
|
||||
"rayon",
|
||||
"serde",
|
||||
"tree_hash",
|
||||
"triomphe",
|
||||
|
||||
@@ -21,9 +21,6 @@ use tree_hash::TreeHash;
|
||||
use typenum::Unsigned;
|
||||
use types::VList;
|
||||
|
||||
#[cfg(feature = "milhouse")]
|
||||
use types::milhouse::ImmList;
|
||||
|
||||
/// Description of how a `BeaconState` field is updated during state processing.
|
||||
///
|
||||
/// When storing a state, this allows us to efficiently store only those entries
|
||||
@@ -301,7 +298,7 @@ field!(
|
||||
T::SlotsPerHistoricalRoot,
|
||||
DBColumn::BeaconBlockRoots,
|
||||
|_| OncePerNSlots { n: 1 },
|
||||
|state: &BeaconState<_>, index, _| safe_modulo_index(state.block_roots(), index)
|
||||
|state: &BeaconState<_>, index, _| safe_modulo_index_vect(state.block_roots(), index)
|
||||
);
|
||||
|
||||
field!(
|
||||
@@ -311,7 +308,7 @@ field!(
|
||||
T::SlotsPerHistoricalRoot,
|
||||
DBColumn::BeaconStateRoots,
|
||||
|_| OncePerNSlots { n: 1 },
|
||||
|state: &BeaconState<_>, index, _| safe_modulo_index(state.state_roots(), index)
|
||||
|state: &BeaconState<_>, index, _| safe_modulo_index_vect(state.state_roots(), index)
|
||||
);
|
||||
|
||||
field!(
|
||||
@@ -323,7 +320,7 @@ field!(
|
||||
|_| OncePerNSlots {
|
||||
n: T::SlotsPerHistoricalRoot::to_u64()
|
||||
},
|
||||
|state: &BeaconState<_>, index, _| safe_modulo_index(state.historical_roots(), index)
|
||||
|state: &BeaconState<_>, index, _| safe_modulo_index_list(state.historical_roots(), index)
|
||||
);
|
||||
|
||||
field!(
|
||||
@@ -333,7 +330,7 @@ field!(
|
||||
T::EpochsPerHistoricalVector,
|
||||
DBColumn::BeaconRandaoMixes,
|
||||
|_| OncePerEpoch { lag: 1 },
|
||||
|state: &BeaconState<_>, index, _| safe_modulo_index(state.randao_mixes(), index)
|
||||
|state: &BeaconState<_>, index, _| safe_modulo_index_vect(state.randao_mixes(), index)
|
||||
);
|
||||
|
||||
pub fn store_updated_vector<F: Field<E>, E: EthSpec, S: KeyValueStore<E>>(
|
||||
@@ -572,7 +569,25 @@ fn safe_modulo_index<T: Copy>(values: &[T], index: u64) -> Result<T, ChunkError>
|
||||
}
|
||||
|
||||
#[cfg(feature = "milhouse")]
|
||||
fn safe_modulo_index<V: ImmList<T>, T: Copy>(values: &V, index: u64) -> Result<T, ChunkError> {
|
||||
fn safe_modulo_index_list<T: TreeHash + Copy, N: Unsigned>(
|
||||
values: &VList<T, N>,
|
||||
index: u64,
|
||||
) -> Result<T, ChunkError> {
|
||||
if values.is_empty() {
|
||||
Err(ChunkError::ZeroLengthVector)
|
||||
} else {
|
||||
values
|
||||
.get(index as usize % values.len())
|
||||
.copied()
|
||||
.ok_or(ChunkError::OutOfBounds)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "milhouse")]
|
||||
fn safe_modulo_index_vect<T: TreeHash + Copy, N: Unsigned>(
|
||||
values: &FixedVector<T, N>,
|
||||
index: u64,
|
||||
) -> Result<T, ChunkError> {
|
||||
if values.is_empty() {
|
||||
Err(ChunkError::ZeroLengthVector)
|
||||
} else {
|
||||
|
||||
@@ -79,7 +79,7 @@ where
|
||||
|
||||
// Inactivity
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
pub inactivity_scores: VariableList<u64, T::ValidatorRegistryLimit>,
|
||||
pub inactivity_scores: VList<u64, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Light-client sync committees
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
@@ -266,17 +266,9 @@ impl<T: EthSpec> PartialBeaconState<T> {
|
||||
let current_epoch = self.slot().epoch(T::slots_per_epoch());
|
||||
let len = randao_mixes.len();
|
||||
|
||||
#[cfg(feature = "milhouse")]
|
||||
{
|
||||
use milhouse::interface::MutList;
|
||||
randao_mixes
|
||||
.replace(current_epoch.as_usize() % len, *self.latest_randao_value())?;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
{
|
||||
randao_mixes[current_epoch.as_usize() % len] = *self.latest_randao_value();
|
||||
}
|
||||
*randao_mixes
|
||||
.get_mut(current_epoch.as_usize() % len)
|
||||
.unwrap() = *self.latest_randao_value();
|
||||
|
||||
*self.randao_mixes_mut() = Some(randao_mixes)
|
||||
}
|
||||
|
||||
@@ -32,13 +32,11 @@ pub fn initiate_validator_exit<T: EthSpec>(
|
||||
.exit_cache_mut()
|
||||
.record_validator_exit(exit_queue_epoch)?;
|
||||
|
||||
let mut validators = state.validators_mut();
|
||||
let validator = validators.get_validator_mut(index)?;
|
||||
|
||||
// FIXME(sproul): could avoid this second lookup with some clever borrowing
|
||||
let mut validator = state.get_validator_mut(index)?;
|
||||
validator.exit_epoch = exit_queue_epoch;
|
||||
validator.withdrawable_epoch =
|
||||
exit_queue_epoch.safe_add(spec.min_validator_withdrawability_delay)?;
|
||||
drop(validators);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ pub use initiate_validator_exit::initiate_validator_exit;
|
||||
pub use slash_validator::slash_validator;
|
||||
|
||||
use safe_arith::SafeArith;
|
||||
use types::{BeaconState, BeaconStateError, EthSpec, GetBalanceMut};
|
||||
use types::{BeaconState, BeaconStateError, EthSpec};
|
||||
|
||||
/// Increase the balance of a validator, erroring upon overflow, as per the spec.
|
||||
pub fn increase_balance<E: EthSpec>(
|
||||
@@ -24,10 +24,7 @@ pub fn increase_balance<E: EthSpec>(
|
||||
index: usize,
|
||||
delta: u64,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
state
|
||||
.balances_mut()
|
||||
.get_balance_mut(index)?
|
||||
.safe_add_assign(delta)?;
|
||||
state.get_balance_mut(index)?.safe_add_assign(delta)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -37,8 +34,7 @@ pub fn decrease_balance<E: EthSpec>(
|
||||
index: usize,
|
||||
delta: u64,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
let mut balances = state.balances_mut();
|
||||
let balance = balances.get_balance_mut(index)?;
|
||||
let balance = state.get_balance_mut(index)?;
|
||||
*balance = balance.saturating_sub(delta);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -17,16 +17,13 @@ pub fn slash_validator<T: EthSpec>(
|
||||
|
||||
initiate_validator_exit(state, slashed_index, spec)?;
|
||||
|
||||
let mut validators = state.validators_mut();
|
||||
let validator = validators.get_validator_mut(slashed_index)?;
|
||||
let validator = state.get_validator_mut(slashed_index)?;
|
||||
validator.slashed = true;
|
||||
validator.withdrawable_epoch = cmp::max(
|
||||
validator.withdrawable_epoch,
|
||||
epoch.safe_add(T::EpochsPerSlashingsVector::to_u64())?,
|
||||
);
|
||||
let validator_effective_balance = validator.effective_balance;
|
||||
drop(validators);
|
||||
|
||||
state.set_slashings(
|
||||
epoch,
|
||||
state
|
||||
|
||||
@@ -96,9 +96,10 @@ pub fn process_activations<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
let (mut validators, balances) = state.validators_and_balances_mut();
|
||||
for index in 0..validators.len() {
|
||||
let validator = validators.get_validator_mut(index)?;
|
||||
let (validators, balances) = state.validators_and_balances_mut();
|
||||
let mut validators_iter = validators.iter_cow();
|
||||
while let Some((index, validator)) = validators_iter.next_cow() {
|
||||
let validator = validator.to_mut();
|
||||
let balance = balances
|
||||
.get(index)
|
||||
.copied()
|
||||
|
||||
@@ -19,6 +19,7 @@ use types::{
|
||||
TIMELY_TARGET_FLAG_INDEX,
|
||||
},
|
||||
BeaconState, BeaconStateError, ChainSpec, Epoch, EthSpec, ParticipationFlags, RelativeEpoch,
|
||||
Validator,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -120,12 +121,10 @@ impl SingleEpochParticipationCache {
|
||||
fn process_active_validator<T: EthSpec>(
|
||||
&mut self,
|
||||
val_index: usize,
|
||||
validator: &Validator,
|
||||
state: &BeaconState<T>,
|
||||
relative_epoch: RelativeEpoch,
|
||||
) -> Result<(), BeaconStateError> {
|
||||
let val_balance = state.get_effective_balance(val_index)?;
|
||||
let validator = state.get_validator(val_index)?;
|
||||
|
||||
// Sanity check to ensure the validator is active.
|
||||
let epoch = relative_epoch.into_epoch(state.current_epoch());
|
||||
if !validator.is_active_at(epoch) {
|
||||
@@ -141,7 +140,8 @@ impl SingleEpochParticipationCache {
|
||||
.ok_or(BeaconStateError::ParticipationOutOfBounds(val_index))?;
|
||||
|
||||
// All active validators increase the total active balance.
|
||||
self.total_active_balance.safe_add_assign(val_balance)?;
|
||||
self.total_active_balance
|
||||
.safe_add_assign(validator.effective_balance)?;
|
||||
|
||||
// Only unslashed validators may proceed.
|
||||
if validator.slashed {
|
||||
@@ -156,7 +156,7 @@ impl SingleEpochParticipationCache {
|
||||
// are set for `val_index`.
|
||||
for (flag, balance) in self.total_flag_balances.iter_mut().enumerate() {
|
||||
if epoch_participation.has_flag(flag)? {
|
||||
balance.safe_add_assign(val_balance)?;
|
||||
balance.safe_add_assign(validator.effective_balance)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +223,7 @@ impl ParticipationCache {
|
||||
if val.is_active_at(current_epoch) {
|
||||
current_epoch_participation.process_active_validator(
|
||||
val_index,
|
||||
val,
|
||||
state,
|
||||
RelativeEpoch::Current,
|
||||
)?;
|
||||
@@ -231,6 +232,7 @@ impl ParticipationCache {
|
||||
if val.is_active_at(previous_epoch) {
|
||||
previous_epoch_participation.process_active_validator(
|
||||
val_index,
|
||||
val,
|
||||
state,
|
||||
RelativeEpoch::Previous,
|
||||
)?;
|
||||
|
||||
@@ -69,6 +69,7 @@ pub fn get_flag_index_deltas<T: EthSpec>(
|
||||
let active_increments = total_active_balance.safe_div(spec.effective_balance_increment)?;
|
||||
|
||||
for &index in participation_cache.eligible_validator_indices() {
|
||||
// FIXME(sproul): compute base reward in participation cache
|
||||
let base_reward = get_base_reward(state, index, total_active_balance, spec)?;
|
||||
let mut delta = Delta::default();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::errors::EpochProcessingError;
|
||||
use safe_arith::SafeArith;
|
||||
use types::beacon_state::BeaconState;
|
||||
use types::chain_spec::ChainSpec;
|
||||
use types::{BeaconStateError, EthSpec, GetValidatorMut};
|
||||
use types::{BeaconStateError, EthSpec};
|
||||
|
||||
pub fn process_effective_balance_updates<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
@@ -13,9 +13,9 @@ 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 (mut validators, balances) = state.validators_and_balances_mut();
|
||||
for index in 0..validators.len() {
|
||||
let validator = validators.get_validator_mut(index)?;
|
||||
let (validators, balances) = state.validators_and_balances_mut();
|
||||
let mut validators_iter = validators.iter_cow();
|
||||
while let Some((index, validator)) = validators_iter.next_cow() {
|
||||
let balance = balances
|
||||
.get(index)
|
||||
.copied()
|
||||
@@ -24,7 +24,7 @@ pub fn process_effective_balance_updates<T: EthSpec>(
|
||||
if balance.safe_add(downward_threshold)? < validator.effective_balance
|
||||
|| validator.effective_balance.safe_add(upward_threshold)? < balance
|
||||
{
|
||||
validator.effective_balance = std::cmp::min(
|
||||
validator.to_mut().effective_balance = std::cmp::min(
|
||||
balance.safe_sub(balance.safe_rem(spec.effective_balance_increment)?)?,
|
||||
spec.max_effective_balance,
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{common::initiate_validator_exit, per_epoch_processing::Error};
|
||||
use itertools::Itertools;
|
||||
use safe_arith::SafeArith;
|
||||
use types::{BeaconState, ChainSpec, EthSpec, GetValidatorMut, Validator};
|
||||
use types::{BeaconState, ChainSpec, EthSpec, Validator};
|
||||
|
||||
/// Performs a validator registry update, if required.
|
||||
///
|
||||
@@ -30,13 +30,11 @@ pub fn process_registry_updates<T: EthSpec>(
|
||||
.collect();
|
||||
|
||||
for index in indices_to_update {
|
||||
let mut validators = state.validators_mut();
|
||||
let validator = validators.get_validator_mut(index)?;
|
||||
let validator = state.get_validator_mut(index)?;
|
||||
if validator.is_eligible_for_activation_queue(spec) {
|
||||
validator.activation_eligibility_epoch = current_epoch.safe_add(1)?;
|
||||
}
|
||||
if is_ejectable(validator) {
|
||||
drop(validators);
|
||||
initiate_validator_exit(state, index, spec)?;
|
||||
}
|
||||
}
|
||||
@@ -54,9 +52,8 @@ pub fn process_registry_updates<T: EthSpec>(
|
||||
// Dequeue validators for activation up to churn limit
|
||||
let churn_limit = state.get_churn_limit(spec)? as usize;
|
||||
let delayed_activation_epoch = state.compute_activation_exit_epoch(current_epoch, spec)?;
|
||||
let mut validators = state.validators_mut();
|
||||
for index in activation_queue.into_iter().take(churn_limit) {
|
||||
validators.get_validator_mut(index)?.activation_epoch = delayed_activation_epoch;
|
||||
state.get_validator_mut(index)?.activation_epoch = delayed_activation_epoch;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::per_epoch_processing::Error;
|
||||
use safe_arith::{SafeArith, SafeArithIter};
|
||||
use types::{BeaconState, ChainSpec, EthSpec, GetBalanceMut, GetValidatorMut, Unsigned};
|
||||
use types::{BeaconState, BeaconStateError, ChainSpec, EthSpec, Unsigned};
|
||||
|
||||
/// Process slashings.
|
||||
pub fn process_slashings<T: EthSpec>(
|
||||
@@ -16,9 +16,9 @@ pub fn process_slashings<T: EthSpec>(
|
||||
total_balance,
|
||||
);
|
||||
|
||||
let (validators, mut balances) = state.validators_and_balances_mut();
|
||||
for index in 0..validators.len() {
|
||||
let validator = validators.get_validator(index)?;
|
||||
let (validators, balances) = state.validators_and_balances_mut();
|
||||
let mut validators_iter = validators.iter_cow();
|
||||
while let Some((index, validator)) = validators_iter.next_cow() {
|
||||
if validator.slashed
|
||||
&& epoch.safe_add(T::EpochsPerSlashingsVector::to_u64().safe_div(2)?)?
|
||||
== validator.withdrawable_epoch
|
||||
@@ -33,7 +33,9 @@ pub fn process_slashings<T: EthSpec>(
|
||||
.safe_mul(increment)?;
|
||||
|
||||
// Equivalent to `decrease_balance(state, index, penalty)`, but avoids borrowing `state`.
|
||||
let balance = balances.get_balance_mut(index)?;
|
||||
let balance = balances
|
||||
.get_mut(index)
|
||||
.ok_or(BeaconStateError::BalancesOutOfBounds(index))?;
|
||||
*balance = balance.saturating_sub(penalty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ pub fn upgrade_to_altair<E: EthSpec>(
|
||||
|
||||
let default_epoch_participation =
|
||||
VariableList::new(vec![ParticipationFlags::default(); pre.validators.len()])?;
|
||||
let inactivity_scores = VariableList::new(vec![0; pre.validators.len()])?;
|
||||
let inactivity_scores = VList::new(vec![0; pre.validators.len()])?;
|
||||
|
||||
let temp_sync_committee = Arc::new(SyncCommittee::temporary()?);
|
||||
|
||||
|
||||
@@ -47,28 +47,6 @@ mod tests;
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
mod tree_hash_cache;
|
||||
|
||||
#[cfg(feature = "milhouse")]
|
||||
mod type_aliases {
|
||||
use super::*;
|
||||
|
||||
pub type ListMut<'a, T, N> = Interface<'a, T, List<T, N>>;
|
||||
pub type VectMut<'a, T, N> = Interface<'a, T, FixedVector<T, N>>;
|
||||
pub type ValidatorsMut<'a, N> = ListMut<'a, Validator, N>;
|
||||
pub type BalancesMut<'a, N> = ListMut<'a, u64, N>;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
mod type_aliases {
|
||||
use super::*;
|
||||
|
||||
pub type ListMut<'a, T, N> = &'a mut VList<T, N>;
|
||||
pub type VectMut<'a, T, N> = &'a mut FixedVector<T, N>;
|
||||
pub type ValidatorsMut<'a, N> = &'a mut VList<Validator, N>;
|
||||
pub type BalancesMut<'a, N> = ListMut<'a, u64, N>;
|
||||
}
|
||||
|
||||
pub use type_aliases::*;
|
||||
|
||||
pub const CACHED_EPOCHS: usize = 3;
|
||||
const MAX_RANDOM_BYTE: u64 = (1 << 8) - 1;
|
||||
|
||||
@@ -248,10 +226,8 @@ where
|
||||
|
||||
// History
|
||||
pub latest_block_header: BeaconBlockHeader,
|
||||
#[superstruct(getter(rename = "block_roots_raw"))]
|
||||
#[test_random(default)]
|
||||
pub block_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>,
|
||||
#[superstruct(getter(rename = "state_roots_raw"))]
|
||||
#[test_random(default)]
|
||||
pub state_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>,
|
||||
#[test_random(default)]
|
||||
@@ -266,22 +242,18 @@ where
|
||||
pub eth1_deposit_index: u64,
|
||||
|
||||
// Registry
|
||||
#[superstruct(getter(rename = "validators_raw"))]
|
||||
#[test_random(default)]
|
||||
pub validators: VList<Validator, T::ValidatorRegistryLimit>,
|
||||
// FIXME(sproul): serde quoting
|
||||
// #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")]
|
||||
#[superstruct(getter(rename = "balances_raw"))]
|
||||
#[test_random(default)]
|
||||
pub balances: VList<u64, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Randomness
|
||||
#[superstruct(getter(rename = "randao_mixes_raw"))]
|
||||
#[test_random(default)]
|
||||
pub randao_mixes: FixedVector<Hash256, T::EpochsPerHistoricalVector>,
|
||||
|
||||
// Slashings
|
||||
#[superstruct(getter(rename = "slashings_raw"))]
|
||||
#[test_random(default)]
|
||||
// FIXME(sproul): serde quoting
|
||||
// #[serde(with = "ssz_types::serde_utils::quoted_u64_fixed_vec")]
|
||||
@@ -312,9 +284,11 @@ where
|
||||
pub finalized_checkpoint: Checkpoint,
|
||||
|
||||
// Inactivity
|
||||
#[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")]
|
||||
// FIXME(sproul): quoting
|
||||
// #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")]
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
pub inactivity_scores: VariableList<u64, T::ValidatorRegistryLimit>,
|
||||
#[test_random(default)]
|
||||
pub inactivity_scores: VList<u64, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Light-client sync committees
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
@@ -990,7 +964,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
|
||||
/// Fill `randao_mixes` with
|
||||
pub fn fill_randao_mixes_with(&mut self, index_root: Hash256) {
|
||||
*self.randao_mixes_raw_mut() = FixedVector::from_elem(index_root);
|
||||
*self.randao_mixes_mut() = FixedVector::from_elem(index_root);
|
||||
}
|
||||
|
||||
/// Safely obtains the index for `randao_mixes`
|
||||
@@ -1139,116 +1113,25 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validators(&self) -> &VList<Validator, T::ValidatorRegistryLimit> {
|
||||
self.validators_raw()
|
||||
}
|
||||
|
||||
pub fn validators_mut(&mut self) -> ValidatorsMut<T::ValidatorRegistryLimit> {
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
{
|
||||
self.validators_raw_mut()
|
||||
}
|
||||
#[cfg(feature = "milhouse")]
|
||||
{
|
||||
self.validators_raw_mut().as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn balances(&self) -> &VList<u64, T::ValidatorRegistryLimit> {
|
||||
self.balances_raw()
|
||||
}
|
||||
|
||||
pub fn balances_mut(&mut self) -> BalancesMut<T::ValidatorRegistryLimit> {
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
{
|
||||
self.balances_raw_mut()
|
||||
}
|
||||
#[cfg(feature = "milhouse")]
|
||||
{
|
||||
self.balances_raw_mut().as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience accessor for validators and balances simultaneously.
|
||||
pub fn validators_and_balances_mut(
|
||||
&mut self,
|
||||
) -> (
|
||||
ValidatorsMut<T::ValidatorRegistryLimit>,
|
||||
BalancesMut<T::ValidatorRegistryLimit>,
|
||||
&mut VList<Validator, T::ValidatorRegistryLimit>,
|
||||
&mut VList<u64, T::ValidatorRegistryLimit>,
|
||||
) {
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
match self {
|
||||
BeaconState::Base(state) => (&mut state.validators, &mut state.balances),
|
||||
BeaconState::Altair(state) => (&mut state.validators, &mut state.balances),
|
||||
BeaconState::Merge(state) => (&mut state.validators, &mut state.balances),
|
||||
}
|
||||
|
||||
#[cfg(feature = "milhouse")]
|
||||
match self {
|
||||
BeaconState::Base(state) => (state.validators.as_mut(), state.balances.as_mut()),
|
||||
BeaconState::Altair(state) => (state.validators.as_mut(), state.balances.as_mut()),
|
||||
BeaconState::Merge(state) => (state.validators.as_mut(), state.balances.as_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block_roots(&self) -> &FixedVector<Hash256, T::SlotsPerHistoricalRoot> {
|
||||
self.block_roots_raw()
|
||||
}
|
||||
|
||||
pub fn block_roots_mut(&mut self) -> VectMut<Hash256, T::SlotsPerHistoricalRoot> {
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
{
|
||||
self.block_roots_raw_mut()
|
||||
}
|
||||
#[cfg(feature = "milhouse")]
|
||||
{
|
||||
self.block_roots_raw_mut().as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state_roots(&self) -> &FixedVector<Hash256, T::SlotsPerHistoricalRoot> {
|
||||
self.state_roots_raw()
|
||||
}
|
||||
|
||||
pub fn state_roots_mut(&mut self) -> VectMut<Hash256, T::SlotsPerHistoricalRoot> {
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
{
|
||||
self.state_roots_raw_mut()
|
||||
}
|
||||
#[cfg(feature = "milhouse")]
|
||||
{
|
||||
self.state_roots_raw_mut().as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn randao_mixes(&self) -> &FixedVector<Hash256, T::EpochsPerHistoricalVector> {
|
||||
self.randao_mixes_raw()
|
||||
}
|
||||
|
||||
pub fn randao_mixes_mut(&mut self) -> VectMut<Hash256, T::EpochsPerHistoricalVector> {
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
{
|
||||
self.randao_mixes_raw_mut()
|
||||
}
|
||||
#[cfg(feature = "milhouse")]
|
||||
{
|
||||
self.randao_mixes_raw_mut().as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn slashings(&self) -> &FixedVector<u64, T::EpochsPerSlashingsVector> {
|
||||
self.slashings_raw()
|
||||
}
|
||||
|
||||
pub fn slashings_mut(&mut self) -> VectMut<u64, T::EpochsPerSlashingsVector> {
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
{
|
||||
self.slashings_raw_mut()
|
||||
}
|
||||
#[cfg(feature = "milhouse")]
|
||||
{
|
||||
self.slashings_raw_mut().as_mut()
|
||||
}
|
||||
/// 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()
|
||||
.get_mut(validator_index)
|
||||
.ok_or(Error::BalancesOutOfBounds(validator_index))
|
||||
}
|
||||
|
||||
/// Generate a seed for the given `epoch`.
|
||||
@@ -1293,14 +1176,22 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
.ok_or(Error::UnknownValidator(validator_index))
|
||||
}
|
||||
|
||||
/* FIXME(sproul): lens?
|
||||
/// Safe mutator for the `validators` list.
|
||||
pub fn get_validator_mut(&mut self, validator_index: usize) -> Result<&mut Validator, Error> {
|
||||
self.validators_mut()
|
||||
.get_mut(validator_index)
|
||||
.ok_or(Error::UnknownValidator(validator_index))
|
||||
}
|
||||
*/
|
||||
|
||||
/// Safe copy-on-write accessor for the `validators` list.
|
||||
pub fn get_validator_cow(
|
||||
&mut self,
|
||||
validator_index: usize,
|
||||
) -> Result<milhouse::Cow<Validator>, Error> {
|
||||
self.validators_mut()
|
||||
.get_cow(validator_index)
|
||||
.ok_or(Error::UnknownValidator(validator_index))
|
||||
}
|
||||
|
||||
/// Return the effective balance for a validator with the given `validator_index`.
|
||||
pub fn get_effective_balance(&self, validator_index: usize) -> Result<u64, Error> {
|
||||
@@ -1387,6 +1278,28 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn compute_total_active_balance(
|
||||
&self,
|
||||
epoch: Epoch,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<u64, Error> {
|
||||
if epoch != self.current_epoch() && epoch != self.next_epoch()? {
|
||||
return Err(Error::EpochOutOfBounds);
|
||||
}
|
||||
|
||||
let mut total_active_balance = 0;
|
||||
|
||||
for validator in self.validators() {
|
||||
if validator.is_active_at(epoch) {
|
||||
total_active_balance.safe_add_assign(validator.effective_balance)?;
|
||||
}
|
||||
}
|
||||
Ok(std::cmp::max(
|
||||
total_active_balance,
|
||||
spec.effective_balance_increment,
|
||||
))
|
||||
}
|
||||
|
||||
/// Implementation of `get_total_active_balance`, matching the spec.
|
||||
///
|
||||
/// Requires the total active balance cache to be initialised, which is initialised whenever
|
||||
@@ -1410,16 +1323,9 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
}
|
||||
|
||||
/// Build the total active balance cache.
|
||||
///
|
||||
/// This function requires the current committee cache to be already built. It is called
|
||||
/// automatically when `build_committee_cache` is called for the current epoch.
|
||||
fn build_total_active_balance_cache(&mut self, spec: &ChainSpec) -> Result<(), Error> {
|
||||
// Order is irrelevant, so use the cached indices.
|
||||
let current_epoch = self.current_epoch();
|
||||
let total_active_balance = self.get_total_balance(
|
||||
self.get_cached_active_validator_indices(RelativeEpoch::Current)?,
|
||||
spec,
|
||||
)?;
|
||||
let total_active_balance = self.compute_total_active_balance(current_epoch, spec)?;
|
||||
*self.total_active_balance_mut() = Some((current_epoch, total_active_balance));
|
||||
Ok(())
|
||||
}
|
||||
@@ -1578,10 +1484,9 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
// not yet been advanced.
|
||||
let new_current_epoch = self.next_epoch()?;
|
||||
if curr_cache.is_initialized_at(new_current_epoch) {
|
||||
*self.total_active_balance_mut() = Some((
|
||||
new_current_epoch,
|
||||
self.get_total_balance(curr_cache.active_validator_indices(), spec)?,
|
||||
));
|
||||
let total_active_balance =
|
||||
self.compute_total_active_balance(new_current_epoch, spec)?;
|
||||
*self.total_active_balance_mut() = Some((new_current_epoch, total_active_balance));
|
||||
}
|
||||
// If the cache is not initialized, then the previous cached value for the total balance is
|
||||
// wrong, so delete it.
|
||||
@@ -1671,6 +1576,38 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
*self.pubkey_cache_mut() = PubkeyCache::default()
|
||||
}
|
||||
|
||||
/// Check if the `BeaconState` has any pending mutations.
|
||||
pub fn has_pending_mutations(&self) -> bool {
|
||||
// FIXME(sproul): check this more thoroughly
|
||||
self.block_roots().has_pending_updates()
|
||||
|| self.state_roots().has_pending_updates()
|
||||
|| self.historical_roots().has_pending_updates()
|
||||
|| self.eth1_data_votes().has_pending_updates()
|
||||
|| self.validators().has_pending_updates()
|
||||
|| self.balances().has_pending_updates()
|
||||
|| self.randao_mixes().has_pending_updates()
|
||||
|| self.slashings().has_pending_updates()
|
||||
|| self
|
||||
.inactivity_scores()
|
||||
.map_or(false, VList::has_pending_updates)
|
||||
}
|
||||
|
||||
pub fn apply_pending_mutations(&mut self) -> Result<(), Error> {
|
||||
self.block_roots_mut().apply_updates()?;
|
||||
self.state_roots_mut().apply_updates()?;
|
||||
self.historical_roots_mut().apply_updates()?;
|
||||
self.eth1_data_votes_mut().apply_updates()?;
|
||||
self.validators_mut().apply_updates()?;
|
||||
self.balances_mut().apply_updates()?;
|
||||
self.randao_mixes_mut().apply_updates()?;
|
||||
self.slashings_mut().apply_updates()?;
|
||||
|
||||
if let Ok(inactivity_scores) = self.inactivity_scores_mut() {
|
||||
inactivity_scores.apply_updates()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialize but don't fill the tree hash cache, if it isn't already initialized.
|
||||
pub fn initialize_tree_hash_cache(&mut self) {
|
||||
#[cfg(not(feature = "milhouse"))]
|
||||
@@ -1700,7 +1637,10 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "milhouse")]
|
||||
Ok(self.tree_hash_root())
|
||||
{
|
||||
self.apply_pending_mutations()?;
|
||||
Ok(self.tree_hash_root())
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the tree hash root of the validators using the tree hash cache.
|
||||
@@ -1724,7 +1664,10 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "milhouse")]
|
||||
Ok(self.validators().tree_hash_root())
|
||||
{
|
||||
self.validators_mut().apply_updates()?;
|
||||
Ok(self.validators().tree_hash_root())
|
||||
}
|
||||
}
|
||||
|
||||
/// Completely drops the tree hash cache, replacing it with a new, empty cache.
|
||||
|
||||
@@ -66,7 +66,6 @@ pub mod voluntary_exit;
|
||||
pub mod slot_epoch_macros;
|
||||
pub mod config_and_preset;
|
||||
pub mod fork_context;
|
||||
pub mod mixin;
|
||||
pub mod participation_flags;
|
||||
pub mod participation_list;
|
||||
pub mod preset;
|
||||
@@ -123,7 +122,6 @@ pub use crate::free_attestation::FreeAttestation;
|
||||
pub use crate::graffiti::{Graffiti, GRAFFITI_BYTES_LEN};
|
||||
pub use crate::historical_batch::HistoricalBatch;
|
||||
pub use crate::indexed_attestation::IndexedAttestation;
|
||||
pub use crate::mixin::{GetBalanceMut, GetValidatorMut};
|
||||
pub use crate::participation_flags::ParticipationFlags;
|
||||
pub use crate::participation_list::ParticipationList;
|
||||
pub use crate::pending_attestation::PendingAttestation;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
use crate::beacon_state::{BalancesMut, Error, ValidatorsMut};
|
||||
use crate::{Unsigned, Validator};
|
||||
|
||||
pub trait GetValidatorMut {
|
||||
fn get_validator(&self, index: usize) -> Result<&Validator, Error>;
|
||||
|
||||
fn get_validator_mut(&mut self, index: usize) -> Result<&mut Validator, Error>;
|
||||
}
|
||||
|
||||
impl<'a, N: Unsigned> GetValidatorMut for ValidatorsMut<'a, N> {
|
||||
fn get_validator(&self, index: usize) -> Result<&Validator, Error> {
|
||||
self.get(index).ok_or(Error::UnknownValidator(index))
|
||||
}
|
||||
|
||||
fn get_validator_mut(&mut self, index: usize) -> Result<&mut Validator, Error> {
|
||||
self.get_mut(index).ok_or(Error::UnknownValidator(index))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GetBalanceMut {
|
||||
fn get_balance(&self, index: usize) -> Result<u64, Error>;
|
||||
|
||||
fn get_balance_mut(&mut self, index: usize) -> Result<&mut u64, Error>;
|
||||
}
|
||||
|
||||
impl<'a, N: Unsigned> GetBalanceMut for BalancesMut<'a, N> {
|
||||
fn get_balance(&self, index: usize) -> Result<u64, Error> {
|
||||
self.get(index)
|
||||
.copied()
|
||||
.ok_or(Error::BalancesOutOfBounds(index))
|
||||
}
|
||||
|
||||
fn get_balance_mut(&mut self, index: usize) -> Result<&mut u64, Error> {
|
||||
self.get_mut(index).ok_or(Error::BalancesOutOfBounds(index))
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ pub fn run<T: EthSpec>(testnet_dir: PathBuf, matches: &ArgMatches) -> Result<(),
|
||||
|
||||
let mut deposit_tree = DepositDataTree::create(&[], 0, DEPOSIT_TREE_DEPTH);
|
||||
let mut deposit_root = Hash256::zero();
|
||||
let mut validators = state.validators_mut();
|
||||
let validators = state.validators_mut();
|
||||
for index in 0..validators.len() {
|
||||
let (secret, _) =
|
||||
recover_validator_secret_from_mnemonic(seed.as_bytes(), index as u32, KeyType::Voting)
|
||||
|
||||
Reference in New Issue
Block a user