@@ -26,12 +26,12 @@ import {
26
26
computeProposers ,
27
27
getActivationChurnLimit ,
28
28
} from "../util/index.js" ;
29
- import { computeEpochShuffling , EpochShuffling } from "../util/epochShuffling.js" ;
29
+ import { computeEpochShuffling , EpochShuffling , getShufflingDecisionBlock } from "../util/epochShuffling.js" ;
30
30
import { computeBaseRewardPerIncrement , computeSyncParticipantReward } from "../util/syncCommittee.js" ;
31
31
import { sumTargetUnslashedBalanceIncrements } from "../util/targetUnslashedBalance.js" ;
32
32
import { EffectiveBalanceIncrements , getEffectiveBalanceIncrementsWithLen } from "./effectiveBalanceIncrements.js" ;
33
33
import { Index2PubkeyCache , PubkeyIndexMap , syncPubkeys } from "./pubkeyCache.js" ;
34
- import { BeaconStateAllForks , BeaconStateAltair } from "./types.js" ;
34
+ import { BeaconStateAllForks , BeaconStateAltair , ShufflingGetter } from "./types.js" ;
35
35
import {
36
36
computeSyncCommitteeCache ,
37
37
getSyncCommitteeCache ,
@@ -51,6 +51,7 @@ export type EpochCacheImmutableData = {
51
51
export type EpochCacheOpts = {
52
52
skipSyncCommitteeCache ?: boolean ;
53
53
skipSyncPubkeys ?: boolean ;
54
+ shufflingGetter ?: ShufflingGetter ;
54
55
} ;
55
56
56
57
/** Defers computing proposers by persisting only the seed, and dropping it once indexes are computed */
@@ -280,21 +281,32 @@ export class EpochCache {
280
281
const currentActiveIndices : ValidatorIndex [ ] = [ ] ;
281
282
const nextActiveIndices : ValidatorIndex [ ] = [ ] ;
282
283
284
+ // BeaconChain could provide a shuffling cache to avoid re-computing shuffling every epoch
285
+ // in that case, we don't need to compute shufflings again
286
+ const previousShufflingDecisionBlock = getShufflingDecisionBlock ( state , previousEpoch ) ;
287
+ const cachedPreviousShuffling = opts ?. shufflingGetter ?.( previousEpoch , previousShufflingDecisionBlock ) ;
288
+ const currentShufflingDecisionBlock = getShufflingDecisionBlock ( state , currentEpoch ) ;
289
+ const cachedCurrentShuffling = opts ?. shufflingGetter ?.( currentEpoch , currentShufflingDecisionBlock ) ;
290
+ const nextShufflingDecisionBlock = getShufflingDecisionBlock ( state , nextEpoch ) ;
291
+ const cachedNextShuffling = opts ?. shufflingGetter ?.( nextEpoch , nextShufflingDecisionBlock ) ;
292
+
283
293
for ( let i = 0 ; i < validatorCount ; i ++ ) {
284
294
const validator = validators [ i ] ;
285
295
286
296
// Note: Not usable for fork-choice balances since in-active validators are not zero'ed
287
297
effectiveBalanceIncrements [ i ] = Math . floor ( validator . effectiveBalance / EFFECTIVE_BALANCE_INCREMENT ) ;
288
298
289
- if ( isActiveValidator ( validator , previousEpoch ) ) {
299
+ // we only need to track active indices for previous, current and next epoch if we have to compute shufflings
300
+ // skip doing that if we already have cached shufflings
301
+ if ( cachedPreviousShuffling == null && isActiveValidator ( validator , previousEpoch ) ) {
290
302
previousActiveIndices . push ( i ) ;
291
303
}
292
- if ( isActiveValidator ( validator , currentEpoch ) ) {
304
+ if ( cachedCurrentShuffling == null && isActiveValidator ( validator , currentEpoch ) ) {
293
305
currentActiveIndices . push ( i ) ;
294
306
// We track totalActiveBalanceIncrements as ETH to fit total network balance in a JS number (53 bits)
295
307
totalActiveBalanceIncrements += effectiveBalanceIncrements [ i ] ;
296
308
}
297
- if ( isActiveValidator ( validator , nextEpoch ) ) {
309
+ if ( cachedNextShuffling == null && isActiveValidator ( validator , nextEpoch ) ) {
298
310
nextActiveIndices . push ( i ) ;
299
311
}
300
312
@@ -317,11 +329,11 @@ export class EpochCache {
317
329
throw Error ( "totalActiveBalanceIncrements >= Number.MAX_SAFE_INTEGER. MAX_EFFECTIVE_BALANCE is too low." ) ;
318
330
}
319
331
320
- const currentShuffling = computeEpochShuffling ( state , currentActiveIndices , currentEpoch ) ;
321
- const previousShuffling = isGenesis
322
- ? currentShuffling
323
- : computeEpochShuffling ( state , previousActiveIndices , previousEpoch ) ;
324
- const nextShuffling = computeEpochShuffling ( state , nextActiveIndices , nextEpoch ) ;
332
+ const currentShuffling = cachedCurrentShuffling ?? computeEpochShuffling ( state , currentActiveIndices , currentEpoch ) ;
333
+ const previousShuffling =
334
+ cachedPreviousShuffling ??
335
+ ( isGenesis ? currentShuffling : computeEpochShuffling ( state , previousActiveIndices , previousEpoch ) ) ;
336
+ const nextShuffling = cachedNextShuffling ?? computeEpochShuffling ( state , nextActiveIndices , nextEpoch ) ;
325
337
326
338
const currentProposerSeed = getSeed ( state , currentEpoch , DOMAIN_BEACON_PROPOSER ) ;
327
339
0 commit comments