-
Notifications
You must be signed in to change notification settings - Fork 794
/
Copy pathregistry_updates.rs
69 lines (63 loc) · 2.76 KB
/
registry_updates.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use crate::{common::initiate_validator_exit, per_epoch_processing::Error};
use itertools::Itertools;
use safe_arith::SafeArith;
use types::{BeaconState, ChainSpec, EthSpec, Validator};
/// Performs a validator registry update, if required.
///
/// NOTE: unchanged in Altair
pub fn process_registry_updates<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
) -> Result<(), Error> {
// Process activation eligibility and ejections.
// Collect eligible and exiting validators (we need to avoid mutating the state while iterating).
// We assume it's safe to re-order the change in eligibility and `initiate_validator_exit`.
// Rest assured exiting validators will still be exited in the same order as in the spec.
let current_epoch = state.current_epoch();
let is_ejectable = |validator: &Validator| {
validator.is_active_at(current_epoch)
&& validator.effective_balance <= spec.ejection_balance
};
let indices_to_update: Vec<_> = state
.validators()
.iter()
.enumerate()
.filter(|(_, validator)| {
validator.is_eligible_for_activation_queue(spec) || is_ejectable(validator)
})
.map(|(idx, _)| idx)
.collect();
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)?;
}
if is_ejectable(validator) {
initiate_validator_exit(state, index, spec)?;
}
}
// Queue validators eligible for activation and not dequeued for activation prior to finalized epoch
let activation_queue = state
.validators()
.iter()
.enumerate()
.filter(|(_, validator)| validator.is_eligible_for_activation(state, spec))
.sorted_by_key(|(index, validator)| (validator.activation_eligibility_epoch, *index))
.map(|(index, _)| index)
.collect_vec();
// We've just absorbed the logic of `get_validator_activation_churn_limit` here
let activation_churn_limit = match state {
BeaconState::Base(_)
| BeaconState::Altair(_)
| BeaconState::Merge(_)
| BeaconState::Capella(_) => state.get_churn_limit(spec)? as usize,
BeaconState::Deneb(_) => spec.max_per_epoch_activation_churn_limit as usize,
BeaconState::Electra(_) => activation_queue.len(),
};
// Dequeue validators for activation up to churn limit
let delayed_activation_epoch = state.compute_activation_exit_epoch(current_epoch, spec)?;
for index in activation_queue.into_iter().take(activation_churn_limit) {
state.get_validator_mut(index)?.activation_epoch = delayed_activation_epoch;
}
Ok(())
}