This commit is contained in:
Michael Sproul
2022-02-08 09:48:48 +11:00
parent f6230a5143
commit 0c742aedff
17 changed files with 152 additions and 244 deletions

2
Cargo.lock generated
View File

@@ -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",

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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(())
}

View File

@@ -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(())
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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,
)?;

View File

@@ -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();

View File

@@ -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,
);

View File

@@ -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(())

View File

@@ -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);
}
}

View File

@@ -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()?);

View File

@@ -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.

View File

@@ -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;

View File

@@ -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))
}
}

View File

@@ -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)