mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 10:11:44 +00:00
Merge branch 'beacon-api-electra' of https://github.com/sigp/lighthouse into p2p-electra
This commit is contained in:
@@ -98,7 +98,10 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
.unwrap())
|
||||
}
|
||||
}
|
||||
ENGINE_NEW_PAYLOAD_V1 | ENGINE_NEW_PAYLOAD_V2 | ENGINE_NEW_PAYLOAD_V3 => {
|
||||
ENGINE_NEW_PAYLOAD_V1
|
||||
| ENGINE_NEW_PAYLOAD_V2
|
||||
| ENGINE_NEW_PAYLOAD_V3
|
||||
| ENGINE_NEW_PAYLOAD_V4 => {
|
||||
let request = match method {
|
||||
ENGINE_NEW_PAYLOAD_V1 => JsonExecutionPayload::V1(
|
||||
get_param::<JsonExecutionPayloadV1<E>>(params, 0)
|
||||
|
||||
@@ -8,12 +8,12 @@ pub fn initiate_validator_exit<E: EthSpec>(
|
||||
index: usize,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
// We do things in a slightly different order to the spec here. Instead of immediately checking
|
||||
// whether the validator has already exited, we instead prepare the exit cache and compute the
|
||||
// cheap-to-calculate values from that. *Then* we look up the validator a single time in the
|
||||
// validator tree (expensive), make the check and mutate as appropriate. Compared to the spec
|
||||
// ordering, this saves us from looking up the validator in the validator registry multiple
|
||||
// times.
|
||||
let validator = state.get_validator_cow(index)?;
|
||||
|
||||
// Return if the validator already initiated exit
|
||||
if validator.exit_epoch != spec.far_future_epoch {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Ensure the exit cache is built.
|
||||
state.build_exit_cache(spec)?;
|
||||
@@ -36,14 +36,7 @@ pub fn initiate_validator_exit<E: EthSpec>(
|
||||
exit_queue_epoch
|
||||
};
|
||||
|
||||
let validator = state.get_validator_cow(index)?;
|
||||
|
||||
// Return if the validator already initiated exit
|
||||
if validator.exit_epoch != spec.far_future_epoch {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let validator = validator.into_mut()?;
|
||||
let validator = state.get_validator_mut(index)?;
|
||||
validator.exit_epoch = exit_queue_epoch;
|
||||
validator.withdrawable_epoch =
|
||||
exit_queue_epoch.safe_add(spec.min_validator_withdrawability_delay)?;
|
||||
|
||||
@@ -86,9 +86,10 @@ impl PreEpochCache {
|
||||
let base_reward_per_increment = BaseRewardPerIncrement::new(total_active_balance, spec)?;
|
||||
|
||||
let effective_balance_increment = spec.effective_balance_increment;
|
||||
let max_effective_balance_eth = spec
|
||||
.max_effective_balance
|
||||
.safe_div(effective_balance_increment)?;
|
||||
let max_effective_balance =
|
||||
spec.max_effective_balance_for_fork(spec.fork_name_at_epoch(epoch));
|
||||
let max_effective_balance_eth =
|
||||
max_effective_balance.safe_div(effective_balance_increment)?;
|
||||
|
||||
let mut base_rewards = Vec::with_capacity(max_effective_balance_eth.safe_add(1)? as usize);
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ pub enum EpochProcessingError {
|
||||
MilhouseError(milhouse::Error),
|
||||
EpochCache(EpochCacheError),
|
||||
SinglePassMissingActivationQueue,
|
||||
MissingEarliestExitEpoch,
|
||||
MissingExitBalanceToConsume,
|
||||
}
|
||||
|
||||
impl From<InclusionError> for EpochProcessingError {
|
||||
|
||||
@@ -167,6 +167,9 @@ pub fn process_epoch_single_pass<E: EthSpec>(
|
||||
None
|
||||
};
|
||||
|
||||
let mut earliest_exit_epoch = state.earliest_exit_epoch().ok();
|
||||
let mut exit_balance_to_consume = state.exit_balance_to_consume().ok();
|
||||
|
||||
// Split the state into several disjoint mutable borrows.
|
||||
let (
|
||||
validators,
|
||||
@@ -286,6 +289,8 @@ pub fn process_epoch_single_pass<E: EthSpec>(
|
||||
exit_cache,
|
||||
activation_queue_refs,
|
||||
state_ctxt,
|
||||
earliest_exit_epoch.as_mut(),
|
||||
exit_balance_to_consume.as_mut(),
|
||||
spec,
|
||||
)?;
|
||||
}
|
||||
@@ -320,6 +325,17 @@ pub fn process_epoch_single_pass<E: EthSpec>(
|
||||
}
|
||||
}
|
||||
|
||||
if conf.registry_updates && fork_name >= ForkName::Electra {
|
||||
if let Ok(earliest_exit_epoch_state) = state.earliest_exit_epoch_mut() {
|
||||
*earliest_exit_epoch_state =
|
||||
earliest_exit_epoch.ok_or(Error::MissingEarliestExitEpoch)?;
|
||||
}
|
||||
if let Ok(exit_balance_to_consume_state) = state.exit_balance_to_consume_mut() {
|
||||
*exit_balance_to_consume_state =
|
||||
exit_balance_to_consume.ok_or(Error::MissingExitBalanceToConsume)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Finish processing pending balance deposits if relevant.
|
||||
//
|
||||
// This *could* be reordered after `process_pending_consolidations` which pushes only to the end
|
||||
@@ -527,12 +543,15 @@ impl RewardsAndPenaltiesContext {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn process_single_registry_update(
|
||||
validator: &mut Cow<Validator>,
|
||||
validator_info: &ValidatorInfo,
|
||||
exit_cache: &mut ExitCache,
|
||||
activation_queues: Option<(&BTreeSet<usize>, &mut ActivationQueue)>,
|
||||
state_ctxt: &StateContext,
|
||||
earliest_exit_epoch: Option<&mut Epoch>,
|
||||
exit_balance_to_consume: Option<&mut u64>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
if state_ctxt.fork_name < ForkName::Electra {
|
||||
@@ -548,7 +567,14 @@ fn process_single_registry_update(
|
||||
spec,
|
||||
)
|
||||
} else {
|
||||
process_single_registry_update_post_electra(validator, exit_cache, state_ctxt, spec)
|
||||
process_single_registry_update_post_electra(
|
||||
validator,
|
||||
exit_cache,
|
||||
state_ctxt,
|
||||
earliest_exit_epoch.ok_or(Error::MissingEarliestExitEpoch)?,
|
||||
exit_balance_to_consume.ok_or(Error::MissingExitBalanceToConsume)?,
|
||||
spec,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,7 +595,7 @@ fn process_single_registry_update_pre_electra(
|
||||
|
||||
if validator.is_active_at(current_epoch) && validator.effective_balance <= spec.ejection_balance
|
||||
{
|
||||
initiate_validator_exit(validator, exit_cache, state_ctxt, spec)?;
|
||||
initiate_validator_exit(validator, exit_cache, state_ctxt, None, None, spec)?;
|
||||
}
|
||||
|
||||
if activation_queue.contains(&validator_info.index) {
|
||||
@@ -592,6 +618,8 @@ fn process_single_registry_update_post_electra(
|
||||
validator: &mut Cow<Validator>,
|
||||
exit_cache: &mut ExitCache,
|
||||
state_ctxt: &StateContext,
|
||||
earliest_exit_epoch: &mut Epoch,
|
||||
exit_balance_to_consume: &mut u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
let current_epoch = state_ctxt.current_epoch;
|
||||
@@ -602,8 +630,14 @@ fn process_single_registry_update_post_electra(
|
||||
|
||||
if validator.is_active_at(current_epoch) && validator.effective_balance <= spec.ejection_balance
|
||||
{
|
||||
// TODO(electra): make sure initiate_validator_exit is updated
|
||||
initiate_validator_exit(validator, exit_cache, state_ctxt, spec)?;
|
||||
initiate_validator_exit(
|
||||
validator,
|
||||
exit_cache,
|
||||
state_ctxt,
|
||||
Some(earliest_exit_epoch),
|
||||
Some(exit_balance_to_consume),
|
||||
spec,
|
||||
)?;
|
||||
}
|
||||
|
||||
if validator.is_eligible_for_activation_with_finalized_checkpoint(
|
||||
@@ -621,6 +655,8 @@ fn initiate_validator_exit(
|
||||
validator: &mut Cow<Validator>,
|
||||
exit_cache: &mut ExitCache,
|
||||
state_ctxt: &StateContext,
|
||||
earliest_exit_epoch: Option<&mut Epoch>,
|
||||
exit_balance_to_consume: Option<&mut u64>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
// Return if the validator already initiated exit
|
||||
@@ -628,16 +664,27 @@ fn initiate_validator_exit(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Compute exit queue epoch
|
||||
let delayed_epoch = spec.compute_activation_exit_epoch(state_ctxt.current_epoch)?;
|
||||
let mut exit_queue_epoch = exit_cache
|
||||
.max_epoch()?
|
||||
.map_or(delayed_epoch, |epoch| max(epoch, delayed_epoch));
|
||||
let exit_queue_churn = exit_cache.get_churn_at(exit_queue_epoch)?;
|
||||
let exit_queue_epoch = if state_ctxt.fork_name >= ForkName::Electra {
|
||||
compute_exit_epoch_and_update_churn(
|
||||
validator,
|
||||
state_ctxt,
|
||||
earliest_exit_epoch.ok_or(Error::MissingEarliestExitEpoch)?,
|
||||
exit_balance_to_consume.ok_or(Error::MissingExitBalanceToConsume)?,
|
||||
spec,
|
||||
)?
|
||||
} else {
|
||||
// Compute exit queue epoch
|
||||
let delayed_epoch = spec.compute_activation_exit_epoch(state_ctxt.current_epoch)?;
|
||||
let mut exit_queue_epoch = exit_cache
|
||||
.max_epoch()?
|
||||
.map_or(delayed_epoch, |epoch| max(epoch, delayed_epoch));
|
||||
let exit_queue_churn = exit_cache.get_churn_at(exit_queue_epoch)?;
|
||||
|
||||
if exit_queue_churn >= state_ctxt.churn_limit {
|
||||
exit_queue_epoch.safe_add_assign(1)?;
|
||||
}
|
||||
if exit_queue_churn >= state_ctxt.churn_limit {
|
||||
exit_queue_epoch.safe_add_assign(1)?;
|
||||
}
|
||||
exit_queue_epoch
|
||||
};
|
||||
|
||||
let validator = validator.make_mut()?;
|
||||
validator.exit_epoch = exit_queue_epoch;
|
||||
@@ -648,6 +695,64 @@ fn initiate_validator_exit(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compute_exit_epoch_and_update_churn(
|
||||
validator: &mut Cow<Validator>,
|
||||
state_ctxt: &StateContext,
|
||||
earliest_exit_epoch_state: &mut Epoch,
|
||||
exit_balance_to_consume_state: &mut u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Epoch, Error> {
|
||||
let exit_balance = validator.effective_balance;
|
||||
let mut earliest_exit_epoch = std::cmp::max(
|
||||
*earliest_exit_epoch_state,
|
||||
spec.compute_activation_exit_epoch(state_ctxt.current_epoch)?,
|
||||
);
|
||||
|
||||
let per_epoch_churn = get_activation_exit_churn_limit(state_ctxt, spec)?;
|
||||
// New epoch for exits
|
||||
let mut exit_balance_to_consume = if *earliest_exit_epoch_state < earliest_exit_epoch {
|
||||
per_epoch_churn
|
||||
} else {
|
||||
*exit_balance_to_consume_state
|
||||
};
|
||||
|
||||
// Exit doesn't fit in the current earliest epoch
|
||||
if exit_balance > exit_balance_to_consume {
|
||||
let balance_to_process = exit_balance.safe_sub(exit_balance_to_consume)?;
|
||||
let additional_epochs = balance_to_process
|
||||
.safe_sub(1)?
|
||||
.safe_div(per_epoch_churn)?
|
||||
.safe_add(1)?;
|
||||
earliest_exit_epoch.safe_add_assign(additional_epochs)?;
|
||||
exit_balance_to_consume.safe_add_assign(additional_epochs.safe_mul(per_epoch_churn)?)?;
|
||||
}
|
||||
// Consume the balance and update state variables
|
||||
*exit_balance_to_consume_state = exit_balance_to_consume.safe_sub(exit_balance)?;
|
||||
*earliest_exit_epoch_state = earliest_exit_epoch;
|
||||
|
||||
Ok(earliest_exit_epoch)
|
||||
}
|
||||
|
||||
fn get_activation_exit_churn_limit(
|
||||
state_ctxt: &StateContext,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<u64, Error> {
|
||||
Ok(std::cmp::min(
|
||||
spec.max_per_epoch_activation_exit_churn_limit,
|
||||
get_balance_churn_limit(state_ctxt, spec)?,
|
||||
))
|
||||
}
|
||||
|
||||
fn get_balance_churn_limit(state_ctxt: &StateContext, spec: &ChainSpec) -> Result<u64, Error> {
|
||||
let total_active_balance = state_ctxt.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)?)?)
|
||||
}
|
||||
|
||||
impl SlashingsContext {
|
||||
fn new<E: EthSpec>(
|
||||
state: &BeaconState<E>,
|
||||
|
||||
@@ -400,6 +400,14 @@ impl ChainSpec {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_effective_balance_for_fork(&self, fork_name: ForkName) -> u64 {
|
||||
if fork_name >= ForkName::Electra {
|
||||
self.max_effective_balance_electra
|
||||
} else {
|
||||
self.max_effective_balance
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a full `Fork` struct for a given epoch.
|
||||
pub fn fork_at_epoch(&self, epoch: Epoch) -> Fork {
|
||||
let current_fork_name = self.fork_name_at_epoch(epoch);
|
||||
|
||||
Reference in New Issue
Block a user