@@ -23,12 +23,14 @@ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX;
2323 *
2424 * - On normal mainnet conditions 0 validators change their effective balance
2525 * - In case of big innactivity event a medium portion of validators may have their effectiveBalance updated
26+ *
27+ * Return number of validators updated
2628 */
2729export function processEffectiveBalanceUpdates (
2830 fork : ForkSeq ,
2931 state : CachedBeaconStateAllForks ,
3032 cache : EpochTransitionCache
31- ) : void {
33+ ) : number {
3234 const HYSTERESIS_INCREMENT = EFFECTIVE_BALANCE_INCREMENT / HYSTERESIS_QUOTIENT ;
3335 const DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER ;
3436 const UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER ;
@@ -43,34 +45,38 @@ export function processEffectiveBalanceUpdates(
4345 // and updated in processPendingBalanceDeposits() and processPendingConsolidations()
4446 // so it's recycled here for performance.
4547 const balances = cache . balances ?? state . balances . getAll ( ) ;
48+ const currentEpochValidators = cache . validators ;
49+ const newCompoundingValidators = cache . newCompoundingValidators ?? new Set ( ) ;
4650
51+ let numUpdate = 0 ;
4752 for ( let i = 0 , len = balances . length ; i < len ; i ++ ) {
4853 const balance = balances [ i ] ;
4954
5055 // PERF: It's faster to access to get() every single element (4ms) than to convert to regular array then loop (9ms)
5156 let effectiveBalanceIncrement = effectiveBalanceIncrements [ i ] ;
5257 let effectiveBalance = effectiveBalanceIncrement * EFFECTIVE_BALANCE_INCREMENT ;
53- let effectiveBalanceLimit ;
58+
59+ let effectiveBalanceLimit : number ;
60+ if ( fork < ForkSeq . electra ) {
61+ effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE ;
62+ } else {
63+ // from electra, effectiveBalanceLimit is per validator
64+ const isCompoundingValidator =
65+ hasCompoundingWithdrawalCredential ( currentEpochValidators [ i ] . withdrawalCredentials ) ||
66+ newCompoundingValidators . has ( i ) ;
67+ effectiveBalanceLimit = isCompoundingValidator ? MAX_EFFECTIVE_BALANCE_ELECTRA : MIN_ACTIVATION_BALANCE ;
68+ }
5469
5570 if (
5671 // Too big
5772 effectiveBalance > balance + DOWNWARD_THRESHOLD ||
5873 // Too small. Check effectiveBalance < MAX_EFFECTIVE_BALANCE to prevent unnecessary updates
59- effectiveBalance + UPWARD_THRESHOLD < balance
74+ ( effectiveBalance < effectiveBalanceLimit && effectiveBalance + UPWARD_THRESHOLD < balance )
6075 ) {
6176 // Update the state tree
6277 // Should happen rarely, so it's fine to update the tree
6378 const validator = validators . get ( i ) ;
6479
65- if ( fork < ForkSeq . electra ) {
66- effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE ;
67- } else {
68- // Electra or after
69- effectiveBalanceLimit = hasCompoundingWithdrawalCredential ( validator . withdrawalCredentials )
70- ? MAX_EFFECTIVE_BALANCE_ELECTRA
71- : MIN_ACTIVATION_BALANCE ;
72- }
73-
7480 effectiveBalance = Math . min ( balance - ( balance % EFFECTIVE_BALANCE_INCREMENT ) , effectiveBalanceLimit ) ;
7581 validator . effectiveBalance = effectiveBalance ;
7682 // Also update the fast cached version
@@ -95,6 +101,7 @@ export function processEffectiveBalanceUpdates(
95101
96102 effectiveBalanceIncrement = newEffectiveBalanceIncrement ;
97103 effectiveBalanceIncrements [ i ] = effectiveBalanceIncrement ;
104+ numUpdate ++ ;
98105 }
99106
100107 // TODO: Do this in afterEpochTransitionCache, looping a Uint8Array should be very cheap
@@ -105,4 +112,5 @@ export function processEffectiveBalanceUpdates(
105112 }
106113
107114 cache . nextEpochTotalActiveBalanceByIncrement = nextEpochTotalActiveBalanceByIncrement ;
115+ return numUpdate ;
108116}
0 commit comments