mirror of
https://github.com/sigp/lighthouse.git
synced 2026-07-05 22:04:29 +00:00
Split validator into ValidatorMutable
This commit is contained in:
@@ -212,8 +212,8 @@ async fn publish_voluntary_exit<E: EthSpec>(
|
|||||||
let validator_data = get_validator_data(client, &keypair.pk).await?;
|
let validator_data = get_validator_data(client, &keypair.pk).await?;
|
||||||
match validator_data.status {
|
match validator_data.status {
|
||||||
ValidatorStatus::ActiveExiting => {
|
ValidatorStatus::ActiveExiting => {
|
||||||
let exit_epoch = validator_data.validator.exit_epoch;
|
let exit_epoch = validator_data.validator.exit_epoch();
|
||||||
let withdrawal_epoch = validator_data.validator.withdrawable_epoch;
|
let withdrawal_epoch = validator_data.validator.withdrawable_epoch();
|
||||||
let current_epoch = get_current_epoch::<E>(genesis_data.genesis_time, spec)
|
let current_epoch = get_current_epoch::<E>(genesis_data.genesis_time, spec)
|
||||||
.ok_or("Failed to get current epoch. Please check your system time")?;
|
.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. \
|
eprintln!("Voluntary exit has been accepted into the beacon chain, but not yet finalized. \
|
||||||
@@ -233,7 +233,7 @@ async fn publish_voluntary_exit<E: EthSpec>(
|
|||||||
ValidatorStatus::ExitedSlashed | ValidatorStatus::ExitedUnslashed => {
|
ValidatorStatus::ExitedSlashed | ValidatorStatus::ExitedUnslashed => {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Validator has exited on epoch: {}",
|
"Validator has exited on epoch: {}",
|
||||||
validator_data.validator.exit_epoch
|
validator_data.validator.exit_epoch()
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -259,7 +259,7 @@ async fn get_validator_index_for_exit(
|
|||||||
ValidatorStatus::ActiveOngoing => {
|
ValidatorStatus::ActiveOngoing => {
|
||||||
let eligible_epoch = validator_data
|
let eligible_epoch = validator_data
|
||||||
.validator
|
.validator
|
||||||
.activation_epoch
|
.activation_epoch()
|
||||||
.safe_add(spec.shard_committee_period)
|
.safe_add(spec.shard_committee_period)
|
||||||
.map_err(|e| format!("Failed to calculate eligible epoch, validator activation epoch too high: {:?}", e))?;
|
.map_err(|e| format!("Failed to calculate eligible epoch, validator activation epoch too high: {:?}", e))?;
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ pub fn get_effective_balances<T: EthSpec>(state: &BeaconState<T>) -> Vec<u64> {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|validator| {
|
.map(|validator| {
|
||||||
if validator.is_active_at(state.current_epoch()) {
|
if validator.is_active_at(state.current_epoch()) {
|
||||||
validator.effective_balance
|
validator.effective_balance()
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1084,7 +1084,7 @@ fn scrape_head_state<T: EthSpec>(state: &BeaconState<T>, state_root: Hash256) {
|
|||||||
num_active += 1;
|
num_active += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.slashed {
|
if v.slashed() {
|
||||||
num_slashed += 1;
|
num_slashed += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -327,12 +327,12 @@ impl<T: EthSpec> ValidatorMonitor<T> {
|
|||||||
metrics::set_int_gauge(
|
metrics::set_int_gauge(
|
||||||
&metrics::VALIDATOR_MONITOR_EFFECTIVE_BALANCE_GWEI,
|
&metrics::VALIDATOR_MONITOR_EFFECTIVE_BALANCE_GWEI,
|
||||||
&[id],
|
&[id],
|
||||||
u64_to_i64(validator.effective_balance),
|
u64_to_i64(validator.effective_balance()),
|
||||||
);
|
);
|
||||||
metrics::set_int_gauge(
|
metrics::set_int_gauge(
|
||||||
&metrics::VALIDATOR_MONITOR_SLASHED,
|
&metrics::VALIDATOR_MONITOR_SLASHED,
|
||||||
&[id],
|
&[id],
|
||||||
if validator.slashed { 1 } else { 0 },
|
if validator.slashed() { 1 } else { 0 },
|
||||||
);
|
);
|
||||||
metrics::set_int_gauge(
|
metrics::set_int_gauge(
|
||||||
&metrics::VALIDATOR_MONITOR_ACTIVE,
|
&metrics::VALIDATOR_MONITOR_ACTIVE,
|
||||||
@@ -364,22 +364,22 @@ impl<T: EthSpec> ValidatorMonitor<T> {
|
|||||||
metrics::set_int_gauge(
|
metrics::set_int_gauge(
|
||||||
&metrics::VALIDATOR_ACTIVATION_ELIGIBILITY_EPOCH,
|
&metrics::VALIDATOR_ACTIVATION_ELIGIBILITY_EPOCH,
|
||||||
&[id],
|
&[id],
|
||||||
u64_to_i64(validator.activation_eligibility_epoch),
|
u64_to_i64(validator.activation_eligibility_epoch()),
|
||||||
);
|
);
|
||||||
metrics::set_int_gauge(
|
metrics::set_int_gauge(
|
||||||
&metrics::VALIDATOR_ACTIVATION_EPOCH,
|
&metrics::VALIDATOR_ACTIVATION_EPOCH,
|
||||||
&[id],
|
&[id],
|
||||||
u64_to_i64(validator.activation_epoch),
|
u64_to_i64(validator.activation_epoch()),
|
||||||
);
|
);
|
||||||
metrics::set_int_gauge(
|
metrics::set_int_gauge(
|
||||||
&metrics::VALIDATOR_EXIT_EPOCH,
|
&metrics::VALIDATOR_EXIT_EPOCH,
|
||||||
&[id],
|
&[id],
|
||||||
u64_to_i64(validator.exit_epoch),
|
u64_to_i64(validator.exit_epoch()),
|
||||||
);
|
);
|
||||||
metrics::set_int_gauge(
|
metrics::set_int_gauge(
|
||||||
&metrics::VALIDATOR_WITHDRAWABLE_EPOCH,
|
&metrics::VALIDATOR_WITHDRAWABLE_EPOCH,
|
||||||
&[id],
|
&[id],
|
||||||
u64_to_i64(validator.withdrawable_epoch),
|
u64_to_i64(validator.withdrawable_epoch()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,13 +99,13 @@ pub fn validator_inclusion_data<T: BeaconChainTypes>(
|
|||||||
let summary = get_epoch_processing_summary(&mut state, &chain.spec)?;
|
let summary = get_epoch_processing_summary(&mut state, &chain.spec)?;
|
||||||
|
|
||||||
Ok(Some(ValidatorInclusionData {
|
Ok(Some(ValidatorInclusionData {
|
||||||
is_slashed: validator.slashed,
|
is_slashed: validator.slashed(),
|
||||||
is_withdrawable_in_current_epoch: validator.is_withdrawable_at(epoch),
|
is_withdrawable_in_current_epoch: validator.is_withdrawable_at(epoch),
|
||||||
is_active_unslashed_in_current_epoch: summary
|
is_active_unslashed_in_current_epoch: summary
|
||||||
.is_active_unslashed_in_current_epoch(validator_index),
|
.is_active_unslashed_in_current_epoch(validator_index),
|
||||||
is_active_unslashed_in_previous_epoch: summary
|
is_active_unslashed_in_previous_epoch: summary
|
||||||
.is_active_unslashed_in_previous_epoch(validator_index),
|
.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: summary
|
||||||
.is_current_epoch_target_attester(validator_index)
|
.is_current_epoch_target_attester(validator_index)
|
||||||
.map_err(convert_cache_error)?,
|
.map_err(convert_cache_error)?,
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ impl<T: EthSpec> OperationPool<T> {
|
|||||||
&& state
|
&& state
|
||||||
.validators()
|
.validators()
|
||||||
.get(slashing.as_inner().signed_header_1.message.proposer_index as usize)
|
.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(),
|
|slashing| slashing.as_inner().clone(),
|
||||||
T::MaxProposerSlashings::to_usize(),
|
T::MaxProposerSlashings::to_usize(),
|
||||||
@@ -429,7 +429,7 @@ impl<T: EthSpec> OperationPool<T> {
|
|||||||
pub fn prune_proposer_slashings(&self, head_state: &BeaconState<T>) {
|
pub fn prune_proposer_slashings(&self, head_state: &BeaconState<T>) {
|
||||||
prune_validator_hash_map(
|
prune_validator_hash_map(
|
||||||
&mut self.proposer_slashings.write(),
|
&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,
|
head_state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -448,7 +448,7 @@ impl<T: EthSpec> OperationPool<T> {
|
|||||||
//
|
//
|
||||||
// We cannot check the `slashed` field since the `head` is not finalized and
|
// We cannot check the `slashed` field since the `head` is not finalized and
|
||||||
// a fork could un-slash someone.
|
// 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());
|
.map_or(false, |indices| !indices.is_empty());
|
||||||
|
|
||||||
@@ -504,7 +504,7 @@ impl<T: EthSpec> OperationPool<T> {
|
|||||||
//
|
//
|
||||||
// We choose simplicity over the gain of pruning more exits since they are small and
|
// We choose simplicity over the gain of pruning more exits since they are small and
|
||||||
// should not be seen frequently.
|
// 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,
|
head_state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -347,20 +347,20 @@ pub enum ValidatorStatus {
|
|||||||
impl ValidatorStatus {
|
impl ValidatorStatus {
|
||||||
pub fn from_validator(validator: &Validator, epoch: Epoch, far_future_epoch: Epoch) -> Self {
|
pub fn from_validator(validator: &Validator, epoch: Epoch, far_future_epoch: Epoch) -> Self {
|
||||||
if validator.is_withdrawable_at(epoch) {
|
if validator.is_withdrawable_at(epoch) {
|
||||||
if validator.effective_balance == 0 {
|
if validator.effective_balance() == 0 {
|
||||||
ValidatorStatus::WithdrawalDone
|
ValidatorStatus::WithdrawalDone
|
||||||
} else {
|
} else {
|
||||||
ValidatorStatus::WithdrawalPossible
|
ValidatorStatus::WithdrawalPossible
|
||||||
}
|
}
|
||||||
} else if validator.is_exited_at(epoch) && epoch < validator.withdrawable_epoch {
|
} else if validator.is_exited_at(epoch) && epoch < validator.withdrawable_epoch() {
|
||||||
if validator.slashed {
|
if validator.slashed() {
|
||||||
ValidatorStatus::ExitedSlashed
|
ValidatorStatus::ExitedSlashed
|
||||||
} else {
|
} else {
|
||||||
ValidatorStatus::ExitedUnslashed
|
ValidatorStatus::ExitedUnslashed
|
||||||
}
|
}
|
||||||
} else if validator.is_active_at(epoch) {
|
} else if validator.is_active_at(epoch) {
|
||||||
if validator.exit_epoch < far_future_epoch {
|
if validator.exit_epoch() < far_future_epoch {
|
||||||
if validator.slashed {
|
if validator.slashed() {
|
||||||
ValidatorStatus::ActiveSlashed
|
ValidatorStatus::ActiveSlashed
|
||||||
} else {
|
} else {
|
||||||
ValidatorStatus::ActiveExiting
|
ValidatorStatus::ActiveExiting
|
||||||
@@ -371,7 +371,7 @@ impl ValidatorStatus {
|
|||||||
// `pending` statuses are specified as validators where `validator.activation_epoch > current_epoch`.
|
// `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)`,
|
// 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.
|
// `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
|
ValidatorStatus::PendingInitialized
|
||||||
} else {
|
} else {
|
||||||
ValidatorStatus::PendingQueued
|
ValidatorStatus::PendingQueued
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub fn initiate_validator_exit<T: EthSpec>(
|
|||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Return if the validator already initiated exit
|
// 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(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,8 +34,8 @@ pub fn initiate_validator_exit<T: EthSpec>(
|
|||||||
|
|
||||||
// FIXME(sproul): could avoid this second lookup with some clever borrowing
|
// FIXME(sproul): could avoid this second lookup with some clever borrowing
|
||||||
let mut validator = state.get_validator_mut(index)?;
|
let mut validator = state.get_validator_mut(index)?;
|
||||||
validator.exit_epoch = exit_queue_epoch;
|
validator.mutable.exit_epoch = exit_queue_epoch;
|
||||||
validator.withdrawable_epoch =
|
validator.mutable.withdrawable_epoch =
|
||||||
exit_queue_epoch.safe_add(spec.min_validator_withdrawability_delay)?;
|
exit_queue_epoch.safe_add(spec.min_validator_withdrawability_delay)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ pub fn slash_validator<T: EthSpec>(
|
|||||||
initiate_validator_exit(state, slashed_index, spec)?;
|
initiate_validator_exit(state, slashed_index, spec)?;
|
||||||
|
|
||||||
let validator = state.get_validator_mut(slashed_index)?;
|
let validator = state.get_validator_mut(slashed_index)?;
|
||||||
validator.slashed = true;
|
validator.mutable.slashed = true;
|
||||||
validator.withdrawable_epoch = cmp::max(
|
validator.mutable.withdrawable_epoch = cmp::max(
|
||||||
validator.withdrawable_epoch,
|
validator.withdrawable_epoch(),
|
||||||
epoch.safe_add(T::EpochsPerSlashingsVector::to_u64())?,
|
epoch.safe_add(T::EpochsPerSlashingsVector::to_u64())?,
|
||||||
);
|
);
|
||||||
let validator_effective_balance = validator.effective_balance;
|
let validator_effective_balance = validator.effective_balance();
|
||||||
state.set_slashings(
|
state.set_slashings(
|
||||||
epoch,
|
epoch,
|
||||||
state
|
state
|
||||||
|
|||||||
@@ -104,13 +104,13 @@ pub fn process_activations<T: EthSpec>(
|
|||||||
.get(index)
|
.get(index)
|
||||||
.copied()
|
.copied()
|
||||||
.ok_or(Error::BalancesOutOfBounds(index))?;
|
.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)?)?,
|
balance.safe_sub(balance.safe_rem(spec.effective_balance_increment)?)?,
|
||||||
spec.max_effective_balance,
|
spec.max_effective_balance,
|
||||||
);
|
);
|
||||||
if validator.effective_balance == spec.max_effective_balance {
|
if validator.effective_balance() == spec.max_effective_balance {
|
||||||
validator.activation_eligibility_epoch = T::genesis_epoch();
|
validator.mutable.activation_eligibility_epoch = T::genesis_epoch();
|
||||||
validator.activation_epoch = T::genesis_epoch();
|
validator.mutable.activation_epoch = T::genesis_epoch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ pub fn process_block_header<T: EthSpec>(
|
|||||||
|
|
||||||
// Verify proposer is not slashed
|
// Verify proposer is not slashed
|
||||||
verify!(
|
verify!(
|
||||||
!state.get_validator(proposer_index as usize)?.slashed,
|
!state.get_validator(proposer_index as usize)?.slashed(),
|
||||||
HeaderInvalid::ProposerSlashed(proposer_index)
|
HeaderInvalid::ProposerSlashed(proposer_index)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ pub mod altair {
|
|||||||
{
|
{
|
||||||
// FIXME(sproul): add effective balance cache here?
|
// FIXME(sproul): add effective balance cache here?
|
||||||
validator_participation.add_flag(flag_index)?;
|
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(
|
proposer_reward_numerator.safe_add_assign(
|
||||||
get_base_reward(effective_balance, base_reward_per_increment, spec)?
|
get_base_reward(effective_balance, base_reward_per_increment, spec)?
|
||||||
.safe_mul(weight)?,
|
.safe_mul(weight)?,
|
||||||
@@ -347,6 +347,7 @@ pub fn process_deposit<T: EthSpec>(
|
|||||||
pubkey: deposit.data.pubkey,
|
pubkey: deposit.data.pubkey,
|
||||||
withdrawal_credentials: deposit.data.withdrawal_credentials,
|
withdrawal_credentials: deposit.data.withdrawal_credentials,
|
||||||
}),
|
}),
|
||||||
|
mutable: ValidatorMutable {
|
||||||
activation_eligibility_epoch: spec.far_future_epoch,
|
activation_eligibility_epoch: spec.far_future_epoch,
|
||||||
activation_epoch: spec.far_future_epoch,
|
activation_epoch: spec.far_future_epoch,
|
||||||
exit_epoch: spec.far_future_epoch,
|
exit_epoch: spec.far_future_epoch,
|
||||||
@@ -356,6 +357,7 @@ pub fn process_deposit<T: EthSpec>(
|
|||||||
spec.max_effective_balance,
|
spec.max_effective_balance,
|
||||||
),
|
),
|
||||||
slashed: false,
|
slashed: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
state.validators_mut().push(validator)?;
|
state.validators_mut().push(validator)?;
|
||||||
state.balances_mut().push(deposit.data.amount)?;
|
state.balances_mut().push(deposit.data.amount)?;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ pub fn verify_exit<T: EthSpec>(
|
|||||||
|
|
||||||
// Verify that the validator has not yet exited.
|
// Verify that the validator has not yet exited.
|
||||||
verify!(
|
verify!(
|
||||||
validator.exit_epoch == spec.far_future_epoch,
|
validator.exit_epoch() == spec.far_future_epoch,
|
||||||
ExitInvalid::AlreadyExited(exit.validator_index)
|
ExitInvalid::AlreadyExited(exit.validator_index)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ pub fn verify_exit<T: EthSpec>(
|
|||||||
|
|
||||||
// Verify the validator has been active long enough.
|
// Verify the validator has been active long enough.
|
||||||
let earliest_exit_epoch = validator
|
let earliest_exit_epoch = validator
|
||||||
.activation_epoch
|
.activation_epoch()
|
||||||
.safe_add(spec.shard_committee_period)?;
|
.safe_add(spec.shard_committee_period)?;
|
||||||
verify!(
|
verify!(
|
||||||
state.current_epoch() >= earliest_exit_epoch,
|
state.current_epoch() >= earliest_exit_epoch,
|
||||||
|
|||||||
@@ -129,10 +129,10 @@ impl SingleEpochParticipationCache {
|
|||||||
|
|
||||||
// All active validators increase the total active balance.
|
// All active validators increase the total active balance.
|
||||||
self.total_active_balance
|
self.total_active_balance
|
||||||
.safe_add_assign(validator.effective_balance)?;
|
.safe_add_assign(validator.effective_balance())?;
|
||||||
|
|
||||||
// Only unslashed validators may proceed.
|
// Only unslashed validators may proceed.
|
||||||
if validator.slashed {
|
if validator.slashed() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ impl SingleEpochParticipationCache {
|
|||||||
// are set for `val_index`.
|
// are set for `val_index`.
|
||||||
for (flag, balance) in self.total_flag_balances.iter_mut().enumerate() {
|
for (flag, balance) in self.total_flag_balances.iter_mut().enumerate() {
|
||||||
if epoch_participation.has_flag(flag)? {
|
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)?)?
|
&& 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
|
// Note: a validator might still be "eligible" whilst returning `false` to
|
||||||
@@ -303,10 +303,10 @@ impl ParticipationCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut validator_info = ValidatorInfo {
|
let mut validator_info = ValidatorInfo {
|
||||||
effective_balance: val.effective_balance,
|
effective_balance: val.effective_balance(),
|
||||||
base_reward: 0, // not read
|
base_reward: 0, // not read
|
||||||
is_eligible,
|
is_eligible,
|
||||||
is_slashed: val.slashed,
|
is_slashed: val.slashed(),
|
||||||
is_active_current_epoch,
|
is_active_current_epoch,
|
||||||
is_active_previous_epoch,
|
is_active_previous_epoch,
|
||||||
previous_epoch_participation: *prev_epoch_flags,
|
previous_epoch_participation: *prev_epoch_flags,
|
||||||
@@ -332,7 +332,7 @@ impl ParticipationCache {
|
|||||||
|
|
||||||
#[allow(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
if is_eligible || is_active_current_epoch {
|
if is_eligible || is_active_current_epoch {
|
||||||
let effective_balance = val.effective_balance;
|
let effective_balance = val.effective_balance();
|
||||||
let base_reward =
|
let base_reward =
|
||||||
get_base_reward(effective_balance, base_reward_per_increment, spec)?;
|
get_base_reward(effective_balance, base_reward_per_increment, spec)?;
|
||||||
validator_info.base_reward = base_reward;
|
validator_info.base_reward = base_reward;
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ impl ValidatorStatuses {
|
|||||||
for (i, validator) in state.validators().iter().enumerate() {
|
for (i, validator) in state.validators().iter().enumerate() {
|
||||||
let effective_balance = state.get_effective_balance(i)?;
|
let effective_balance = state.get_effective_balance(i)?;
|
||||||
let mut status = ValidatorStatus {
|
let mut status = ValidatorStatus {
|
||||||
is_slashed: validator.slashed,
|
is_slashed: validator.slashed(),
|
||||||
is_withdrawable_in_current_epoch: validator
|
is_withdrawable_in_current_epoch: validator
|
||||||
.is_withdrawable_at(state.current_epoch()),
|
.is_withdrawable_at(state.current_epoch()),
|
||||||
current_epoch_effective_balance: effective_balance,
|
current_epoch_effective_balance: effective_balance,
|
||||||
|
|||||||
@@ -28,23 +28,23 @@ pub fn process_effective_balance_updates<T: EthSpec>(
|
|||||||
.ok_or(BeaconStateError::BalancesOutOfBounds(index))?;
|
.ok_or(BeaconStateError::BalancesOutOfBounds(index))?;
|
||||||
|
|
||||||
let new_effective_balance = if balance.safe_add(downward_threshold)?
|
let new_effective_balance = if balance.safe_add(downward_threshold)?
|
||||||
< validator.effective_balance
|
< validator.effective_balance()
|
||||||
|| validator.effective_balance.safe_add(upward_threshold)? < balance
|
|| validator.effective_balance().safe_add(upward_threshold)? < balance
|
||||||
{
|
{
|
||||||
std::cmp::min(
|
std::cmp::min(
|
||||||
balance.safe_sub(balance.safe_rem(spec.effective_balance_increment)?)?,
|
balance.safe_sub(balance.safe_rem(spec.effective_balance_increment)?)?,
|
||||||
spec.max_effective_balance,
|
spec.max_effective_balance,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
validator.effective_balance
|
validator.effective_balance()
|
||||||
};
|
};
|
||||||
|
|
||||||
if validator.is_active_at(next_epoch) {
|
if validator.is_active_at(next_epoch) {
|
||||||
new_total_active_balance.safe_add_assign(new_effective_balance)?;
|
new_total_active_balance.safe_add_assign(new_effective_balance)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_effective_balance != validator.effective_balance {
|
if new_effective_balance != validator.effective_balance() {
|
||||||
validator.to_mut().effective_balance = new_effective_balance;
|
validator.to_mut().mutable.effective_balance = new_effective_balance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub fn process_registry_updates<T: EthSpec>(
|
|||||||
let current_epoch = state.current_epoch();
|
let current_epoch = state.current_epoch();
|
||||||
let is_ejectable = |validator: &Validator| {
|
let is_ejectable = |validator: &Validator| {
|
||||||
validator.is_active_at(current_epoch)
|
validator.is_active_at(current_epoch)
|
||||||
&& validator.effective_balance <= spec.ejection_balance
|
&& validator.effective_balance() <= spec.ejection_balance
|
||||||
};
|
};
|
||||||
let indices_to_update: Vec<_> = state
|
let indices_to_update: Vec<_> = state
|
||||||
.validators()
|
.validators()
|
||||||
@@ -32,7 +32,7 @@ pub fn process_registry_updates<T: EthSpec>(
|
|||||||
for index in indices_to_update {
|
for index in indices_to_update {
|
||||||
let validator = state.get_validator_mut(index)?;
|
let validator = state.get_validator_mut(index)?;
|
||||||
if validator.is_eligible_for_activation_queue(spec) {
|
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) {
|
if is_ejectable(validator) {
|
||||||
initiate_validator_exit(state, index, spec)?;
|
initiate_validator_exit(state, index, spec)?;
|
||||||
@@ -45,7 +45,7 @@ pub fn process_registry_updates<T: EthSpec>(
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, validator)| validator.is_eligible_for_activation(state, spec))
|
.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)
|
.map(|(index, _)| index)
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ pub fn process_registry_updates<T: EthSpec>(
|
|||||||
let churn_limit = state.get_churn_limit(spec)? as usize;
|
let churn_limit = state.get_churn_limit(spec)? as usize;
|
||||||
let delayed_activation_epoch = state.compute_activation_exit_epoch(current_epoch, spec)?;
|
let delayed_activation_epoch = state.compute_activation_exit_epoch(current_epoch, spec)?;
|
||||||
for index in activation_queue.into_iter().take(churn_limit) {
|
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(())
|
Ok(())
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ pub fn process_slashings<T: EthSpec>(
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, validator)| {
|
.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()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -833,7 +833,7 @@ impl<T: EthSpec> BeaconState<T> {
|
|||||||
.get(shuffled_index)
|
.get(shuffled_index)
|
||||||
.ok_or(Error::ShuffleIndexOutOfBounds(shuffled_index))?;
|
.ok_or(Error::ShuffleIndexOutOfBounds(shuffled_index))?;
|
||||||
let random_byte = Self::shuffling_random_byte(i, seed.as_bytes())?;
|
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)?
|
if effective_balance.safe_mul(MAX_RANDOM_BYTE)?
|
||||||
>= spec
|
>= spec
|
||||||
.max_effective_balance
|
.max_effective_balance
|
||||||
@@ -1196,7 +1196,7 @@ impl<T: EthSpec> BeaconState<T> {
|
|||||||
/// Return the effective balance for a validator with the given `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> {
|
pub fn get_effective_balance(&self, validator_index: usize) -> Result<u64, Error> {
|
||||||
self.get_validator(validator_index)
|
self.get_validator(validator_index)
|
||||||
.map(|v| v.effective_balance)
|
.map(|v| v.effective_balance())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the inactivity score for a single validator.
|
/// Get the inactivity score for a single validator.
|
||||||
@@ -1291,7 +1291,7 @@ impl<T: EthSpec> BeaconState<T> {
|
|||||||
|
|
||||||
for validator in self.validators() {
|
for validator in self.validators() {
|
||||||
if validator.is_active_at(epoch) {
|
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(
|
Ok(std::cmp::max(
|
||||||
@@ -1636,7 +1636,7 @@ impl<T: EthSpec> BeaconState<T> {
|
|||||||
/// a tangible speed improvement in state processing.
|
/// a tangible speed improvement in state processing.
|
||||||
pub fn is_eligible_validator(&self, previous_epoch: Epoch, val: &Validator) -> bool {
|
pub fn is_eligible_validator(&self, previous_epoch: Epoch, val: &Validator) -> bool {
|
||||||
val.is_active_at(previous_epoch)
|
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
|
/// Passing `previous_epoch` to this function rather than computing it internally provides
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ impl ExitCache {
|
|||||||
// Add all validators with a non-default exit epoch to the cache.
|
// Add all validators with a non-default exit epoch to the cache.
|
||||||
validators
|
validators
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|validator| validator.exit_epoch != spec.far_future_epoch)
|
.filter(|validator| validator.exit_epoch() != spec.far_future_epoch)
|
||||||
.try_for_each(|validator| exit_cache.record_validator_exit(validator.exit_epoch))?;
|
.try_for_each(|validator| exit_cache.record_validator_exit(validator.exit_epoch()))?;
|
||||||
Ok(exit_cache)
|
Ok(exit_cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ pub use crate::sync_committee_subscription::SyncCommitteeSubscription;
|
|||||||
pub use crate::sync_duty::SyncDuty;
|
pub use crate::sync_duty::SyncDuty;
|
||||||
pub use crate::sync_selection_proof::SyncSelectionProof;
|
pub use crate::sync_selection_proof::SyncSelectionProof;
|
||||||
pub use crate::sync_subnet_id::SyncSubnetId;
|
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_registration_data::*;
|
||||||
pub use crate::validator_subscription::ValidatorSubscription;
|
pub use crate::validator_subscription::ValidatorSubscription;
|
||||||
pub use crate::voluntary_exit::VoluntaryExit;
|
pub use crate::voluntary_exit::VoluntaryExit;
|
||||||
|
|||||||
@@ -12,8 +12,16 @@ const NUM_FIELDS: usize = 8;
|
|||||||
/// Information about a `BeaconChain` validator.
|
/// Information about a `BeaconChain` validator.
|
||||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
|
||||||
|
// FIXME(sproul): fix serialize/deserialize impl
|
||||||
pub struct Validator {
|
pub struct Validator {
|
||||||
pub immutable: Arc<ValidatorImmutable>,
|
pub immutable: Arc<ValidatorImmutable>,
|
||||||
|
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")]
|
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||||
pub effective_balance: u64,
|
pub effective_balance: u64,
|
||||||
pub slashed: bool,
|
pub slashed: bool,
|
||||||
@@ -48,32 +56,56 @@ impl Validator {
|
|||||||
self.immutable.withdrawal_credentials
|
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.
|
/// Returns `true` if the validator is considered active at some epoch.
|
||||||
pub fn is_active_at(&self, epoch: Epoch) -> bool {
|
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.
|
/// Returns `true` if the validator is slashable at some epoch.
|
||||||
pub fn is_slashable_at(&self, epoch: Epoch) -> bool {
|
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.
|
/// Returns `true` if the validator is considered exited at some epoch.
|
||||||
pub fn is_exited_at(&self, epoch: Epoch) -> bool {
|
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.
|
/// Returns `true` if the validator is able to withdraw at some epoch.
|
||||||
pub fn is_withdrawable_at(&self, epoch: Epoch) -> bool {
|
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.
|
/// Returns `true` if the validator is eligible to join the activation queue.
|
||||||
///
|
///
|
||||||
/// Spec v0.12.1
|
/// Spec v0.12.1
|
||||||
pub fn is_eligible_for_activation_queue(&self, spec: &ChainSpec) -> bool {
|
pub fn is_eligible_for_activation_queue(&self, spec: &ChainSpec) -> bool {
|
||||||
self.activation_eligibility_epoch == spec.far_future_epoch
|
self.activation_eligibility_epoch() == spec.far_future_epoch
|
||||||
&& self.effective_balance == spec.max_effective_balance
|
&& self.effective_balance() == spec.max_effective_balance
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the validator is eligible to be activated.
|
/// Returns `true` if the validator is eligible to be activated.
|
||||||
@@ -85,9 +117,9 @@ impl Validator {
|
|||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Placement in queue is finalized
|
// 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
|
// 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<Hash256, tree_hash::Error> {
|
fn tree_hash_root_internal(&self) -> Result<Hash256, tree_hash::Error> {
|
||||||
@@ -95,16 +127,16 @@ impl Validator {
|
|||||||
|
|
||||||
hasher.write(self.pubkey().tree_hash_root().as_bytes())?;
|
hasher.write(self.pubkey().tree_hash_root().as_bytes())?;
|
||||||
hasher.write(self.withdrawal_credentials().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.effective_balance().tree_hash_root().as_bytes())?;
|
||||||
hasher.write(self.slashed.tree_hash_root().as_bytes())?;
|
hasher.write(self.slashed().tree_hash_root().as_bytes())?;
|
||||||
hasher.write(
|
hasher.write(
|
||||||
self.activation_eligibility_epoch
|
self.activation_eligibility_epoch()
|
||||||
.tree_hash_root()
|
.tree_hash_root()
|
||||||
.as_bytes(),
|
.as_bytes(),
|
||||||
)?;
|
)?;
|
||||||
hasher.write(self.activation_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.exit_epoch().tree_hash_root().as_bytes())?;
|
||||||
hasher.write(self.withdrawable_epoch.tree_hash_root().as_bytes())?;
|
hasher.write(self.withdrawable_epoch().tree_hash_root().as_bytes())?;
|
||||||
|
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
@@ -118,12 +150,14 @@ impl Default for Validator {
|
|||||||
pubkey: PublicKeyBytes::empty(),
|
pubkey: PublicKeyBytes::empty(),
|
||||||
withdrawal_credentials: Hash256::default(),
|
withdrawal_credentials: Hash256::default(),
|
||||||
}),
|
}),
|
||||||
|
mutable: ValidatorMutable {
|
||||||
activation_eligibility_epoch: Epoch::from(std::u64::MAX),
|
activation_eligibility_epoch: Epoch::from(std::u64::MAX),
|
||||||
activation_epoch: Epoch::from(std::u64::MAX),
|
activation_epoch: Epoch::from(std::u64::MAX),
|
||||||
exit_epoch: Epoch::from(std::u64::MAX),
|
exit_epoch: Epoch::from(std::u64::MAX),
|
||||||
withdrawable_epoch: Epoch::from(std::u64::MAX),
|
withdrawable_epoch: Epoch::from(std::u64::MAX),
|
||||||
slashed: false,
|
slashed: false,
|
||||||
effective_balance: std::u64::MAX,
|
effective_balance: std::u64::MAX,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +194,7 @@ mod tests {
|
|||||||
assert!(!v.is_active_at(epoch));
|
assert!(!v.is_active_at(epoch));
|
||||||
assert!(!v.is_exited_at(epoch));
|
assert!(!v.is_exited_at(epoch));
|
||||||
assert!(!v.is_withdrawable_at(epoch));
|
assert!(!v.is_withdrawable_at(epoch));
|
||||||
assert!(!v.slashed);
|
assert!(!v.slashed());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user