mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-19 13:58:28 +00:00
beacon state changes
This commit is contained in:
@@ -10,14 +10,27 @@ pub fn upgrade_to_electra<E: EthSpec>(
|
|||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let epoch = pre_state.current_epoch();
|
let epoch = pre_state.current_epoch();
|
||||||
let pre = pre_state.as_deneb_mut()?;
|
|
||||||
|
|
||||||
|
let exit_balance_to_consume = pre_state.get_activation_exit_churn_limit(spec)?;
|
||||||
|
let earliest_exit_epoch = pre_state
|
||||||
|
.validators()
|
||||||
|
.iter()
|
||||||
|
.filter(|v| v.exit_epoch != spec.far_future_epoch)
|
||||||
|
.map(|v| v.exit_epoch)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(epoch)
|
||||||
|
+ 1;
|
||||||
|
|
||||||
|
let consolidation_balance_to_consume = pre_state.get_consolidation_churn_limit(spec)?;
|
||||||
|
let earliest_consolidation_epoch = spec.compute_activation_exit_epoch(epoch)?;
|
||||||
|
|
||||||
|
let pre = pre_state.as_deneb_mut()?;
|
||||||
// Where possible, use something like `mem::take` to move fields from behind the &mut
|
// Where possible, use something like `mem::take` to move fields from behind the &mut
|
||||||
// reference. For other fields that don't have a good default value, use `clone`.
|
// reference. For other fields that don't have a good default value, use `clone`.
|
||||||
//
|
//
|
||||||
// Fixed size vectors get cloned because replacing them would require the same size
|
// Fixed size vectors get cloned because replacing them would require the same size
|
||||||
// allocation as cloning.
|
// allocation as cloning.
|
||||||
let post = BeaconState::Electra(BeaconStateElectra {
|
let mut post = BeaconState::Electra(BeaconStateElectra {
|
||||||
// Versioning
|
// Versioning
|
||||||
genesis_time: pre.genesis_time,
|
genesis_time: pre.genesis_time,
|
||||||
genesis_validators_root: pre.genesis_validators_root,
|
genesis_validators_root: pre.genesis_validators_root,
|
||||||
@@ -62,6 +75,16 @@ pub fn upgrade_to_electra<E: EthSpec>(
|
|||||||
next_withdrawal_index: pre.next_withdrawal_index,
|
next_withdrawal_index: pre.next_withdrawal_index,
|
||||||
next_withdrawal_validator_index: pre.next_withdrawal_validator_index,
|
next_withdrawal_validator_index: pre.next_withdrawal_validator_index,
|
||||||
historical_summaries: pre.historical_summaries.clone(),
|
historical_summaries: pre.historical_summaries.clone(),
|
||||||
|
// Electra
|
||||||
|
deposit_receipts_start_index: spec.unset_deposit_receipts_start_index,
|
||||||
|
deposit_balance_to_consume: 0,
|
||||||
|
exit_balance_to_consume,
|
||||||
|
earliest_exit_epoch,
|
||||||
|
consolidation_balance_to_consume,
|
||||||
|
earliest_consolidation_epoch,
|
||||||
|
pending_balance_deposits: Default::default(),
|
||||||
|
pending_partial_withdrawals: Default::default(),
|
||||||
|
pending_consolidations: Default::default(),
|
||||||
// Caches
|
// Caches
|
||||||
total_active_balance: pre.total_active_balance,
|
total_active_balance: pre.total_active_balance,
|
||||||
progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache),
|
progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache),
|
||||||
@@ -72,6 +95,37 @@ pub fn upgrade_to_electra<E: EthSpec>(
|
|||||||
epoch_cache: EpochCache::default(),
|
epoch_cache: EpochCache::default(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add validators that are not yet active to pending balance deposits
|
||||||
|
let validators = post.validators().clone();
|
||||||
|
let mut pre_activation = validators
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, validator)| validator.activation_epoch == spec.far_future_epoch)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Sort the indices by activation_eligibility_epoch and then by index
|
||||||
|
pre_activation.sort_by(|(index_a, val_a), (index_b, val_b)| {
|
||||||
|
if val_a.activation_eligibility_epoch == val_b.activation_eligibility_epoch {
|
||||||
|
index_a.cmp(index_b)
|
||||||
|
} else {
|
||||||
|
val_a
|
||||||
|
.activation_eligibility_epoch
|
||||||
|
.cmp(&val_b.activation_eligibility_epoch)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Process validators to queue entire balance and reset them
|
||||||
|
for (index, _) in pre_activation {
|
||||||
|
post.queue_entire_balance_and_reset_validator(index, spec)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure early adopters of compounding credentials go through the activation churn
|
||||||
|
for (index, validator) in validators.iter().enumerate() {
|
||||||
|
if validator.has_compounding_withdrawal_credential(spec) {
|
||||||
|
post.queue_excess_active_balance(index, spec)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*pre_state = post;
|
*pre_state = post;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -467,6 +467,40 @@ where
|
|||||||
#[test_random(default)]
|
#[test_random(default)]
|
||||||
pub historical_summaries: List<HistoricalSummary, E::HistoricalRootsLimit>,
|
pub historical_summaries: List<HistoricalSummary, E::HistoricalRootsLimit>,
|
||||||
|
|
||||||
|
// Electra
|
||||||
|
#[superstruct(only(Electra), partial_getter(copy))]
|
||||||
|
#[metastruct(exclude_from(tree_lists))]
|
||||||
|
#[serde(with = "serde_utils::quoted_u64")]
|
||||||
|
pub deposit_receipts_start_index: u64,
|
||||||
|
#[superstruct(only(Electra), partial_getter(copy))]
|
||||||
|
#[metastruct(exclude_from(tree_lists))]
|
||||||
|
#[serde(with = "serde_utils::quoted_u64")]
|
||||||
|
pub deposit_balance_to_consume: u64,
|
||||||
|
#[superstruct(only(Electra), partial_getter(copy))]
|
||||||
|
#[metastruct(exclude_from(tree_lists))]
|
||||||
|
#[serde(with = "serde_utils::quoted_u64")]
|
||||||
|
pub exit_balance_to_consume: u64,
|
||||||
|
#[superstruct(only(Electra), partial_getter(copy))]
|
||||||
|
#[metastruct(exclude_from(tree_lists))]
|
||||||
|
pub earliest_exit_epoch: Epoch,
|
||||||
|
#[superstruct(only(Electra), partial_getter(copy))]
|
||||||
|
#[metastruct(exclude_from(tree_lists))]
|
||||||
|
#[serde(with = "serde_utils::quoted_u64")]
|
||||||
|
pub consolidation_balance_to_consume: u64,
|
||||||
|
#[superstruct(only(Electra), partial_getter(copy))]
|
||||||
|
#[metastruct(exclude_from(tree_lists))]
|
||||||
|
pub earliest_consolidation_epoch: Epoch,
|
||||||
|
#[test_random(default)]
|
||||||
|
#[superstruct(only(Electra))]
|
||||||
|
pub pending_balance_deposits: List<PendingBalanceDeposit, E::PendingBalanceDepositsLimit>,
|
||||||
|
#[test_random(default)]
|
||||||
|
#[superstruct(only(Electra))]
|
||||||
|
pub pending_partial_withdrawals:
|
||||||
|
List<PendingPartialWithdrawal, E::PendingPartialWithdrawalsLimit>,
|
||||||
|
#[test_random(default)]
|
||||||
|
#[superstruct(only(Electra))]
|
||||||
|
pub pending_consolidations: List<PendingConsolidation, E::PendingConsolidationsLimit>,
|
||||||
|
|
||||||
// Caching (not in the spec)
|
// Caching (not in the spec)
|
||||||
#[serde(skip_serializing, skip_deserializing)]
|
#[serde(skip_serializing, skip_deserializing)]
|
||||||
#[ssz(skip_serializing, skip_deserializing)]
|
#[ssz(skip_serializing, skip_deserializing)]
|
||||||
@@ -2031,6 +2065,83 @@ impl<E: EthSpec> BeaconState<E> {
|
|||||||
self.epoch_cache().get_base_reward(validator_index)
|
self.epoch_cache().get_base_reward(validator_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ******* Electra accessors *******
|
||||||
|
|
||||||
|
/// Return the churn limit for the current epoch.
|
||||||
|
pub fn get_balance_churn_limit(&self, spec: &ChainSpec) -> Result<u64, Error> {
|
||||||
|
let total_active_balance = self.get_total_active_balance()?;
|
||||||
|
let churn = std::cmp::max(
|
||||||
|
spec.min_per_epoch_churn_limit_electra,
|
||||||
|
total_active_balance.safe_div(spec.churn_limit_quotient)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(churn.safe_sub(churn.safe_rem(spec.effective_balance_increment)?)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the churn limit for the current epoch dedicated to activations and exits.
|
||||||
|
pub fn get_activation_exit_churn_limit(&self, spec: &ChainSpec) -> Result<u64, Error> {
|
||||||
|
Ok(std::cmp::min(
|
||||||
|
spec.max_per_epoch_activation_exit_churn_limit,
|
||||||
|
self.get_balance_churn_limit(spec)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_consolidation_churn_limit(&self, spec: &ChainSpec) -> Result<u64, Error> {
|
||||||
|
self.get_balance_churn_limit(spec)?
|
||||||
|
.safe_sub(self.get_activation_exit_churn_limit(spec)?)
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******* Electra mutators *******
|
||||||
|
|
||||||
|
pub fn queue_excess_active_balance(
|
||||||
|
&mut self,
|
||||||
|
validator_index: usize,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let balance = self
|
||||||
|
.balances_mut()
|
||||||
|
.get_mut(validator_index)
|
||||||
|
.ok_or(Error::UnknownValidator(validator_index))?;
|
||||||
|
if *balance > spec.min_activation_balance {
|
||||||
|
let excess_balance = balance.safe_sub(spec.min_activation_balance)?;
|
||||||
|
*balance = spec.min_activation_balance;
|
||||||
|
self.pending_balance_deposits_mut()?
|
||||||
|
.push(PendingBalanceDeposit {
|
||||||
|
index: validator_index as u64,
|
||||||
|
amount: excess_balance,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queue_entire_balance_and_reset_validator(
|
||||||
|
&mut self,
|
||||||
|
validator_index: usize,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let balance = self
|
||||||
|
.balances_mut()
|
||||||
|
.get_mut(validator_index)
|
||||||
|
.ok_or(Error::UnknownValidator(validator_index))?;
|
||||||
|
let balance_copy = *balance;
|
||||||
|
*balance = 0_u64;
|
||||||
|
|
||||||
|
let validator = self
|
||||||
|
.validators_mut()
|
||||||
|
.get_mut(validator_index)
|
||||||
|
.ok_or(Error::UnknownValidator(validator_index))?;
|
||||||
|
validator.effective_balance = 0;
|
||||||
|
validator.activation_eligibility_epoch = spec.far_future_epoch;
|
||||||
|
|
||||||
|
self.pending_balance_deposits_mut()?
|
||||||
|
.push(PendingBalanceDeposit {
|
||||||
|
index: validator_index as u64,
|
||||||
|
amount: balance_copy,
|
||||||
|
})
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::arithmetic_side_effects)]
|
#[allow(clippy::arithmetic_side_effects)]
|
||||||
pub fn rebase_on(&mut self, base: &Self, spec: &ChainSpec) -> Result<(), Error> {
|
pub fn rebase_on(&mut self, base: &Self, spec: &ChainSpec) -> Result<(), Error> {
|
||||||
// Required for macros (which use type-hints internally).
|
// Required for macros (which use type-hints internally).
|
||||||
|
|||||||
@@ -102,6 +102,11 @@ impl Validator {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if ``validator`` has an 0x02 prefixed "compounding" withdrawal credential.
|
||||||
|
pub fn has_compounding_withdrawal_credential(&self, spec: &ChainSpec) -> bool {
|
||||||
|
is_compounding_withdrawal_credential(self.withdrawal_credentials, spec)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the eth1 withdrawal address if this validator has one initialized.
|
/// Get the eth1 withdrawal address if this validator has one initialized.
|
||||||
pub fn get_eth1_withdrawal_address(&self, spec: &ChainSpec) -> Option<Address> {
|
pub fn get_eth1_withdrawal_address(&self, spec: &ChainSpec) -> Option<Address> {
|
||||||
self.has_eth1_withdrawal_credential(spec)
|
self.has_eth1_withdrawal_credential(spec)
|
||||||
@@ -153,6 +158,17 @@ impl Default for Validator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_compounding_withdrawal_credential(
|
||||||
|
withdrawal_credentials: Hash256,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
) -> bool {
|
||||||
|
withdrawal_credentials
|
||||||
|
.as_bytes()
|
||||||
|
.first()
|
||||||
|
.map(|prefix_byte| *prefix_byte == spec.compounding_withdrawal_prefix_byte)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user