Skip to content

Commit 8b24880

Browse files
authored
Add more electra helpers (#5653)
* Add new helpers * Fix some stuff * Fix compilation errors * lint * Address review
1 parent 000a4fd commit 8b24880

File tree

2 files changed

+157
-6
lines changed

2 files changed

+157
-6
lines changed

consensus/types/src/beacon_state.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,38 @@ impl<E: EthSpec> BeaconState<E> {
20922092
.map_err(Into::into)
20932093
}
20942094

2095+
/// Get active balance for the given `validator_index`.
2096+
pub fn get_active_balance(
2097+
&self,
2098+
validator_index: usize,
2099+
spec: &ChainSpec,
2100+
) -> Result<u64, Error> {
2101+
let max_effective_balance = self
2102+
.validators()
2103+
.get(validator_index)
2104+
.map(|validator| validator.get_validator_max_effective_balance(spec))
2105+
.ok_or(Error::UnknownValidator(validator_index))?;
2106+
Ok(std::cmp::min(
2107+
*self
2108+
.balances()
2109+
.get(validator_index)
2110+
.ok_or(Error::UnknownValidator(validator_index))?,
2111+
max_effective_balance,
2112+
))
2113+
}
2114+
2115+
pub fn get_pending_balance_to_withdraw(&self, validator_index: usize) -> Result<u64, Error> {
2116+
let mut pending_balance = 0;
2117+
for withdrawal in self
2118+
.pending_partial_withdrawals()?
2119+
.iter()
2120+
.filter(|withdrawal| withdrawal.index as usize == validator_index)
2121+
{
2122+
pending_balance.safe_add_assign(withdrawal.amount)?;
2123+
}
2124+
Ok(pending_balance)
2125+
}
2126+
20952127
// ******* Electra mutators *******
20962128

20972129
pub fn queue_excess_active_balance(
@@ -2142,6 +2174,101 @@ impl<E: EthSpec> BeaconState<E> {
21422174
.map_err(Into::into)
21432175
}
21442176

2177+
/// Change the withdrawal prefix of the given `validator_index` to the compounding withdrawal validator prefix.
2178+
pub fn switch_to_compounding_validator(
2179+
&mut self,
2180+
validator_index: usize,
2181+
spec: &ChainSpec,
2182+
) -> Result<(), Error> {
2183+
let validator = self
2184+
.validators_mut()
2185+
.get_mut(validator_index)
2186+
.ok_or(Error::UnknownValidator(validator_index))?;
2187+
if validator.has_eth1_withdrawal_credential(spec) {
2188+
validator.withdrawal_credentials.as_fixed_bytes_mut()[0] =
2189+
spec.compounding_withdrawal_prefix_byte;
2190+
self.queue_excess_active_balance(validator_index, spec)?;
2191+
}
2192+
Ok(())
2193+
}
2194+
2195+
pub fn compute_exit_epoch_and_update_churn(
2196+
&mut self,
2197+
exit_balance: u64,
2198+
spec: &ChainSpec,
2199+
) -> Result<Epoch, Error> {
2200+
let mut earliest_exit_epoch = std::cmp::max(
2201+
self.earliest_exit_epoch()?,
2202+
self.compute_activation_exit_epoch(self.current_epoch(), spec)?,
2203+
);
2204+
2205+
let per_epoch_churn = self.get_activation_exit_churn_limit(spec)?;
2206+
// New epoch for exits
2207+
let mut exit_balance_to_consume = if self.earliest_exit_epoch()? < earliest_exit_epoch {
2208+
per_epoch_churn
2209+
} else {
2210+
self.exit_balance_to_consume()?
2211+
};
2212+
2213+
// Exit doesn't fit in the current earliest epoch
2214+
if exit_balance > exit_balance_to_consume {
2215+
let balance_to_process = exit_balance.safe_sub(exit_balance_to_consume)?;
2216+
let additional_epochs = balance_to_process
2217+
.safe_sub(1)?
2218+
.safe_div(per_epoch_churn)?
2219+
.safe_add(1)?;
2220+
earliest_exit_epoch.safe_add_assign(additional_epochs)?;
2221+
exit_balance_to_consume
2222+
.safe_add_assign(additional_epochs.safe_mul(per_epoch_churn)?)?;
2223+
}
2224+
let state = self.as_electra_mut()?;
2225+
// Consume the balance and update state variables
2226+
state.exit_balance_to_consume = exit_balance_to_consume.safe_sub(exit_balance)?;
2227+
state.earliest_exit_epoch = earliest_exit_epoch;
2228+
2229+
Ok(state.earliest_exit_epoch)
2230+
}
2231+
2232+
pub fn compute_consolidation_epoch_and_update_churn(
2233+
&mut self,
2234+
consolidation_balance: u64,
2235+
spec: &ChainSpec,
2236+
) -> Result<Epoch, Error> {
2237+
let mut earliest_consolidation_epoch = std::cmp::max(
2238+
self.earliest_consolidation_epoch()?,
2239+
self.compute_activation_exit_epoch(self.current_epoch(), spec)?,
2240+
);
2241+
2242+
let per_epoch_consolidation_churn = self.get_consolidation_churn_limit(spec)?;
2243+
2244+
// New epoch for consolidations
2245+
let mut consolidation_balance_to_consume =
2246+
if self.earliest_consolidation_epoch()? < earliest_consolidation_epoch {
2247+
per_epoch_consolidation_churn
2248+
} else {
2249+
self.consolidation_balance_to_consume()?
2250+
};
2251+
// Consolidation doesn't fit in the current earliest epoch
2252+
if consolidation_balance > consolidation_balance_to_consume {
2253+
let balance_to_process =
2254+
consolidation_balance.safe_sub(consolidation_balance_to_consume)?;
2255+
let additional_epochs = balance_to_process
2256+
.safe_sub(1)?
2257+
.safe_div(per_epoch_consolidation_churn)?
2258+
.safe_add(1)?;
2259+
earliest_consolidation_epoch.safe_add_assign(additional_epochs)?;
2260+
consolidation_balance_to_consume
2261+
.safe_add_assign(additional_epochs.safe_mul(per_epoch_consolidation_churn)?)?;
2262+
}
2263+
// Consume the balance and update state variables
2264+
let state = self.as_electra_mut()?;
2265+
state.consolidation_balance_to_consume =
2266+
consolidation_balance_to_consume.safe_sub(consolidation_balance)?;
2267+
state.earliest_consolidation_epoch = earliest_consolidation_epoch;
2268+
2269+
Ok(state.earliest_consolidation_epoch)
2270+
}
2271+
21452272
#[allow(clippy::arithmetic_side_effects)]
21462273
pub fn rebase_on(&mut self, base: &Self, spec: &ChainSpec) -> Result<(), Error> {
21472274
// Required for macros (which use type-hints internally).

consensus/types/src/validator.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ impl Validator {
5757

5858
/// Returns `true` if the validator is eligible to join the activation queue.
5959
///
60-
/// Spec v0.12.1
60+
/// Modified in electra
6161
pub fn is_eligible_for_activation_queue(&self, spec: &ChainSpec) -> bool {
6262
self.activation_eligibility_epoch == spec.far_future_epoch
63-
&& self.effective_balance == spec.max_effective_balance
63+
&& self.effective_balance >= spec.min_activation_balance
6464
}
6565

6666
/// Returns `true` if the validator is eligible to be activated.
@@ -130,15 +130,39 @@ impl Validator {
130130
}
131131

132132
/// Returns `true` if the validator is fully withdrawable at some epoch.
133+
///
134+
/// Note: Modified in electra.
133135
pub fn is_fully_withdrawable_at(&self, balance: u64, epoch: Epoch, spec: &ChainSpec) -> bool {
134-
self.has_eth1_withdrawal_credential(spec) && self.withdrawable_epoch <= epoch && balance > 0
136+
self.has_execution_withdrawal_credential(spec)
137+
&& self.withdrawable_epoch <= epoch
138+
&& balance > 0
135139
}
136140

137141
/// Returns `true` if the validator is partially withdrawable.
142+
///
143+
/// Note: Modified in electra.
138144
pub fn is_partially_withdrawable_validator(&self, balance: u64, spec: &ChainSpec) -> bool {
139-
self.has_eth1_withdrawal_credential(spec)
140-
&& self.effective_balance == spec.max_effective_balance
141-
&& balance > spec.max_effective_balance
145+
let max_effective_balance = self.get_validator_max_effective_balance(spec);
146+
let has_max_effective_balance = self.effective_balance == max_effective_balance;
147+
let has_excess_balance = balance > max_effective_balance;
148+
self.has_execution_withdrawal_credential(spec)
149+
&& has_max_effective_balance
150+
&& has_excess_balance
151+
}
152+
153+
/// Returns `true` if the validator has a 0x01 or 0x02 prefixed withdrawal credential.
154+
pub fn has_execution_withdrawal_credential(&self, spec: &ChainSpec) -> bool {
155+
self.has_compounding_withdrawal_credential(spec)
156+
|| self.has_eth1_withdrawal_credential(spec)
157+
}
158+
159+
/// Returns the max effective balance for a validator in gwei.
160+
pub fn get_validator_max_effective_balance(&self, spec: &ChainSpec) -> u64 {
161+
if self.has_compounding_withdrawal_credential(spec) {
162+
spec.max_effective_balance_electra
163+
} else {
164+
spec.min_activation_balance
165+
}
142166
}
143167
}
144168

0 commit comments

Comments
 (0)