diff --git a/Cargo.lock b/Cargo.lock index ac14f6e231..c1aa1b7abb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3481,6 +3481,7 @@ dependencies = [ "eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot", "serde", + "smallvec", "tree_hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "typenum", ] @@ -5611,6 +5612,7 @@ dependencies = [ "sloggers", "state_processing", "tempfile", + "tree_hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "types", ] diff --git a/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs b/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs index 34903aed5d..66a99e1f42 100644 --- a/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs +++ b/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs @@ -217,12 +217,13 @@ where }; let finalized_checkpoint = justified_checkpoint; + // FIXME(sproul): avoid `to_vec` perf penalty Self { store, balances_cache: <_>::default(), time: anchor_state.slot(), justified_checkpoint, - justified_balances: anchor_state.balances().clone().into(), + justified_balances: anchor_state.balances().to_vec(), finalized_checkpoint, best_justified_checkpoint: justified_checkpoint, _phantom: PhantomData, @@ -327,8 +328,7 @@ where .map_err(Error::FailedToReadState)? .ok_or_else(|| Error::MissingState(justified_block.state_root()))? .balances() - .clone() - .into(); + .to_vec(); } Ok(()) diff --git a/beacon_node/store/Cargo.toml b/beacon_node/store/Cargo.toml index bfd865ba0b..74b38e2034 100644 --- a/beacon_node/store/Cargo.toml +++ b/beacon_node/store/Cargo.toml @@ -25,6 +25,7 @@ lighthouse_metrics = { path = "../../common/lighthouse_metrics" } lru = "0.6.0" sloggers = "2.0.2" directory = { path = "../../common/directory" } +tree_hash = "0.4.0" [features] milhouse = ["state_processing/milhouse"] diff --git a/beacon_node/store/src/chunked_vector.rs b/beacon_node/store/src/chunked_vector.rs index fdad5cc87e..6f60cf1fe3 100644 --- a/beacon_node/store/src/chunked_vector.rs +++ b/beacon_node/store/src/chunked_vector.rs @@ -17,6 +17,7 @@ use self::UpdatePattern::*; use crate::*; use ssz::{Decode, Encode}; +use tree_hash::TreeHash; use typenum::Unsigned; use types::VList; @@ -56,7 +57,7 @@ pub trait Field: Copy { /// The type of value stored in this field: the `T` from `FixedVector`. /// /// The `Default` impl will be used to fill extra vector entries. - type Value: Decode + Encode + Default + Clone + PartialEq + std::fmt::Debug; + type Value: TreeHash + Decode + Encode + Default + Clone + PartialEq + std::fmt::Debug; /// The length of this field: the `N` from `FixedVector`. type Length: Unsigned; diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index 127bfc665f..eacff1b192 100644 --- a/beacon_node/store/src/partial_beacon_state.rs +++ b/beacon_node/store/src/partial_beacon_state.rs @@ -48,7 +48,7 @@ where // Registry pub validators: VList, - pub balances: VariableList, + pub balances: VList, // Shuffling /// Randao value from the current slot, for patching into the per-epoch randao vector. diff --git a/consensus/fork_choice/src/fork_choice.rs b/consensus/fork_choice/src/fork_choice.rs index d0aa8abc1d..af44176eb7 100644 --- a/consensus/fork_choice/src/fork_choice.rs +++ b/consensus/fork_choice/src/fork_choice.rs @@ -352,12 +352,15 @@ where let store = &mut self.fc_store; + // FIXME(sproul): plumb VList through fork choice + let justified_balances = store.justified_balances().to_vec(); + self.proto_array .find_head( store.justified_checkpoint().epoch, store.justified_checkpoint().root, store.finalized_checkpoint().epoch, - store.justified_balances(), + &justified_balances, ) .map_err(Into::into) } diff --git a/consensus/state_processing/src/common/mod.rs b/consensus/state_processing/src/common/mod.rs index 334a293ed5..a1e4f673b8 100644 --- a/consensus/state_processing/src/common/mod.rs +++ b/consensus/state_processing/src/common/mod.rs @@ -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}; +use types::{BeaconState, BeaconStateError, EthSpec, GetBalanceMut}; /// Increase the balance of a validator, erroring upon overflow, as per the spec. pub fn increase_balance( @@ -24,7 +24,10 @@ pub fn increase_balance( index: usize, delta: u64, ) -> Result<(), BeaconStateError> { - state.get_balance_mut(index)?.safe_add_assign(delta)?; + state + .balances_mut() + .get_balance_mut(index)? + .safe_add_assign(delta)?; Ok(()) } @@ -34,7 +37,8 @@ pub fn decrease_balance( index: usize, delta: u64, ) -> Result<(), BeaconStateError> { - let balance = state.get_balance_mut(index)?; + let mut balances = state.balances_mut(); + let balance = balances.get_balance_mut(index)?; *balance = balance.saturating_sub(delta); Ok(()) } diff --git a/consensus/state_processing/src/per_epoch_processing/slashings.rs b/consensus/state_processing/src/per_epoch_processing/slashings.rs index 2721abbe7b..c2d456c494 100644 --- a/consensus/state_processing/src/per_epoch_processing/slashings.rs +++ b/consensus/state_processing/src/per_epoch_processing/slashings.rs @@ -1,6 +1,6 @@ use crate::per_epoch_processing::Error; use safe_arith::{SafeArith, SafeArithIter}; -use types::{BeaconState, BeaconStateError, ChainSpec, EthSpec, GetValidatorMut, Unsigned}; +use types::{BeaconState, ChainSpec, EthSpec, GetBalanceMut, GetValidatorMut, Unsigned}; /// Process slashings. pub fn process_slashings( @@ -15,7 +15,7 @@ pub fn process_slashings( let adjusted_total_slashing_balance = std::cmp::min(sum_slashings.safe_mul(slashing_multiplier)?, total_balance); - let (validators, balances) = state.validators_and_balances_mut(); + let (validators, mut balances) = state.validators_and_balances_mut(); for index in 0..validators.len() { let validator = validators.get_validator(index)?; if validator.slashed @@ -32,9 +32,7 @@ pub fn process_slashings( .safe_mul(increment)?; // Equivalent to `decrease_balance(state, index, penalty)`, but avoids borrowing `state`. - let balance = balances - .get_mut(index) - .ok_or(BeaconStateError::BalancesOutOfBounds(index))?; + let balance = balances.get_balance_mut(index)?; *balance = balance.saturating_sub(penalty); } } diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index 5859264212..f9373019b7 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -53,6 +53,11 @@ pub type ValidatorsMut<'a, N> = ListMut<'a, Validator, N>; #[cfg(not(feature = "milhouse"))] pub type ValidatorsMut<'a, N> = &'a mut VList; +#[cfg(feature = "milhouse")] +pub type BalancesMut<'a, N> = ListMut<'a, u64, N>; +#[cfg(not(feature = "milhouse"))] +pub type BalancesMut<'a, N> = ListMut<'a, u64, N>; + pub const CACHED_EPOCHS: usize = 3; const MAX_RANDOM_BYTE: u64 = (1 << 8) - 1; @@ -251,9 +256,11 @@ where #[superstruct(getter(rename = "validators_raw"))] #[test_random(default)] pub validators: VList, - #[compare_fields(as_slice)] - #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")] - pub balances: VariableList, + // 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, // Randomness pub randao_mixes: FixedVector, @@ -365,8 +372,8 @@ impl BeaconState { eth1_deposit_index: 0, // Validator registry - validators: VList::empty(), // Set later. - balances: VariableList::empty(), // Set later. + validators: VList::empty(), // Set later. + balances: VList::empty(), // Set later. // Randomness randao_mixes: FixedVector::from_elem(Hash256::zero()), @@ -1122,10 +1129,28 @@ impl BeaconState { } } + pub fn balances(&self) -> &VList { + self.balances_raw() + } + + pub fn balances_mut(&mut self) -> BalancesMut { + #[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, &mut [u64]) { + ) -> ( + ValidatorsMut, + BalancesMut, + ) { #[cfg(not(feature = "milhouse"))] match self { BeaconState::Base(state) => (&mut state.validators, &mut state.balances), @@ -1134,8 +1159,8 @@ impl BeaconState { #[cfg(feature = "milhouse")] match self { - BeaconState::Base(state) => (state.validators.as_mut(), &mut state.balances), - BeaconState::Altair(state) => (state.validators.as_mut(), &mut state.balances), + BeaconState::Base(state) => (state.validators.as_mut(), state.balances.as_mut()), + BeaconState::Altair(state) => (state.validators.as_mut(), state.balances.as_mut()), } } @@ -1215,13 +1240,6 @@ impl BeaconState { .ok_or(Error::InactivityScoresOutOfBounds(validator_index)) } - /// 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)) - } - /// Return the epoch at which an activation or exit triggered in ``epoch`` takes effect. /// /// Spec v0.12.1 diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index de41093be0..86a8aca98a 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -118,7 +118,7 @@ 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::GetValidatorMut; +pub use crate::mixin::{GetBalanceMut, GetValidatorMut}; pub use crate::participation_flags::ParticipationFlags; pub use crate::participation_list::ParticipationList; pub use crate::pending_attestation::PendingAttestation; diff --git a/consensus/types/src/mixin.rs b/consensus/types/src/mixin.rs index 2735cf35cb..41f2203740 100644 --- a/consensus/types/src/mixin.rs +++ b/consensus/types/src/mixin.rs @@ -1,4 +1,4 @@ -use crate::beacon_state::{Error, ValidatorsMut}; +use crate::beacon_state::{BalancesMut, Error, ValidatorsMut}; use crate::{Unsigned, Validator}; pub trait GetValidatorMut { @@ -16,3 +16,21 @@ impl<'a, N: Unsigned> GetValidatorMut for ValidatorsMut<'a, N> { self.get_mut(index).ok_or(Error::UnknownValidator(index)) } } + +pub trait GetBalanceMut { + fn get_balance(&self, index: usize) -> Result; + + 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 { + 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)) + } +}