@lodestar/state-transition 1.39.0-dev.aceb5b7416 → 1.39.0-dev.ad129ced66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/block/index.d.ts.map +1 -1
- package/lib/block/index.js +4 -2
- package/lib/block/index.js.map +1 -1
- package/lib/block/isValidIndexedAttestation.d.ts +5 -5
- package/lib/block/isValidIndexedAttestation.d.ts.map +1 -1
- package/lib/block/isValidIndexedAttestation.js +9 -10
- package/lib/block/isValidIndexedAttestation.js.map +1 -1
- package/lib/block/processAttestationPhase0.d.ts.map +1 -1
- package/lib/block/processAttestationPhase0.js +1 -1
- package/lib/block/processAttestationPhase0.js.map +1 -1
- package/lib/block/processAttestationsAltair.d.ts.map +1 -1
- package/lib/block/processAttestationsAltair.js +1 -1
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processAttesterSlashing.d.ts +3 -2
- package/lib/block/processAttesterSlashing.d.ts.map +1 -1
- package/lib/block/processAttesterSlashing.js +3 -3
- package/lib/block/processAttesterSlashing.js.map +1 -1
- package/lib/block/processBlsToExecutionChange.d.ts +3 -1
- package/lib/block/processBlsToExecutionChange.d.ts.map +1 -1
- package/lib/block/processBlsToExecutionChange.js +7 -11
- package/lib/block/processBlsToExecutionChange.js.map +1 -1
- package/lib/block/processExecutionPayload.d.ts.map +1 -1
- package/lib/block/processExecutionPayload.js +6 -4
- package/lib/block/processExecutionPayload.js.map +1 -1
- package/lib/block/processProposerSlashing.d.ts +5 -2
- package/lib/block/processProposerSlashing.d.ts.map +1 -1
- package/lib/block/processProposerSlashing.js +7 -5
- package/lib/block/processProposerSlashing.js.map +1 -1
- package/lib/block/processRandao.js +2 -2
- package/lib/block/processRandao.js.map +1 -1
- package/lib/block/processSyncCommittee.d.ts +3 -1
- package/lib/block/processSyncCommittee.d.ts.map +1 -1
- package/lib/block/processSyncCommittee.js +6 -4
- package/lib/block/processSyncCommittee.js.map +1 -1
- package/lib/block/processVoluntaryExit.d.ts.map +1 -1
- package/lib/block/processVoluntaryExit.js +2 -1
- package/lib/block/processVoluntaryExit.js.map +1 -1
- package/lib/block/processWithdrawals.d.ts +3 -3
- package/lib/block/processWithdrawals.d.ts.map +1 -1
- package/lib/block/processWithdrawals.js +152 -105
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/cache/epochCache.d.ts +6 -12
- package/lib/cache/epochCache.d.ts.map +1 -1
- package/lib/cache/epochCache.js +33 -105
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/cache/epochTransitionCache.d.ts +5 -12
- package/lib/cache/epochTransitionCache.d.ts.map +1 -1
- package/lib/cache/epochTransitionCache.js +4 -14
- package/lib/cache/epochTransitionCache.js.map +1 -1
- package/lib/cache/stateCache.d.ts +1 -0
- package/lib/cache/stateCache.d.ts.map +1 -1
- package/lib/cache/stateCache.js +1 -2
- package/lib/cache/stateCache.js.map +1 -1
- package/lib/epoch/processProposerLookahead.d.ts.map +1 -1
- package/lib/epoch/processProposerLookahead.js +3 -6
- package/lib/epoch/processProposerLookahead.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/rewards/attestationsRewards.d.ts +6 -0
- package/lib/rewards/attestationsRewards.d.ts.map +1 -0
- package/lib/rewards/attestationsRewards.js +113 -0
- package/lib/rewards/attestationsRewards.js.map +1 -0
- package/lib/rewards/blockRewards.d.ts +14 -0
- package/lib/rewards/blockRewards.d.ts.map +1 -0
- package/lib/rewards/blockRewards.js +96 -0
- package/lib/rewards/blockRewards.js.map +1 -0
- package/lib/rewards/index.d.ts +4 -0
- package/lib/rewards/index.d.ts.map +1 -0
- package/lib/rewards/index.js +4 -0
- package/lib/rewards/index.js.map +1 -0
- package/lib/rewards/syncCommitteeRewards.d.ts +6 -0
- package/lib/rewards/syncCommitteeRewards.d.ts.map +1 -0
- package/lib/rewards/syncCommitteeRewards.js +35 -0
- package/lib/rewards/syncCommitteeRewards.js.map +1 -0
- package/lib/signatureSets/attesterSlashings.d.ts +5 -5
- package/lib/signatureSets/attesterSlashings.d.ts.map +1 -1
- package/lib/signatureSets/attesterSlashings.js +10 -7
- package/lib/signatureSets/attesterSlashings.js.map +1 -1
- package/lib/signatureSets/blsToExecutionChange.d.ts +1 -2
- package/lib/signatureSets/blsToExecutionChange.d.ts.map +1 -1
- package/lib/signatureSets/blsToExecutionChange.js +2 -2
- package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
- package/lib/signatureSets/index.d.ts +3 -2
- package/lib/signatureSets/index.d.ts.map +1 -1
- package/lib/signatureSets/index.js +10 -10
- package/lib/signatureSets/index.js.map +1 -1
- package/lib/signatureSets/indexedAttestation.d.ts +6 -6
- package/lib/signatureSets/indexedAttestation.d.ts.map +1 -1
- package/lib/signatureSets/indexedAttestation.js +12 -9
- package/lib/signatureSets/indexedAttestation.js.map +1 -1
- package/lib/signatureSets/proposer.d.ts +6 -6
- package/lib/signatureSets/proposer.d.ts.map +1 -1
- package/lib/signatureSets/proposer.js +12 -11
- package/lib/signatureSets/proposer.js.map +1 -1
- package/lib/signatureSets/proposerSlashings.d.ts +4 -4
- package/lib/signatureSets/proposerSlashings.d.ts.map +1 -1
- package/lib/signatureSets/proposerSlashings.js +7 -4
- package/lib/signatureSets/proposerSlashings.js.map +1 -1
- package/lib/signatureSets/randao.d.ts +3 -3
- package/lib/signatureSets/randao.d.ts.map +1 -1
- package/lib/signatureSets/randao.js +6 -4
- package/lib/signatureSets/randao.js.map +1 -1
- package/lib/signatureSets/voluntaryExits.d.ts +5 -5
- package/lib/signatureSets/voluntaryExits.d.ts.map +1 -1
- package/lib/signatureSets/voluntaryExits.js +10 -7
- package/lib/signatureSets/voluntaryExits.js.map +1 -1
- package/lib/stateTransition.js +1 -1
- package/lib/stateTransition.js.map +1 -1
- package/lib/types.d.ts +1 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/util/epochShuffling.d.ts +1 -34
- package/lib/util/epochShuffling.d.ts.map +1 -1
- package/lib/util/epochShuffling.js +1 -1
- package/lib/util/epochShuffling.js.map +1 -1
- package/lib/util/execution.d.ts +11 -1
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +26 -1
- package/lib/util/execution.js.map +1 -1
- package/package.json +14 -11
- package/src/block/index.ts +6 -2
- package/src/block/isValidIndexedAttestation.ts +22 -12
- package/src/block/processAttestationPhase0.ts +3 -1
- package/src/block/processAttestationsAltair.ts +7 -1
- package/src/block/processAttesterSlashing.ts +16 -4
- package/src/block/processBlsToExecutionChange.ts +13 -14
- package/src/block/processExecutionPayload.ts +14 -8
- package/src/block/processProposerSlashing.ts +21 -6
- package/src/block/processRandao.ts +2 -2
- package/src/block/processSyncCommittee.ts +15 -4
- package/src/block/processVoluntaryExit.ts +4 -1
- package/src/block/processWithdrawals.ts +230 -135
- package/src/cache/epochCache.ts +40 -118
- package/src/cache/epochTransitionCache.ts +9 -34
- package/src/cache/stateCache.ts +2 -2
- package/src/epoch/processProposerLookahead.ts +3 -7
- package/src/index.ts +2 -2
- package/src/rewards/attestationsRewards.ts +200 -0
- package/src/rewards/blockRewards.ts +150 -0
- package/src/rewards/index.ts +3 -0
- package/src/rewards/syncCommitteeRewards.ts +56 -0
- package/src/signatureSets/attesterSlashings.ts +14 -9
- package/src/signatureSets/blsToExecutionChange.ts +2 -3
- package/src/signatureSets/index.ts +14 -11
- package/src/signatureSets/indexedAttestation.ts +18 -11
- package/src/signatureSets/proposer.ts +14 -12
- package/src/signatureSets/proposerSlashings.ts +10 -10
- package/src/signatureSets/randao.ts +7 -5
- package/src/signatureSets/voluntaryExits.ts +14 -9
- package/src/stateTransition.ts +1 -1
- package/src/types.ts +1 -0
- package/src/util/epochShuffling.ts +2 -43
- package/src/util/execution.ts +39 -0
package/src/cache/epochCache.ts
CHANGED
|
@@ -32,7 +32,7 @@ import {getTotalSlashingsByIncrement} from "../epoch/processSlashings.js";
|
|
|
32
32
|
import {AttesterDuty, calculateCommitteeAssignments} from "../util/calculateCommitteeAssignments.js";
|
|
33
33
|
import {
|
|
34
34
|
EpochShuffling,
|
|
35
|
-
|
|
35
|
+
calculateDecisionRoot,
|
|
36
36
|
calculateShufflingDecisionRoot,
|
|
37
37
|
computeEpochShuffling,
|
|
38
38
|
} from "../util/epochShuffling.js";
|
|
@@ -61,7 +61,7 @@ import {
|
|
|
61
61
|
computeSyncCommitteeCache,
|
|
62
62
|
getSyncCommitteeCache,
|
|
63
63
|
} from "./syncCommitteeCache.js";
|
|
64
|
-
import {BeaconStateAllForks, BeaconStateAltair, BeaconStateGloas} from "./types.js";
|
|
64
|
+
import {BeaconStateAllForks, BeaconStateAltair, BeaconStateGloas, ShufflingGetter} from "./types.js";
|
|
65
65
|
|
|
66
66
|
/** `= PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT)` */
|
|
67
67
|
export const PROPOSER_WEIGHT_FACTOR = PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT);
|
|
@@ -70,12 +70,12 @@ export type EpochCacheImmutableData = {
|
|
|
70
70
|
config: BeaconConfig;
|
|
71
71
|
pubkey2index: PubkeyIndexMap;
|
|
72
72
|
index2pubkey: Index2PubkeyCache;
|
|
73
|
-
shufflingCache?: IShufflingCache;
|
|
74
73
|
};
|
|
75
74
|
|
|
76
75
|
export type EpochCacheOpts = {
|
|
77
76
|
skipSyncCommitteeCache?: boolean;
|
|
78
77
|
skipSyncPubkeys?: boolean;
|
|
78
|
+
shufflingGetter?: ShufflingGetter;
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
/** Defers computing proposers by persisting only the seed, and dropping it once indexes are computed */
|
|
@@ -117,12 +117,6 @@ export class EpochCache {
|
|
|
117
117
|
* $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates)
|
|
118
118
|
*/
|
|
119
119
|
index2pubkey: Index2PubkeyCache;
|
|
120
|
-
/**
|
|
121
|
-
* ShufflingCache is passed in from `beacon-node` so should be available at runtime but may not be
|
|
122
|
-
* present during testing.
|
|
123
|
-
*/
|
|
124
|
-
shufflingCache?: IShufflingCache;
|
|
125
|
-
|
|
126
120
|
/**
|
|
127
121
|
* Indexes of the block proposers for the current epoch.
|
|
128
122
|
* For pre-fulu, this is computed and cached from the current shuffling.
|
|
@@ -161,7 +155,7 @@ export class EpochCache {
|
|
|
161
155
|
/** Same as previousShuffling */
|
|
162
156
|
currentShuffling: EpochShuffling;
|
|
163
157
|
/** Same as previousShuffling */
|
|
164
|
-
nextShuffling: EpochShuffling
|
|
158
|
+
nextShuffling: EpochShuffling;
|
|
165
159
|
/**
|
|
166
160
|
* Cache nextActiveIndices so that in afterProcessEpoch the next shuffling can be build synchronously
|
|
167
161
|
* in case it is not built or the ShufflingCache is not available
|
|
@@ -254,7 +248,6 @@ export class EpochCache {
|
|
|
254
248
|
config: BeaconConfig;
|
|
255
249
|
pubkey2index: PubkeyIndexMap;
|
|
256
250
|
index2pubkey: Index2PubkeyCache;
|
|
257
|
-
shufflingCache?: IShufflingCache;
|
|
258
251
|
proposers: number[];
|
|
259
252
|
proposersPrevEpoch: number[] | null;
|
|
260
253
|
proposersNextEpoch: ProposersDeferred;
|
|
@@ -263,7 +256,7 @@ export class EpochCache {
|
|
|
263
256
|
nextDecisionRoot: RootHex;
|
|
264
257
|
previousShuffling: EpochShuffling;
|
|
265
258
|
currentShuffling: EpochShuffling;
|
|
266
|
-
nextShuffling: EpochShuffling
|
|
259
|
+
nextShuffling: EpochShuffling;
|
|
267
260
|
nextActiveIndices: Uint32Array;
|
|
268
261
|
effectiveBalanceIncrements: EffectiveBalanceIncrements;
|
|
269
262
|
totalSlashingsByIncrement: number;
|
|
@@ -286,7 +279,6 @@ export class EpochCache {
|
|
|
286
279
|
this.config = data.config;
|
|
287
280
|
this.pubkey2index = data.pubkey2index;
|
|
288
281
|
this.index2pubkey = data.index2pubkey;
|
|
289
|
-
this.shufflingCache = data.shufflingCache;
|
|
290
282
|
this.proposers = data.proposers;
|
|
291
283
|
this.proposersPrevEpoch = data.proposersPrevEpoch;
|
|
292
284
|
this.proposersNextEpoch = data.proposersNextEpoch;
|
|
@@ -324,7 +316,7 @@ export class EpochCache {
|
|
|
324
316
|
*/
|
|
325
317
|
static createFromState(
|
|
326
318
|
state: BeaconStateAllForks,
|
|
327
|
-
{config, pubkey2index, index2pubkey
|
|
319
|
+
{config, pubkey2index, index2pubkey}: EpochCacheImmutableData,
|
|
328
320
|
opts?: EpochCacheOpts
|
|
329
321
|
): EpochCache {
|
|
330
322
|
const currentEpoch = computeEpochAtSlot(state.slot);
|
|
@@ -351,14 +343,15 @@ export class EpochCache {
|
|
|
351
343
|
const currentActiveIndicesAsNumberArray: ValidatorIndex[] = [];
|
|
352
344
|
const nextActiveIndicesAsNumberArray: ValidatorIndex[] = [];
|
|
353
345
|
|
|
354
|
-
// BeaconChain could provide a shuffling
|
|
346
|
+
// BeaconChain could provide a shuffling getter to avoid re-computing shuffling every epoch
|
|
355
347
|
// in that case, we don't need to compute shufflings again
|
|
348
|
+
const shufflingGetter = opts?.shufflingGetter;
|
|
356
349
|
const previousDecisionRoot = calculateShufflingDecisionRoot(config, state, previousEpoch);
|
|
357
|
-
const cachedPreviousShuffling =
|
|
350
|
+
const cachedPreviousShuffling = shufflingGetter?.(previousEpoch, previousDecisionRoot);
|
|
358
351
|
const currentDecisionRoot = calculateShufflingDecisionRoot(config, state, currentEpoch);
|
|
359
|
-
const cachedCurrentShuffling =
|
|
352
|
+
const cachedCurrentShuffling = shufflingGetter?.(currentEpoch, currentDecisionRoot);
|
|
360
353
|
const nextDecisionRoot = calculateShufflingDecisionRoot(config, state, nextEpoch);
|
|
361
|
-
const cachedNextShuffling =
|
|
354
|
+
const cachedNextShuffling = shufflingGetter?.(nextEpoch, nextDecisionRoot);
|
|
362
355
|
|
|
363
356
|
for (let i = 0; i < validatorCount; i++) {
|
|
364
357
|
const validator = validators[i];
|
|
@@ -366,8 +359,7 @@ export class EpochCache {
|
|
|
366
359
|
// Note: Not usable for fork-choice balances since in-active validators are not zero'ed
|
|
367
360
|
effectiveBalanceIncrements[i] = Math.floor(validator.effectiveBalance / EFFECTIVE_BALANCE_INCREMENT);
|
|
368
361
|
|
|
369
|
-
//
|
|
370
|
-
// skip doing that if we already have cached shufflings
|
|
362
|
+
// Collect active indices for each epoch to compute shufflings
|
|
371
363
|
if (cachedPreviousShuffling == null && isActiveValidator(validator, previousEpoch)) {
|
|
372
364
|
previousActiveIndicesAsNumberArray.push(i);
|
|
373
365
|
}
|
|
@@ -402,47 +394,19 @@ export class EpochCache {
|
|
|
402
394
|
}
|
|
403
395
|
|
|
404
396
|
const nextActiveIndices = new Uint32Array(nextActiveIndicesAsNumberArray);
|
|
405
|
-
let previousShuffling: EpochShuffling;
|
|
406
|
-
let currentShuffling: EpochShuffling;
|
|
407
|
-
let nextShuffling: EpochShuffling;
|
|
408
|
-
|
|
409
|
-
if (!shufflingCache) {
|
|
410
|
-
// Only for testing. shufflingCache should always be available in prod
|
|
411
|
-
previousShuffling = computeEpochShuffling(
|
|
412
|
-
state,
|
|
413
|
-
new Uint32Array(previousActiveIndicesAsNumberArray),
|
|
414
|
-
previousEpoch
|
|
415
|
-
);
|
|
416
397
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
398
|
+
// Use cached shufflings if available, otherwise compute
|
|
399
|
+
const currentShuffling =
|
|
400
|
+
cachedCurrentShuffling ??
|
|
401
|
+
computeEpochShuffling(state, new Uint32Array(currentActiveIndicesAsNumberArray), currentEpoch);
|
|
420
402
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
?
|
|
425
|
-
:
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
previousShuffling = cachedPreviousShuffling
|
|
431
|
-
? cachedPreviousShuffling
|
|
432
|
-
: isGenesis
|
|
433
|
-
? currentShuffling
|
|
434
|
-
: shufflingCache.getSync(previousEpoch, previousDecisionRoot, {
|
|
435
|
-
state,
|
|
436
|
-
activeIndices: new Uint32Array(previousActiveIndicesAsNumberArray),
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
nextShuffling = cachedNextShuffling
|
|
440
|
-
? cachedNextShuffling
|
|
441
|
-
: shufflingCache.getSync(nextEpoch, nextDecisionRoot, {
|
|
442
|
-
state,
|
|
443
|
-
activeIndices: nextActiveIndices,
|
|
444
|
-
});
|
|
445
|
-
}
|
|
403
|
+
const previousShuffling =
|
|
404
|
+
cachedPreviousShuffling ??
|
|
405
|
+
(isGenesis
|
|
406
|
+
? currentShuffling
|
|
407
|
+
: computeEpochShuffling(state, new Uint32Array(previousActiveIndicesAsNumberArray), previousEpoch));
|
|
408
|
+
|
|
409
|
+
const nextShuffling = cachedNextShuffling ?? computeEpochShuffling(state, nextActiveIndices, nextEpoch);
|
|
446
410
|
|
|
447
411
|
const currentProposerSeed = getSeed(state, currentEpoch, DOMAIN_BEACON_PROPOSER);
|
|
448
412
|
|
|
@@ -549,7 +513,6 @@ export class EpochCache {
|
|
|
549
513
|
config,
|
|
550
514
|
pubkey2index,
|
|
551
515
|
index2pubkey,
|
|
552
|
-
shufflingCache,
|
|
553
516
|
proposers,
|
|
554
517
|
// On first epoch, set to null to prevent unnecessary work since this is only used for metrics
|
|
555
518
|
proposersPrevEpoch: null,
|
|
@@ -593,7 +556,6 @@ export class EpochCache {
|
|
|
593
556
|
// Common append-only structures shared with all states, no need to clone
|
|
594
557
|
pubkey2index: this.pubkey2index,
|
|
595
558
|
index2pubkey: this.index2pubkey,
|
|
596
|
-
shufflingCache: this.shufflingCache,
|
|
597
559
|
// Immutable data
|
|
598
560
|
proposers: this.proposers,
|
|
599
561
|
proposersPrevEpoch: this.proposersPrevEpoch,
|
|
@@ -652,62 +614,26 @@ export class EpochCache {
|
|
|
652
614
|
this.previousShuffling = this.currentShuffling;
|
|
653
615
|
this.previousDecisionRoot = this.currentDecisionRoot;
|
|
654
616
|
|
|
655
|
-
// move next to current
|
|
617
|
+
// move next to current
|
|
656
618
|
this.currentDecisionRoot = this.nextDecisionRoot;
|
|
657
|
-
|
|
658
|
-
// was already pulled from the ShufflingCache to the EpochCache (should be in most cases)
|
|
659
|
-
this.currentShuffling = this.nextShuffling;
|
|
660
|
-
} else {
|
|
661
|
-
this.shufflingCache?.metrics?.shufflingCache.nextShufflingNotOnEpochCache.inc();
|
|
662
|
-
this.currentShuffling =
|
|
663
|
-
this.shufflingCache?.getSync(upcomingEpoch, this.currentDecisionRoot, {
|
|
664
|
-
state,
|
|
665
|
-
// have to use the "nextActiveIndices" that were saved in the last transition here to calculate
|
|
666
|
-
// the upcoming shuffling if it is not already built (similar condition to the below computation)
|
|
667
|
-
activeIndices: this.nextActiveIndices,
|
|
668
|
-
}) ??
|
|
669
|
-
// allow for this case during testing where the ShufflingCache is not present, may affect perf testing
|
|
670
|
-
// so should be taken into account when structuring tests. Should not affect unit or other tests though
|
|
671
|
-
computeEpochShuffling(state, this.nextActiveIndices, upcomingEpoch);
|
|
672
|
-
}
|
|
619
|
+
this.currentShuffling = this.nextShuffling;
|
|
673
620
|
|
|
674
|
-
//
|
|
675
|
-
|
|
621
|
+
// Compute shuffling for epoch n+2
|
|
622
|
+
//
|
|
623
|
+
// Post-Fulu (EIP-7917), the beacon state includes a `proposer_lookahead` field that stores
|
|
624
|
+
// proposer indices for MIN_SEED_LOOKAHEAD + 1 epochs ahead (2 epochs with MIN_SEED_LOOKAHEAD=1).
|
|
625
|
+
// At each epoch boundary, processProposerLookahead() shifts out the current epoch's proposers
|
|
626
|
+
// and appends new proposers for epoch n + MIN_SEED_LOOKAHEAD + 1 (i.e., epoch n+2).
|
|
627
|
+
//
|
|
628
|
+
// processProposerLookahead() already computes the n+2 shuffling and stores it in
|
|
629
|
+
// epochTransitionCache.nextShuffling. Reuse it here to avoid duplicate computation.
|
|
630
|
+
// Pre-Fulu, we need to compute it here since processProposerLookahead doesn't run.
|
|
631
|
+
//
|
|
632
|
+
// See: https://eips.ethereum.org/EIPS/eip-7917
|
|
633
|
+
this.nextDecisionRoot = calculateDecisionRoot(state, epochAfterUpcoming);
|
|
676
634
|
this.nextActiveIndices = epochTransitionCache.nextShufflingActiveIndices;
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
this.nextShuffling = this.shufflingCache.getSync(epochAfterUpcoming, this.nextDecisionRoot, {
|
|
680
|
-
state,
|
|
681
|
-
activeIndices: this.nextActiveIndices,
|
|
682
|
-
});
|
|
683
|
-
} else {
|
|
684
|
-
this.nextShuffling = null;
|
|
685
|
-
// This promise will resolve immediately after the synchronous code of the state-transition runs. Until
|
|
686
|
-
// the build is done on a worker thread it will be calculated immediately after the epoch transition
|
|
687
|
-
// completes. Once the work is done concurrently it should be ready by time this get runs so the promise
|
|
688
|
-
// will resolve directly on the next spin of the event loop because the epoch transition and shuffling take
|
|
689
|
-
// about the same time to calculate so theoretically its ready now. Do not await here though in case it
|
|
690
|
-
// is not ready yet as the transition must not be asynchronous.
|
|
691
|
-
this.shufflingCache
|
|
692
|
-
.get(epochAfterUpcoming, this.nextDecisionRoot)
|
|
693
|
-
.then((shuffling) => {
|
|
694
|
-
if (!shuffling) {
|
|
695
|
-
throw new Error("EpochShuffling not returned from get in afterProcessEpoch");
|
|
696
|
-
}
|
|
697
|
-
this.nextShuffling = shuffling;
|
|
698
|
-
})
|
|
699
|
-
.catch((err) => {
|
|
700
|
-
this.shufflingCache?.logger?.error(
|
|
701
|
-
"EPOCH_CONTEXT_SHUFFLING_BUILD_ERROR",
|
|
702
|
-
{epoch: epochAfterUpcoming, decisionRoot: epochTransitionCache.nextShufflingDecisionRoot},
|
|
703
|
-
err
|
|
704
|
-
);
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
} else {
|
|
708
|
-
// Only for testing. shufflingCache should always be available in prod
|
|
709
|
-
this.nextShuffling = computeEpochShuffling(state, this.nextActiveIndices, epochAfterUpcoming);
|
|
710
|
-
}
|
|
635
|
+
this.nextShuffling =
|
|
636
|
+
epochTransitionCache.nextShuffling ?? computeEpochShuffling(state, this.nextActiveIndices, epochAfterUpcoming);
|
|
711
637
|
|
|
712
638
|
// TODO: DEDUPLICATE from createEpochCache
|
|
713
639
|
//
|
|
@@ -1100,10 +1026,6 @@ export class EpochCache {
|
|
|
1100
1026
|
case this.epoch:
|
|
1101
1027
|
return this.currentShuffling;
|
|
1102
1028
|
case this.nextEpoch:
|
|
1103
|
-
if (!this.nextShuffling) {
|
|
1104
|
-
this.nextShuffling =
|
|
1105
|
-
this.shufflingCache?.getSync(this.nextEpoch, this.getShufflingDecisionRoot(this.nextEpoch)) ?? null;
|
|
1106
|
-
}
|
|
1107
1029
|
return this.nextShuffling;
|
|
1108
1030
|
default:
|
|
1109
1031
|
return null;
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
ForkSeq,
|
|
5
|
-
MIN_ACTIVATION_BALANCE,
|
|
6
|
-
SLOTS_PER_HISTORICAL_ROOT,
|
|
7
|
-
} from "@lodestar/params";
|
|
8
|
-
import {Epoch, RootHex, ValidatorIndex} from "@lodestar/types";
|
|
9
|
-
import {intDiv, toRootHex} from "@lodestar/utils";
|
|
1
|
+
import {EPOCHS_PER_SLASHINGS_VECTOR, FAR_FUTURE_EPOCH, ForkSeq, MIN_ACTIVATION_BALANCE} from "@lodestar/params";
|
|
2
|
+
import {Epoch, ValidatorIndex} from "@lodestar/types";
|
|
3
|
+
import {intDiv} from "@lodestar/utils";
|
|
10
4
|
import {processPendingAttestations} from "../epoch/processPendingAttestations.js";
|
|
11
5
|
import {
|
|
12
6
|
CachedBeaconStateAllForks,
|
|
@@ -26,16 +20,13 @@ import {
|
|
|
26
20
|
FLAG_UNSLASHED,
|
|
27
21
|
hasMarkers,
|
|
28
22
|
} from "../util/attesterStatus.js";
|
|
23
|
+
import {EpochShuffling} from "../util/epochShuffling.js";
|
|
29
24
|
|
|
30
25
|
export type EpochTransitionCacheOpts = {
|
|
31
26
|
/**
|
|
32
27
|
* Assert progressive balances the same to EpochTransitionCache
|
|
33
28
|
*/
|
|
34
29
|
assertCorrectProgressiveBalances?: boolean;
|
|
35
|
-
/**
|
|
36
|
-
* Do not queue shuffling calculation async. Forces sync JIT calculation in afterProcessEpoch
|
|
37
|
-
*/
|
|
38
|
-
asyncShufflingCalculation?: boolean;
|
|
39
30
|
};
|
|
40
31
|
|
|
41
32
|
/**
|
|
@@ -162,9 +153,10 @@ export interface EpochTransitionCache {
|
|
|
162
153
|
nextShufflingActiveIndices: Uint32Array;
|
|
163
154
|
|
|
164
155
|
/**
|
|
165
|
-
*
|
|
156
|
+
* Pre-computed shuffling for epoch N+2, populated by processProposerLookahead (Fulu+).
|
|
157
|
+
* Used by afterProcessEpoch to avoid recomputing the same shuffling.
|
|
166
158
|
*/
|
|
167
|
-
|
|
159
|
+
nextShuffling: EpochShuffling | null;
|
|
168
160
|
|
|
169
161
|
/**
|
|
170
162
|
* Altair specific, this is total active balances for the next epoch.
|
|
@@ -179,12 +171,6 @@ export interface EpochTransitionCache {
|
|
|
179
171
|
*/
|
|
180
172
|
nextEpochTotalActiveBalanceByIncrement: number;
|
|
181
173
|
|
|
182
|
-
/**
|
|
183
|
-
* Compute the shuffling sync or async. Defaults to synchronous. Need to pass `true` with the
|
|
184
|
-
* `EpochTransitionCacheOpts`
|
|
185
|
-
*/
|
|
186
|
-
asyncShufflingCalculation: boolean;
|
|
187
|
-
|
|
188
174
|
/**
|
|
189
175
|
* Track by validator index if it's active in the prev epoch.
|
|
190
176
|
* Used in metrics
|
|
@@ -379,12 +365,7 @@ export function beforeProcessEpoch(
|
|
|
379
365
|
}
|
|
380
366
|
});
|
|
381
367
|
|
|
382
|
-
//
|
|
383
|
-
const epochAfterNext = state.epochCtx.nextEpoch + 1;
|
|
384
|
-
// cannot call calculateShufflingDecisionRoot here because spec prevent getting current slot
|
|
385
|
-
// as a decision block. we are part way through the transition though and this was added in
|
|
386
|
-
// process slot beforeProcessEpoch happens so it available and valid
|
|
387
|
-
const nextShufflingDecisionRoot = toRootHex(state.blockRoots.get(state.slot % SLOTS_PER_HISTORICAL_ROOT));
|
|
368
|
+
// Prepare shuffling data for epoch after next (nextShuffling post epoch transition)
|
|
388
369
|
const nextShufflingActiveIndices = new Uint32Array(nextEpochShufflingActiveIndicesLength);
|
|
389
370
|
if (nextEpochShufflingActiveIndicesLength > nextEpochShufflingActiveValidatorIndices.length) {
|
|
390
371
|
throw new Error(
|
|
@@ -396,11 +377,6 @@ export function beforeProcessEpoch(
|
|
|
396
377
|
nextShufflingActiveIndices[i] = nextEpochShufflingActiveValidatorIndices[i];
|
|
397
378
|
}
|
|
398
379
|
|
|
399
|
-
const asyncShufflingCalculation = opts?.asyncShufflingCalculation ?? false;
|
|
400
|
-
if (asyncShufflingCalculation) {
|
|
401
|
-
state.epochCtx.shufflingCache?.build(epochAfterNext, nextShufflingDecisionRoot, state, nextShufflingActiveIndices);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
380
|
if (totalActiveStakeByIncrement < 1) {
|
|
405
381
|
totalActiveStakeByIncrement = 1;
|
|
406
382
|
} else if (totalActiveStakeByIncrement >= Number.MAX_SAFE_INTEGER) {
|
|
@@ -524,9 +500,8 @@ export function beforeProcessEpoch(
|
|
|
524
500
|
indicesEligibleForActivationQueue,
|
|
525
501
|
indicesEligibleForActivation: indicesEligibleForActivation.map(({validatorIndex}) => validatorIndex),
|
|
526
502
|
indicesToEject,
|
|
527
|
-
nextShufflingDecisionRoot,
|
|
528
503
|
nextShufflingActiveIndices,
|
|
529
|
-
|
|
504
|
+
nextShuffling: null,
|
|
530
505
|
// to be updated in processEffectiveBalanceUpdates
|
|
531
506
|
nextEpochTotalActiveBalanceByIncrement: 0,
|
|
532
507
|
isActivePrevEpoch,
|
package/src/cache/stateCache.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from "./types.js";
|
|
18
18
|
|
|
19
19
|
export type BeaconStateCache = {
|
|
20
|
+
/** @deprecated should not access config outside of state-transition package */
|
|
20
21
|
config: BeaconConfig;
|
|
21
22
|
epochCtx: EpochCache;
|
|
22
23
|
/** Count of clones created from this BeaconStateCache instance. readonly to prevent accidental usage downstream */
|
|
@@ -179,7 +180,7 @@ export function loadCachedBeaconState<T extends BeaconStateAllForks & BeaconStat
|
|
|
179
180
|
stateBytes,
|
|
180
181
|
seedValidatorsBytes
|
|
181
182
|
);
|
|
182
|
-
const {pubkey2index, index2pubkey
|
|
183
|
+
const {pubkey2index, index2pubkey} = cachedSeedState.epochCtx;
|
|
183
184
|
// Get the validators sub tree once for all the loop
|
|
184
185
|
const validators = migratedState.validators;
|
|
185
186
|
for (const validatorIndex of modifiedValidators) {
|
|
@@ -195,7 +196,6 @@ export function loadCachedBeaconState<T extends BeaconStateAllForks & BeaconStat
|
|
|
195
196
|
config: cachedSeedState.config,
|
|
196
197
|
pubkey2index,
|
|
197
198
|
index2pubkey,
|
|
198
|
-
shufflingCache,
|
|
199
199
|
},
|
|
200
200
|
{...(opts ?? {}), ...{skipSyncPubkeys: true}}
|
|
201
201
|
) as T;
|
|
@@ -22,13 +22,9 @@ export function processProposerLookahead(
|
|
|
22
22
|
// Fill in the last epoch with new proposer indices
|
|
23
23
|
const epoch = state.epochCtx.epoch + MIN_SEED_LOOKAHEAD + 1;
|
|
24
24
|
|
|
25
|
-
const shuffling =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
activeIndices: cache.nextShufflingActiveIndices,
|
|
29
|
-
}) ??
|
|
30
|
-
// Only for testing. shufflingCache should always be available in prod
|
|
31
|
-
computeEpochShuffling(state, cache.nextShufflingActiveIndices, epoch);
|
|
25
|
+
const shuffling = computeEpochShuffling(state, cache.nextShufflingActiveIndices, epoch);
|
|
26
|
+
// Save shuffling to cache so afterProcessEpoch can reuse it instead of recomputing
|
|
27
|
+
cache.nextShuffling = shuffling;
|
|
32
28
|
|
|
33
29
|
const lastEpochProposerLookahead = computeProposerIndices(fork, state, shuffling, epoch);
|
|
34
30
|
|
package/src/index.ts
CHANGED
|
@@ -27,8 +27,7 @@ export {
|
|
|
27
27
|
createEmptyEpochCacheImmutableData,
|
|
28
28
|
} from "./cache/epochCache.js";
|
|
29
29
|
export {type EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js";
|
|
30
|
-
|
|
31
|
-
export {type Index2PubkeyCache} from "./cache/pubkeyCache.js";
|
|
30
|
+
export {type Index2PubkeyCache, syncPubkeys} from "./cache/pubkeyCache.js";
|
|
32
31
|
// Main state caches
|
|
33
32
|
export {
|
|
34
33
|
type BeaconStateCache,
|
|
@@ -41,6 +40,7 @@ export {
|
|
|
41
40
|
export * from "./constants/index.js";
|
|
42
41
|
export type {EpochTransitionStep} from "./epoch/index.js";
|
|
43
42
|
export {type BeaconStateTransitionMetrics, getMetrics} from "./metrics.js";
|
|
43
|
+
export * from "./rewards/index.js";
|
|
44
44
|
export * from "./signatureSets/index.js";
|
|
45
45
|
export * from "./stateTransition.js";
|
|
46
46
|
export type {
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map";
|
|
2
|
+
import {BeaconConfig} from "@lodestar/config";
|
|
3
|
+
import {
|
|
4
|
+
EFFECTIVE_BALANCE_INCREMENT,
|
|
5
|
+
ForkName,
|
|
6
|
+
INACTIVITY_PENALTY_QUOTIENT_ALTAIR,
|
|
7
|
+
MAX_EFFECTIVE_BALANCE,
|
|
8
|
+
MAX_EFFECTIVE_BALANCE_ELECTRA,
|
|
9
|
+
PARTICIPATION_FLAG_WEIGHTS,
|
|
10
|
+
TIMELY_HEAD_FLAG_INDEX,
|
|
11
|
+
TIMELY_SOURCE_FLAG_INDEX,
|
|
12
|
+
TIMELY_TARGET_FLAG_INDEX,
|
|
13
|
+
WEIGHT_DENOMINATOR,
|
|
14
|
+
isForkPostElectra,
|
|
15
|
+
} from "@lodestar/params";
|
|
16
|
+
import {ValidatorIndex, rewards} from "@lodestar/types";
|
|
17
|
+
import {fromHex} from "@lodestar/utils";
|
|
18
|
+
import {EpochTransitionCache, beforeProcessEpoch} from "../cache/epochTransitionCache.js";
|
|
19
|
+
import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js";
|
|
20
|
+
import {
|
|
21
|
+
FLAG_ELIGIBLE_ATTESTER,
|
|
22
|
+
FLAG_PREV_HEAD_ATTESTER_UNSLASHED,
|
|
23
|
+
FLAG_PREV_SOURCE_ATTESTER_UNSLASHED,
|
|
24
|
+
FLAG_PREV_TARGET_ATTESTER_UNSLASHED,
|
|
25
|
+
hasMarkers,
|
|
26
|
+
isInInactivityLeak,
|
|
27
|
+
} from "../util/index.js";
|
|
28
|
+
|
|
29
|
+
/** Attestations penalty with respect to effective balance in Gwei */
|
|
30
|
+
type AttestationsPenalty = {target: number; source: number; effectiveBalance: number};
|
|
31
|
+
|
|
32
|
+
const defaultAttestationsReward = {head: 0, target: 0, source: 0, inclusionDelay: 0, inactivity: 0};
|
|
33
|
+
const defaultAttestationsPenalty = {target: 0, source: 0};
|
|
34
|
+
|
|
35
|
+
export async function computeAttestationsRewards(
|
|
36
|
+
config: BeaconConfig,
|
|
37
|
+
pubkey2index: PubkeyIndexMap,
|
|
38
|
+
state: CachedBeaconStateAllForks,
|
|
39
|
+
validatorIds?: (ValidatorIndex | string)[]
|
|
40
|
+
): Promise<rewards.AttestationsRewards> {
|
|
41
|
+
const fork = config.getForkName(state.slot);
|
|
42
|
+
if (fork === ForkName.phase0) {
|
|
43
|
+
throw Error("Unsupported fork. Attestations rewards calculation is not available in phase0");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const stateAltair = state as CachedBeaconStateAltair;
|
|
47
|
+
const transitionCache = beforeProcessEpoch(stateAltair);
|
|
48
|
+
|
|
49
|
+
const [idealRewards, penalties] = computeIdealAttestationsRewardsAndPenaltiesAltair(
|
|
50
|
+
config,
|
|
51
|
+
stateAltair,
|
|
52
|
+
transitionCache
|
|
53
|
+
);
|
|
54
|
+
const totalRewards = computeTotalAttestationsRewardsAltair(
|
|
55
|
+
config,
|
|
56
|
+
pubkey2index,
|
|
57
|
+
stateAltair,
|
|
58
|
+
transitionCache,
|
|
59
|
+
idealRewards,
|
|
60
|
+
penalties,
|
|
61
|
+
validatorIds
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return {idealRewards, totalRewards};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function computeIdealAttestationsRewardsAndPenaltiesAltair(
|
|
68
|
+
config: BeaconConfig,
|
|
69
|
+
state: CachedBeaconStateAllForks,
|
|
70
|
+
transitionCache: EpochTransitionCache
|
|
71
|
+
): [rewards.IdealAttestationsReward[], AttestationsPenalty[]] {
|
|
72
|
+
const baseRewardPerIncrement = transitionCache.baseRewardPerIncrement;
|
|
73
|
+
const activeBalanceByIncrement = transitionCache.totalActiveStakeByIncrement;
|
|
74
|
+
const fork = config.getForkName(state.slot);
|
|
75
|
+
const maxEffectiveBalance = isForkPostElectra(fork) ? MAX_EFFECTIVE_BALANCE_ELECTRA : MAX_EFFECTIVE_BALANCE;
|
|
76
|
+
const maxEffectiveBalanceByIncrement = Math.floor(maxEffectiveBalance / EFFECTIVE_BALANCE_INCREMENT);
|
|
77
|
+
|
|
78
|
+
const idealRewards = Array.from({length: maxEffectiveBalanceByIncrement + 1}, (_, effectiveBalanceByIncrement) => ({
|
|
79
|
+
...defaultAttestationsReward,
|
|
80
|
+
effectiveBalance: effectiveBalanceByIncrement * EFFECTIVE_BALANCE_INCREMENT,
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
const attestationsPenalties: AttestationsPenalty[] = Array.from(
|
|
84
|
+
{length: maxEffectiveBalanceByIncrement + 1},
|
|
85
|
+
(_, effectiveBalanceByIncrement) => ({
|
|
86
|
+
...defaultAttestationsPenalty,
|
|
87
|
+
effectiveBalance: effectiveBalanceByIncrement * EFFECTIVE_BALANCE_INCREMENT,
|
|
88
|
+
})
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
for (let i = 0; i < PARTICIPATION_FLAG_WEIGHTS.length; i++) {
|
|
92
|
+
const weight = PARTICIPATION_FLAG_WEIGHTS[i];
|
|
93
|
+
|
|
94
|
+
let unslashedStakeByIncrement: number;
|
|
95
|
+
let flagName: keyof rewards.IdealAttestationsReward;
|
|
96
|
+
|
|
97
|
+
switch (i) {
|
|
98
|
+
case TIMELY_SOURCE_FLAG_INDEX: {
|
|
99
|
+
unslashedStakeByIncrement = transitionCache.prevEpochUnslashedStake.sourceStakeByIncrement;
|
|
100
|
+
flagName = "source";
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case TIMELY_TARGET_FLAG_INDEX: {
|
|
104
|
+
unslashedStakeByIncrement = transitionCache.prevEpochUnslashedStake.targetStakeByIncrement;
|
|
105
|
+
flagName = "target";
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case TIMELY_HEAD_FLAG_INDEX: {
|
|
109
|
+
unslashedStakeByIncrement = transitionCache.prevEpochUnslashedStake.headStakeByIncrement;
|
|
110
|
+
flagName = "head";
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
default: {
|
|
114
|
+
throw Error(`Unable to retrieve unslashed stake. Unknown participation flag index: ${i}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for (
|
|
119
|
+
let effectiveBalanceByIncrement = 0;
|
|
120
|
+
effectiveBalanceByIncrement <= maxEffectiveBalanceByIncrement;
|
|
121
|
+
effectiveBalanceByIncrement++
|
|
122
|
+
) {
|
|
123
|
+
const baseReward = effectiveBalanceByIncrement * baseRewardPerIncrement;
|
|
124
|
+
const rewardNumerator = baseReward * weight * unslashedStakeByIncrement;
|
|
125
|
+
// Both idealReward and penalty are rounded to nearest integer. Loss of precision is minimal as unit is gwei
|
|
126
|
+
const idealReward = Math.round(rewardNumerator / activeBalanceByIncrement / WEIGHT_DENOMINATOR);
|
|
127
|
+
const penalty = Math.round((baseReward * weight) / WEIGHT_DENOMINATOR); // Positive number indicates penalty
|
|
128
|
+
|
|
129
|
+
const idealAttestationsReward = idealRewards[effectiveBalanceByIncrement];
|
|
130
|
+
idealAttestationsReward[flagName] = isInInactivityLeak(state) ? 0 : idealReward; // No attestations rewards during inactivity leak
|
|
131
|
+
|
|
132
|
+
if (flagName !== "head") {
|
|
133
|
+
const attestationPenalty = attestationsPenalties[effectiveBalanceByIncrement];
|
|
134
|
+
attestationPenalty[flagName] = penalty;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return [idealRewards, attestationsPenalties];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Same calculation as `getRewardsAndPenaltiesAltair` but returns the breakdown of rewards instead of aggregated
|
|
143
|
+
function computeTotalAttestationsRewardsAltair(
|
|
144
|
+
config: BeaconConfig,
|
|
145
|
+
pubkey2index: PubkeyIndexMap,
|
|
146
|
+
state: CachedBeaconStateAltair,
|
|
147
|
+
transitionCache: EpochTransitionCache,
|
|
148
|
+
idealRewards: rewards.IdealAttestationsReward[],
|
|
149
|
+
penalties: AttestationsPenalty[],
|
|
150
|
+
validatorIds: (ValidatorIndex | string)[] = []
|
|
151
|
+
): rewards.TotalAttestationsReward[] {
|
|
152
|
+
const rewards = [];
|
|
153
|
+
const {flags} = transitionCache;
|
|
154
|
+
const {epochCtx} = state;
|
|
155
|
+
const validatorIndices = validatorIds
|
|
156
|
+
.map((id) => (typeof id === "number" ? id : pubkey2index.get(fromHex(id))))
|
|
157
|
+
.filter((index) => index !== undefined); // Validator indices to include in the result
|
|
158
|
+
|
|
159
|
+
const inactivityPenaltyDenominator = config.INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_ALTAIR;
|
|
160
|
+
|
|
161
|
+
for (let i = 0; i < flags.length; i++) {
|
|
162
|
+
if (validatorIndices.length && !validatorIndices.includes(i)) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const flag = flags[i];
|
|
167
|
+
if (!hasMarkers(flag, FLAG_ELIGIBLE_ATTESTER)) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const effectiveBalanceIncrement = epochCtx.effectiveBalanceIncrements[i];
|
|
172
|
+
|
|
173
|
+
const currentRewards = {...defaultAttestationsReward, validatorIndex: i};
|
|
174
|
+
|
|
175
|
+
if (hasMarkers(flag, FLAG_PREV_SOURCE_ATTESTER_UNSLASHED)) {
|
|
176
|
+
currentRewards.source = idealRewards[effectiveBalanceIncrement].source;
|
|
177
|
+
} else {
|
|
178
|
+
currentRewards.source = penalties[effectiveBalanceIncrement].source * -1; // Negative reward to indicate penalty
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (hasMarkers(flag, FLAG_PREV_TARGET_ATTESTER_UNSLASHED)) {
|
|
182
|
+
currentRewards.target = idealRewards[effectiveBalanceIncrement].target;
|
|
183
|
+
} else {
|
|
184
|
+
currentRewards.target = penalties[effectiveBalanceIncrement].target * -1;
|
|
185
|
+
|
|
186
|
+
// Also incur inactivity penalty if not voting target correctly
|
|
187
|
+
const inactivityPenaltyNumerator =
|
|
188
|
+
effectiveBalanceIncrement * EFFECTIVE_BALANCE_INCREMENT * state.inactivityScores.get(i);
|
|
189
|
+
currentRewards.inactivity = Math.floor(inactivityPenaltyNumerator / inactivityPenaltyDenominator) * -1;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (hasMarkers(flag, FLAG_PREV_HEAD_ATTESTER_UNSLASHED)) {
|
|
193
|
+
currentRewards.head = idealRewards[effectiveBalanceIncrement].head;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
rewards.push(currentRewards);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return rewards;
|
|
200
|
+
}
|