From 9a1799f23531eaccfd0c021e94c8501892d21416 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 28 Sep 2022 11:43:58 +1000 Subject: [PATCH] Split validator into ValidatorMutable --- account_manager/src/validator/exit.rs | 8 +- .../src/beacon_fork_choice_store.rs | 2 +- beacon_node/beacon_chain/src/metrics.rs | 2 +- .../beacon_chain/src/validator_monitor.rs | 12 +-- .../http_api/src/validator_inclusion.rs | 4 +- beacon_node/operation_pool/src/lib.rs | 8 +- common/eth2/src/types.rs | 12 +-- .../src/common/initiate_validator_exit.rs | 6 +- .../src/common/slash_validator.rs | 8 +- consensus/state_processing/src/genesis.rs | 8 +- .../src/per_block_processing.rs | 2 +- .../process_operations.rs | 22 +++--- .../src/per_block_processing/verify_exit.rs | 4 +- .../altair/participation_cache.rs | 18 ++--- .../base/validator_statuses.rs | 2 +- .../effective_balance_updates.rs | 10 +-- .../per_epoch_processing/registry_updates.rs | 8 +- .../src/per_epoch_processing/slashings.rs | 4 +- consensus/types/src/beacon_state.rs | 8 +- .../types/src/beacon_state/exit_cache.rs | 4 +- consensus/types/src/lib.rs | 2 +- consensus/types/src/validator.rs | 76 ++++++++++++++----- 22 files changed, 133 insertions(+), 97 deletions(-) diff --git a/account_manager/src/validator/exit.rs b/account_manager/src/validator/exit.rs index ca8cab5bd3..934a8a6816 100644 --- a/account_manager/src/validator/exit.rs +++ b/account_manager/src/validator/exit.rs @@ -212,8 +212,8 @@ async fn publish_voluntary_exit( let validator_data = get_validator_data(client, &keypair.pk).await?; match validator_data.status { ValidatorStatus::ActiveExiting => { - let exit_epoch = validator_data.validator.exit_epoch; - let withdrawal_epoch = validator_data.validator.withdrawable_epoch; + let exit_epoch = validator_data.validator.exit_epoch(); + let withdrawal_epoch = validator_data.validator.withdrawable_epoch(); let current_epoch = get_current_epoch::(genesis_data.genesis_time, spec) .ok_or("Failed to get current epoch. Please check your system time")?; eprintln!("Voluntary exit has been accepted into the beacon chain, but not yet finalized. \ @@ -233,7 +233,7 @@ async fn publish_voluntary_exit( ValidatorStatus::ExitedSlashed | ValidatorStatus::ExitedUnslashed => { eprintln!( "Validator has exited on epoch: {}", - validator_data.validator.exit_epoch + validator_data.validator.exit_epoch() ); break; } @@ -259,7 +259,7 @@ async fn get_validator_index_for_exit( ValidatorStatus::ActiveOngoing => { let eligible_epoch = validator_data .validator - .activation_epoch + .activation_epoch() .safe_add(spec.shard_committee_period) .map_err(|e| format!("Failed to calculate eligible epoch, validator activation epoch too high: {:?}", e))?; 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 dc8ac21c21..a21db19725 100644 --- a/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs +++ b/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs @@ -52,7 +52,7 @@ pub fn get_effective_balances(state: &BeaconState) -> Vec { .iter() .map(|validator| { if validator.is_active_at(state.current_epoch()) { - validator.effective_balance + validator.effective_balance() } else { 0 } diff --git a/beacon_node/beacon_chain/src/metrics.rs b/beacon_node/beacon_chain/src/metrics.rs index 8e56a34bae..a3c7c94865 100644 --- a/beacon_node/beacon_chain/src/metrics.rs +++ b/beacon_node/beacon_chain/src/metrics.rs @@ -1084,7 +1084,7 @@ fn scrape_head_state(state: &BeaconState, state_root: Hash256) { num_active += 1; } - if v.slashed { + if v.slashed() { num_slashed += 1; } diff --git a/beacon_node/beacon_chain/src/validator_monitor.rs b/beacon_node/beacon_chain/src/validator_monitor.rs index 9242ef4b36..6761935f87 100644 --- a/beacon_node/beacon_chain/src/validator_monitor.rs +++ b/beacon_node/beacon_chain/src/validator_monitor.rs @@ -327,12 +327,12 @@ impl ValidatorMonitor { metrics::set_int_gauge( &metrics::VALIDATOR_MONITOR_EFFECTIVE_BALANCE_GWEI, &[id], - u64_to_i64(validator.effective_balance), + u64_to_i64(validator.effective_balance()), ); metrics::set_int_gauge( &metrics::VALIDATOR_MONITOR_SLASHED, &[id], - if validator.slashed { 1 } else { 0 }, + if validator.slashed() { 1 } else { 0 }, ); metrics::set_int_gauge( &metrics::VALIDATOR_MONITOR_ACTIVE, @@ -364,22 +364,22 @@ impl ValidatorMonitor { metrics::set_int_gauge( &metrics::VALIDATOR_ACTIVATION_ELIGIBILITY_EPOCH, &[id], - u64_to_i64(validator.activation_eligibility_epoch), + u64_to_i64(validator.activation_eligibility_epoch()), ); metrics::set_int_gauge( &metrics::VALIDATOR_ACTIVATION_EPOCH, &[id], - u64_to_i64(validator.activation_epoch), + u64_to_i64(validator.activation_epoch()), ); metrics::set_int_gauge( &metrics::VALIDATOR_EXIT_EPOCH, &[id], - u64_to_i64(validator.exit_epoch), + u64_to_i64(validator.exit_epoch()), ); metrics::set_int_gauge( &metrics::VALIDATOR_WITHDRAWABLE_EPOCH, &[id], - u64_to_i64(validator.withdrawable_epoch), + u64_to_i64(validator.withdrawable_epoch()), ); } } diff --git a/beacon_node/http_api/src/validator_inclusion.rs b/beacon_node/http_api/src/validator_inclusion.rs index 917e85e649..9be4fdde20 100644 --- a/beacon_node/http_api/src/validator_inclusion.rs +++ b/beacon_node/http_api/src/validator_inclusion.rs @@ -99,13 +99,13 @@ pub fn validator_inclusion_data( let summary = get_epoch_processing_summary(&mut state, &chain.spec)?; Ok(Some(ValidatorInclusionData { - is_slashed: validator.slashed, + is_slashed: validator.slashed(), is_withdrawable_in_current_epoch: validator.is_withdrawable_at(epoch), is_active_unslashed_in_current_epoch: summary .is_active_unslashed_in_current_epoch(validator_index), is_active_unslashed_in_previous_epoch: summary .is_active_unslashed_in_previous_epoch(validator_index), - current_epoch_effective_balance_gwei: validator.effective_balance, + current_epoch_effective_balance_gwei: validator.effective_balance(), is_current_epoch_target_attester: summary .is_current_epoch_target_attester(validator_index) .map_err(convert_cache_error)?, diff --git a/beacon_node/operation_pool/src/lib.rs b/beacon_node/operation_pool/src/lib.rs index 8c335189c6..4f1e20521b 100644 --- a/beacon_node/operation_pool/src/lib.rs +++ b/beacon_node/operation_pool/src/lib.rs @@ -370,7 +370,7 @@ impl OperationPool { && state .validators() .get(slashing.as_inner().signed_header_1.message.proposer_index as usize) - .map_or(false, |validator| !validator.slashed) + .map_or(false, |validator| !validator.slashed()) }, |slashing| slashing.as_inner().clone(), T::MaxProposerSlashings::to_usize(), @@ -429,7 +429,7 @@ impl OperationPool { pub fn prune_proposer_slashings(&self, head_state: &BeaconState) { prune_validator_hash_map( &mut self.proposer_slashings.write(), - |validator| validator.exit_epoch <= head_state.finalized_checkpoint().epoch, + |validator| validator.exit_epoch() <= head_state.finalized_checkpoint().epoch, head_state, ); } @@ -448,7 +448,7 @@ impl OperationPool { // // We cannot check the `slashed` field since the `head` is not finalized and // a fork could un-slash someone. - validator.exit_epoch > head_state.finalized_checkpoint().epoch + validator.exit_epoch() > head_state.finalized_checkpoint().epoch }) .map_or(false, |indices| !indices.is_empty()); @@ -504,7 +504,7 @@ impl OperationPool { // // We choose simplicity over the gain of pruning more exits since they are small and // should not be seen frequently. - |validator| validator.exit_epoch <= head_state.finalized_checkpoint().epoch, + |validator| validator.exit_epoch() <= head_state.finalized_checkpoint().epoch, head_state, ); } diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index 878af57a1f..468f719269 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -347,20 +347,20 @@ pub enum ValidatorStatus { impl ValidatorStatus { pub fn from_validator(validator: &Validator, epoch: Epoch, far_future_epoch: Epoch) -> Self { if validator.is_withdrawable_at(epoch) { - if validator.effective_balance == 0 { + if validator.effective_balance() == 0 { ValidatorStatus::WithdrawalDone } else { ValidatorStatus::WithdrawalPossible } - } else if validator.is_exited_at(epoch) && epoch < validator.withdrawable_epoch { - if validator.slashed { + } else if validator.is_exited_at(epoch) && epoch < validator.withdrawable_epoch() { + if validator.slashed() { ValidatorStatus::ExitedSlashed } else { ValidatorStatus::ExitedUnslashed } } else if validator.is_active_at(epoch) { - if validator.exit_epoch < far_future_epoch { - if validator.slashed { + if validator.exit_epoch() < far_future_epoch { + if validator.slashed() { ValidatorStatus::ActiveSlashed } else { ValidatorStatus::ActiveExiting @@ -371,7 +371,7 @@ impl ValidatorStatus { // `pending` statuses are specified as validators where `validator.activation_epoch > current_epoch`. // If this code is reached, this criteria must have been met because `validator.is_active_at(epoch)`, // `validator.is_exited_at(epoch)`, and `validator.is_withdrawable_at(epoch)` all returned false. - } else if validator.activation_eligibility_epoch == far_future_epoch { + } else if validator.activation_eligibility_epoch() == far_future_epoch { ValidatorStatus::PendingInitialized } else { ValidatorStatus::PendingQueued diff --git a/consensus/state_processing/src/common/initiate_validator_exit.rs b/consensus/state_processing/src/common/initiate_validator_exit.rs index a2bb47ebe0..4ac8798d2d 100644 --- a/consensus/state_processing/src/common/initiate_validator_exit.rs +++ b/consensus/state_processing/src/common/initiate_validator_exit.rs @@ -9,7 +9,7 @@ pub fn initiate_validator_exit( spec: &ChainSpec, ) -> Result<(), Error> { // Return if the validator already initiated exit - if state.get_validator(index)?.exit_epoch != spec.far_future_epoch { + if state.get_validator(index)?.exit_epoch() != spec.far_future_epoch { return Ok(()); } @@ -34,8 +34,8 @@ pub fn initiate_validator_exit( // 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 = + validator.mutable.exit_epoch = exit_queue_epoch; + validator.mutable.withdrawable_epoch = exit_queue_epoch.safe_add(spec.min_validator_withdrawability_delay)?; Ok(()) diff --git a/consensus/state_processing/src/common/slash_validator.rs b/consensus/state_processing/src/common/slash_validator.rs index e9d94a1062..ea107643ab 100644 --- a/consensus/state_processing/src/common/slash_validator.rs +++ b/consensus/state_processing/src/common/slash_validator.rs @@ -18,12 +18,12 @@ pub fn slash_validator( initiate_validator_exit(state, slashed_index, spec)?; let validator = state.get_validator_mut(slashed_index)?; - validator.slashed = true; - validator.withdrawable_epoch = cmp::max( - validator.withdrawable_epoch, + validator.mutable.slashed = true; + validator.mutable.withdrawable_epoch = cmp::max( + validator.withdrawable_epoch(), epoch.safe_add(T::EpochsPerSlashingsVector::to_u64())?, ); - let validator_effective_balance = validator.effective_balance; + let validator_effective_balance = validator.effective_balance(); state.set_slashings( epoch, state diff --git a/consensus/state_processing/src/genesis.rs b/consensus/state_processing/src/genesis.rs index 274664816e..8de3581279 100644 --- a/consensus/state_processing/src/genesis.rs +++ b/consensus/state_processing/src/genesis.rs @@ -104,13 +104,13 @@ pub fn process_activations( .get(index) .copied() .ok_or(Error::BalancesOutOfBounds(index))?; - validator.effective_balance = std::cmp::min( + validator.mutable.effective_balance = std::cmp::min( balance.safe_sub(balance.safe_rem(spec.effective_balance_increment)?)?, spec.max_effective_balance, ); - if validator.effective_balance == spec.max_effective_balance { - validator.activation_eligibility_epoch = T::genesis_epoch(); - validator.activation_epoch = T::genesis_epoch(); + if validator.effective_balance() == spec.max_effective_balance { + validator.mutable.activation_eligibility_epoch = T::genesis_epoch(); + validator.mutable.activation_epoch = T::genesis_epoch(); } } Ok(()) diff --git a/consensus/state_processing/src/per_block_processing.rs b/consensus/state_processing/src/per_block_processing.rs index eca27c82e0..da20146a6d 100644 --- a/consensus/state_processing/src/per_block_processing.rs +++ b/consensus/state_processing/src/per_block_processing.rs @@ -227,7 +227,7 @@ pub fn process_block_header( // Verify proposer is not slashed verify!( - !state.get_validator(proposer_index as usize)?.slashed, + !state.get_validator(proposer_index as usize)?.slashed(), HeaderInvalid::ProposerSlashed(proposer_index) ); diff --git a/consensus/state_processing/src/per_block_processing/process_operations.rs b/consensus/state_processing/src/per_block_processing/process_operations.rs index e71ca5f8e9..3a870cb2ba 100644 --- a/consensus/state_processing/src/per_block_processing/process_operations.rs +++ b/consensus/state_processing/src/per_block_processing/process_operations.rs @@ -146,7 +146,7 @@ pub mod altair { { // FIXME(sproul): add effective balance cache here? validator_participation.add_flag(flag_index)?; - let effective_balance = state.get_validator(index)?.effective_balance; + let effective_balance = state.get_validator(index)?.effective_balance(); proposer_reward_numerator.safe_add_assign( get_base_reward(effective_balance, base_reward_per_increment, spec)? .safe_mul(weight)?, @@ -347,15 +347,17 @@ pub fn process_deposit( pubkey: deposit.data.pubkey, withdrawal_credentials: deposit.data.withdrawal_credentials, }), - activation_eligibility_epoch: spec.far_future_epoch, - activation_epoch: spec.far_future_epoch, - exit_epoch: spec.far_future_epoch, - withdrawable_epoch: spec.far_future_epoch, - effective_balance: std::cmp::min( - amount.safe_sub(amount.safe_rem(spec.effective_balance_increment)?)?, - spec.max_effective_balance, - ), - slashed: false, + mutable: ValidatorMutable { + activation_eligibility_epoch: spec.far_future_epoch, + activation_epoch: spec.far_future_epoch, + exit_epoch: spec.far_future_epoch, + withdrawable_epoch: spec.far_future_epoch, + effective_balance: std::cmp::min( + amount.safe_sub(amount.safe_rem(spec.effective_balance_increment)?)?, + spec.max_effective_balance, + ), + slashed: false, + }, }; state.validators_mut().push(validator)?; state.balances_mut().push(deposit.data.amount)?; diff --git a/consensus/state_processing/src/per_block_processing/verify_exit.rs b/consensus/state_processing/src/per_block_processing/verify_exit.rs index f17e5fcd23..7fd29e3194 100644 --- a/consensus/state_processing/src/per_block_processing/verify_exit.rs +++ b/consensus/state_processing/src/per_block_processing/verify_exit.rs @@ -39,7 +39,7 @@ pub fn verify_exit( // Verify that the validator has not yet exited. verify!( - validator.exit_epoch == spec.far_future_epoch, + validator.exit_epoch() == spec.far_future_epoch, ExitInvalid::AlreadyExited(exit.validator_index) ); @@ -54,7 +54,7 @@ pub fn verify_exit( // Verify the validator has been active long enough. let earliest_exit_epoch = validator - .activation_epoch + .activation_epoch() .safe_add(spec.shard_committee_period)?; verify!( state.current_epoch() >= earliest_exit_epoch, diff --git a/consensus/state_processing/src/per_epoch_processing/altair/participation_cache.rs b/consensus/state_processing/src/per_epoch_processing/altair/participation_cache.rs index 52d372bb56..fa5379a945 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair/participation_cache.rs +++ b/consensus/state_processing/src/per_epoch_processing/altair/participation_cache.rs @@ -129,10 +129,10 @@ impl SingleEpochParticipationCache { // All active validators increase the total active balance. self.total_active_balance - .safe_add_assign(validator.effective_balance)?; + .safe_add_assign(validator.effective_balance())?; // Only unslashed validators may proceed. - if validator.slashed { + if validator.slashed() { return Ok(()); } @@ -140,7 +140,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(validator.effective_balance)?; + balance.safe_add_assign(validator.effective_balance())?; } } @@ -288,11 +288,11 @@ impl ParticipationCache { )?; } - if val.slashed + if val.slashed() && current_epoch.safe_add(T::EpochsPerSlashingsVector::to_u64().safe_div(2)?)? - == val.withdrawable_epoch + == val.withdrawable_epoch() { - process_slashings_indices.push((val_index, val.effective_balance)); + process_slashings_indices.push((val_index, val.effective_balance())); } // Note: a validator might still be "eligible" whilst returning `false` to @@ -303,10 +303,10 @@ impl ParticipationCache { } let mut validator_info = ValidatorInfo { - effective_balance: val.effective_balance, + effective_balance: val.effective_balance(), base_reward: 0, // not read is_eligible, - is_slashed: val.slashed, + is_slashed: val.slashed(), is_active_current_epoch, is_active_previous_epoch, previous_epoch_participation: *prev_epoch_flags, @@ -332,7 +332,7 @@ impl ParticipationCache { #[allow(clippy::indexing_slicing)] if is_eligible || is_active_current_epoch { - let effective_balance = val.effective_balance; + let effective_balance = val.effective_balance(); let base_reward = get_base_reward(effective_balance, base_reward_per_increment, spec)?; validator_info.base_reward = base_reward; diff --git a/consensus/state_processing/src/per_epoch_processing/base/validator_statuses.rs b/consensus/state_processing/src/per_epoch_processing/base/validator_statuses.rs index 26d2536e5f..8a29bbb072 100644 --- a/consensus/state_processing/src/per_epoch_processing/base/validator_statuses.rs +++ b/consensus/state_processing/src/per_epoch_processing/base/validator_statuses.rs @@ -198,7 +198,7 @@ impl ValidatorStatuses { for (i, validator) in state.validators().iter().enumerate() { let effective_balance = state.get_effective_balance(i)?; let mut status = ValidatorStatus { - is_slashed: validator.slashed, + is_slashed: validator.slashed(), is_withdrawable_in_current_epoch: validator .is_withdrawable_at(state.current_epoch()), current_epoch_effective_balance: effective_balance, diff --git a/consensus/state_processing/src/per_epoch_processing/effective_balance_updates.rs b/consensus/state_processing/src/per_epoch_processing/effective_balance_updates.rs index ba6f86c248..82f62915e3 100644 --- a/consensus/state_processing/src/per_epoch_processing/effective_balance_updates.rs +++ b/consensus/state_processing/src/per_epoch_processing/effective_balance_updates.rs @@ -28,23 +28,23 @@ pub fn process_effective_balance_updates( .ok_or(BeaconStateError::BalancesOutOfBounds(index))?; let new_effective_balance = if balance.safe_add(downward_threshold)? - < validator.effective_balance - || validator.effective_balance.safe_add(upward_threshold)? < balance + < validator.effective_balance() + || validator.effective_balance().safe_add(upward_threshold)? < balance { std::cmp::min( balance.safe_sub(balance.safe_rem(spec.effective_balance_increment)?)?, spec.max_effective_balance, ) } else { - validator.effective_balance + validator.effective_balance() }; if validator.is_active_at(next_epoch) { new_total_active_balance.safe_add_assign(new_effective_balance)?; } - if new_effective_balance != validator.effective_balance { - validator.to_mut().effective_balance = new_effective_balance; + if new_effective_balance != validator.effective_balance() { + validator.to_mut().mutable.effective_balance = new_effective_balance; } } diff --git a/consensus/state_processing/src/per_epoch_processing/registry_updates.rs b/consensus/state_processing/src/per_epoch_processing/registry_updates.rs index 4fd2d68586..7f3bfd9dce 100644 --- a/consensus/state_processing/src/per_epoch_processing/registry_updates.rs +++ b/consensus/state_processing/src/per_epoch_processing/registry_updates.rs @@ -17,7 +17,7 @@ pub fn process_registry_updates( let current_epoch = state.current_epoch(); let is_ejectable = |validator: &Validator| { validator.is_active_at(current_epoch) - && validator.effective_balance <= spec.ejection_balance + && validator.effective_balance() <= spec.ejection_balance }; let indices_to_update: Vec<_> = state .validators() @@ -32,7 +32,7 @@ pub fn process_registry_updates( for index in indices_to_update { let validator = state.get_validator_mut(index)?; if validator.is_eligible_for_activation_queue(spec) { - validator.activation_eligibility_epoch = current_epoch.safe_add(1)?; + validator.mutable.activation_eligibility_epoch = current_epoch.safe_add(1)?; } if is_ejectable(validator) { initiate_validator_exit(state, index, spec)?; @@ -45,7 +45,7 @@ pub fn process_registry_updates( .iter() .enumerate() .filter(|(_, validator)| validator.is_eligible_for_activation(state, spec)) - .sorted_by_key(|(index, validator)| (validator.activation_eligibility_epoch, *index)) + .sorted_by_key(|(index, validator)| (validator.activation_eligibility_epoch(), *index)) .map(|(index, _)| index) .collect_vec(); @@ -53,7 +53,7 @@ pub fn process_registry_updates( let churn_limit = state.get_churn_limit(spec)? as usize; let delayed_activation_epoch = state.compute_activation_exit_epoch(current_epoch, spec)?; for index in activation_queue.into_iter().take(churn_limit) { - state.get_validator_mut(index)?.activation_epoch = delayed_activation_epoch; + state.get_validator_mut(index)?.mutable.activation_epoch = delayed_activation_epoch; } Ok(()) diff --git a/consensus/state_processing/src/per_epoch_processing/slashings.rs b/consensus/state_processing/src/per_epoch_processing/slashings.rs index 8d7838700a..1a14f8f993 100644 --- a/consensus/state_processing/src/per_epoch_processing/slashings.rs +++ b/consensus/state_processing/src/per_epoch_processing/slashings.rs @@ -26,9 +26,9 @@ pub fn process_slashings( .iter() .enumerate() .filter(|(_, validator)| { - validator.slashed && target_withdrawable_epoch == validator.withdrawable_epoch + validator.slashed() && target_withdrawable_epoch == validator.withdrawable_epoch() }) - .map(|(index, validator)| (index, validator.effective_balance)) + .map(|(index, validator)| (index, validator.effective_balance())) .collect() }); diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index 4b5ffbca61..7a31d74827 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -833,7 +833,7 @@ impl BeaconState { .get(shuffled_index) .ok_or(Error::ShuffleIndexOutOfBounds(shuffled_index))?; let random_byte = Self::shuffling_random_byte(i, seed.as_bytes())?; - let effective_balance = self.get_validator(candidate_index)?.effective_balance; + let effective_balance = self.get_validator(candidate_index)?.effective_balance(); if effective_balance.safe_mul(MAX_RANDOM_BYTE)? >= spec .max_effective_balance @@ -1196,7 +1196,7 @@ impl BeaconState { /// Return the effective balance for a validator with the given `validator_index`. pub fn get_effective_balance(&self, validator_index: usize) -> Result { self.get_validator(validator_index) - .map(|v| v.effective_balance) + .map(|v| v.effective_balance()) } /// Get the inactivity score for a single validator. @@ -1291,7 +1291,7 @@ impl BeaconState { for validator in self.validators() { if validator.is_active_at(epoch) { - total_active_balance.safe_add_assign(validator.effective_balance)?; + total_active_balance.safe_add_assign(validator.effective_balance())?; } } Ok(std::cmp::max( @@ -1636,7 +1636,7 @@ impl BeaconState { /// a tangible speed improvement in state processing. pub fn is_eligible_validator(&self, previous_epoch: Epoch, val: &Validator) -> bool { val.is_active_at(previous_epoch) - || (val.slashed && previous_epoch + Epoch::new(1) < val.withdrawable_epoch) + || (val.slashed() && previous_epoch + Epoch::new(1) < val.withdrawable_epoch()) } /// Passing `previous_epoch` to this function rather than computing it internally provides diff --git a/consensus/types/src/beacon_state/exit_cache.rs b/consensus/types/src/beacon_state/exit_cache.rs index 2b243b661d..e80c77b431 100644 --- a/consensus/types/src/beacon_state/exit_cache.rs +++ b/consensus/types/src/beacon_state/exit_cache.rs @@ -23,8 +23,8 @@ impl ExitCache { // Add all validators with a non-default exit epoch to the cache. validators .into_iter() - .filter(|validator| validator.exit_epoch != spec.far_future_epoch) - .try_for_each(|validator| exit_cache.record_validator_exit(validator.exit_epoch))?; + .filter(|validator| validator.exit_epoch() != spec.far_future_epoch) + .try_for_each(|validator| exit_cache.record_validator_exit(validator.exit_epoch()))?; Ok(exit_cache) } diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index f10c8b4fd6..52983d4f8c 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -160,7 +160,7 @@ pub use crate::sync_committee_subscription::SyncCommitteeSubscription; pub use crate::sync_duty::SyncDuty; pub use crate::sync_selection_proof::SyncSelectionProof; pub use crate::sync_subnet_id::SyncSubnetId; -pub use crate::validator::{Validator, ValidatorImmutable}; +pub use crate::validator::{Validator, ValidatorImmutable, ValidatorMutable}; pub use crate::validator_registration_data::*; pub use crate::validator_subscription::ValidatorSubscription; pub use crate::voluntary_exit::VoluntaryExit; diff --git a/consensus/types/src/validator.rs b/consensus/types/src/validator.rs index 2676fdc416..668c65ede1 100644 --- a/consensus/types/src/validator.rs +++ b/consensus/types/src/validator.rs @@ -12,8 +12,16 @@ const NUM_FIELDS: usize = 8; /// Information about a `BeaconChain` validator. #[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)] +// FIXME(sproul): fix serialize/deserialize impl pub struct Validator { pub immutable: Arc, + pub mutable: ValidatorMutable, +} + +/// The mutable fields of a validator. +#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)] +pub struct ValidatorMutable { #[serde(with = "eth2_serde_utils::quoted_u64")] pub effective_balance: u64, pub slashed: bool, @@ -48,32 +56,56 @@ impl Validator { self.immutable.withdrawal_credentials } + pub fn effective_balance(&self) -> u64 { + self.mutable.effective_balance + } + + pub fn slashed(&self) -> bool { + self.mutable.slashed + } + + pub fn activation_eligibility_epoch(&self) -> Epoch { + self.mutable.activation_eligibility_epoch + } + + pub fn activation_epoch(&self) -> Epoch { + self.mutable.activation_epoch + } + + pub fn exit_epoch(&self) -> Epoch { + self.mutable.exit_epoch + } + + pub fn withdrawable_epoch(&self) -> Epoch { + self.mutable.withdrawable_epoch + } + /// Returns `true` if the validator is considered active at some epoch. pub fn is_active_at(&self, epoch: Epoch) -> bool { - self.activation_epoch <= epoch && epoch < self.exit_epoch + self.activation_epoch() <= epoch && epoch < self.exit_epoch() } /// Returns `true` if the validator is slashable at some epoch. pub fn is_slashable_at(&self, epoch: Epoch) -> bool { - !self.slashed && self.activation_epoch <= epoch && epoch < self.withdrawable_epoch + !self.slashed() && self.activation_epoch() <= epoch && epoch < self.withdrawable_epoch() } /// Returns `true` if the validator is considered exited at some epoch. pub fn is_exited_at(&self, epoch: Epoch) -> bool { - self.exit_epoch <= epoch + self.exit_epoch() <= epoch } /// Returns `true` if the validator is able to withdraw at some epoch. pub fn is_withdrawable_at(&self, epoch: Epoch) -> bool { - epoch >= self.withdrawable_epoch + epoch >= self.withdrawable_epoch() } /// Returns `true` if the validator is eligible to join the activation queue. /// /// Spec v0.12.1 pub fn is_eligible_for_activation_queue(&self, spec: &ChainSpec) -> bool { - self.activation_eligibility_epoch == spec.far_future_epoch - && self.effective_balance == spec.max_effective_balance + self.activation_eligibility_epoch() == spec.far_future_epoch + && self.effective_balance() == spec.max_effective_balance } /// Returns `true` if the validator is eligible to be activated. @@ -85,9 +117,9 @@ impl Validator { spec: &ChainSpec, ) -> bool { // Placement in queue is finalized - self.activation_eligibility_epoch <= state.finalized_checkpoint().epoch + self.activation_eligibility_epoch() <= state.finalized_checkpoint().epoch // Has not yet been activated - && self.activation_epoch == spec.far_future_epoch + && self.activation_epoch() == spec.far_future_epoch } fn tree_hash_root_internal(&self) -> Result { @@ -95,16 +127,16 @@ impl Validator { hasher.write(self.pubkey().tree_hash_root().as_bytes())?; hasher.write(self.withdrawal_credentials().tree_hash_root().as_bytes())?; - hasher.write(self.effective_balance.tree_hash_root().as_bytes())?; - hasher.write(self.slashed.tree_hash_root().as_bytes())?; + hasher.write(self.effective_balance().tree_hash_root().as_bytes())?; + hasher.write(self.slashed().tree_hash_root().as_bytes())?; hasher.write( - self.activation_eligibility_epoch + self.activation_eligibility_epoch() .tree_hash_root() .as_bytes(), )?; - hasher.write(self.activation_epoch.tree_hash_root().as_bytes())?; - hasher.write(self.exit_epoch.tree_hash_root().as_bytes())?; - hasher.write(self.withdrawable_epoch.tree_hash_root().as_bytes())?; + hasher.write(self.activation_epoch().tree_hash_root().as_bytes())?; + hasher.write(self.exit_epoch().tree_hash_root().as_bytes())?; + hasher.write(self.withdrawable_epoch().tree_hash_root().as_bytes())?; hasher.finish() } @@ -118,12 +150,14 @@ impl Default for Validator { pubkey: PublicKeyBytes::empty(), withdrawal_credentials: Hash256::default(), }), - activation_eligibility_epoch: Epoch::from(std::u64::MAX), - activation_epoch: Epoch::from(std::u64::MAX), - exit_epoch: Epoch::from(std::u64::MAX), - withdrawable_epoch: Epoch::from(std::u64::MAX), - slashed: false, - effective_balance: std::u64::MAX, + mutable: ValidatorMutable { + activation_eligibility_epoch: Epoch::from(std::u64::MAX), + activation_epoch: Epoch::from(std::u64::MAX), + exit_epoch: Epoch::from(std::u64::MAX), + withdrawable_epoch: Epoch::from(std::u64::MAX), + slashed: false, + effective_balance: std::u64::MAX, + }, } } } @@ -160,7 +194,7 @@ mod tests { assert!(!v.is_active_at(epoch)); assert!(!v.is_exited_at(epoch)); assert!(!v.is_withdrawable_at(epoch)); - assert!(!v.slashed); + assert!(!v.slashed()); } #[test]