@@ -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).
0 commit comments