@lodestar/state-transition 1.46.0-dev.d96240a05e → 1.46.0-dev.df02c7532b
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/externalData.js +2 -4
- package/lib/block/externalData.js.map +1 -1
- package/lib/block/index.d.ts.map +1 -1
- package/lib/block/index.js +3 -2
- package/lib/block/index.js.map +1 -1
- package/lib/block/initiateValidatorExit.js.map +1 -1
- package/lib/block/isValidIndexedAttestation.js.map +1 -1
- package/lib/block/isValidIndexedPayloadAttestation.js.map +1 -1
- package/lib/block/processAttestationPhase0.js.map +1 -1
- package/lib/block/processAttestations.d.ts +2 -2
- package/lib/block/processAttestations.d.ts.map +1 -1
- package/lib/block/processAttestations.js +2 -2
- package/lib/block/processAttestations.js.map +1 -1
- package/lib/block/processAttestationsAltair.d.ts +3 -3
- package/lib/block/processAttestationsAltair.d.ts.map +1 -1
- package/lib/block/processAttestationsAltair.js +7 -4
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processAttesterSlashing.js.map +1 -1
- package/lib/block/processBlobKzgCommitments.js.map +1 -1
- package/lib/block/processBlockHeader.js.map +1 -1
- package/lib/block/processBlsToExecutionChange.js.map +1 -1
- package/lib/block/processBuilderDepositRequest.js.map +1 -1
- package/lib/block/processBuilderExitRequest.js.map +1 -1
- package/lib/block/processConsolidationRequest.js.map +1 -1
- package/lib/block/processDeposit.js.map +1 -1
- package/lib/block/processDepositRequest.js.map +1 -1
- package/lib/block/processEth1Data.js.map +1 -1
- package/lib/block/processExecutionPayload.js.map +1 -1
- package/lib/block/processExecutionPayloadBid.d.ts +3 -3
- package/lib/block/processExecutionPayloadBid.d.ts.map +1 -1
- package/lib/block/processExecutionPayloadBid.js +10 -3
- package/lib/block/processExecutionPayloadBid.js.map +1 -1
- package/lib/block/processOperations.d.ts +2 -2
- package/lib/block/processOperations.d.ts.map +1 -1
- package/lib/block/processOperations.js +2 -2
- package/lib/block/processOperations.js.map +1 -1
- package/lib/block/processParentExecutionPayload.js.map +1 -1
- package/lib/block/processPayloadAttestation.js.map +1 -1
- package/lib/block/processProposerSlashing.js.map +1 -1
- package/lib/block/processRandao.js.map +1 -1
- package/lib/block/processSyncCommittee.js.map +1 -1
- package/lib/block/processVoluntaryExit.js +1 -2
- package/lib/block/processVoluntaryExit.js.map +1 -1
- package/lib/block/processWithdrawalRequest.d.ts.map +1 -1
- package/lib/block/processWithdrawalRequest.js +2 -2
- package/lib/block/processWithdrawalRequest.js.map +1 -1
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/block/slashValidator.js.map +1 -1
- package/lib/block/types.js +1 -2
- package/lib/block/types.js.map +1 -1
- package/lib/cache/effectiveBalanceIncrements.js.map +1 -1
- package/lib/cache/epochCache.d.ts.map +1 -1
- package/lib/cache/epochCache.js +19 -21
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/cache/epochTransitionCache.js.map +1 -1
- package/lib/cache/pubkeyCache.js.map +1 -1
- package/lib/cache/rewardCache.js.map +1 -1
- package/lib/cache/stateCache.d.ts +2 -1
- package/lib/cache/stateCache.d.ts.map +1 -1
- package/lib/cache/stateCache.js +3 -2
- package/lib/cache/stateCache.js.map +1 -1
- package/lib/cache/syncCommitteeCache.js.map +1 -1
- package/lib/cache/types.d.ts +1 -0
- package/lib/cache/types.d.ts.map +1 -1
- package/lib/epoch/computeUnrealizedCheckpoints.js.map +1 -1
- package/lib/epoch/getAttestationDeltas.js.map +1 -1
- package/lib/epoch/getRewardsAndPenalties.js.map +1 -1
- package/lib/epoch/index.js +1 -2
- package/lib/epoch/index.js.map +1 -1
- package/lib/epoch/processBuilderPendingPayments.js.map +1 -1
- package/lib/epoch/processEffectiveBalanceUpdates.js.map +1 -1
- package/lib/epoch/processEth1DataReset.js.map +1 -1
- package/lib/epoch/processHistoricalRootsUpdate.js.map +1 -1
- package/lib/epoch/processHistoricalSummariesUpdate.js.map +1 -1
- package/lib/epoch/processInactivityUpdates.js.map +1 -1
- package/lib/epoch/processJustificationAndFinalization.js.map +1 -1
- package/lib/epoch/processParticipationFlagUpdates.js.map +1 -1
- package/lib/epoch/processParticipationRecordUpdates.js.map +1 -1
- package/lib/epoch/processPendingAttestations.js.map +1 -1
- package/lib/epoch/processPendingConsolidations.js.map +1 -1
- package/lib/epoch/processPendingDeposits.js.map +1 -1
- package/lib/epoch/processProposerLookahead.js.map +1 -1
- package/lib/epoch/processPtcWindow.js.map +1 -1
- package/lib/epoch/processRandaoMixesReset.js.map +1 -1
- package/lib/epoch/processRegistryUpdates.js.map +1 -1
- package/lib/epoch/processRewardsAndPenalties.js.map +1 -1
- package/lib/epoch/processSlashings.js.map +1 -1
- package/lib/epoch/processSlashingsReset.js.map +1 -1
- package/lib/epoch/processSyncCommitteeUpdates.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/lightClient/proofs.js.map +1 -1
- package/lib/lightClient/spec/index.js.map +1 -1
- package/lib/lightClient/spec/isBetterUpdate.js.map +1 -1
- package/lib/lightClient/spec/processLightClientUpdate.js.map +1 -1
- package/lib/lightClient/spec/store.js.map +1 -1
- package/lib/lightClient/spec/utils.d.ts +0 -2
- package/lib/lightClient/spec/utils.d.ts.map +1 -1
- package/lib/lightClient/spec/utils.js +8 -2
- package/lib/lightClient/spec/utils.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientBootstrap.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -1
- package/lib/metrics.d.ts.map +1 -1
- package/lib/metrics.js +3 -2
- package/lib/metrics.js.map +1 -1
- package/lib/rewards/attestationsRewards.js.map +1 -1
- package/lib/rewards/blockRewards.d.ts.map +1 -1
- package/lib/rewards/blockRewards.js +7 -4
- package/lib/rewards/blockRewards.js.map +1 -1
- package/lib/rewards/syncCommitteeRewards.js.map +1 -1
- package/lib/signatureSets/attesterSlashings.js.map +1 -1
- package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
- package/lib/signatureSets/executionPayloadBid.d.ts +2 -2
- package/lib/signatureSets/executionPayloadBid.d.ts.map +1 -1
- package/lib/signatureSets/executionPayloadBid.js +7 -5
- package/lib/signatureSets/executionPayloadBid.js.map +1 -1
- package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
- package/lib/signatureSets/index.js.map +1 -1
- package/lib/signatureSets/indexedAttestation.js.map +1 -1
- package/lib/signatureSets/indexedPayloadAttestation.js.map +1 -1
- package/lib/signatureSets/proposer.js.map +1 -1
- package/lib/signatureSets/proposerPreferences.js.map +1 -1
- package/lib/signatureSets/proposerSlashings.js.map +1 -1
- package/lib/signatureSets/randao.js.map +1 -1
- package/lib/signatureSets/voluntaryExits.js.map +1 -1
- package/lib/slot/index.d.ts +1 -0
- package/lib/slot/index.d.ts.map +1 -1
- package/lib/slot/index.js +1 -0
- package/lib/slot/index.js.map +1 -1
- package/lib/slot/upgradeStateToAltair.js +1 -1
- package/lib/slot/upgradeStateToAltair.js.map +1 -1
- package/lib/slot/upgradeStateToBellatrix.js.map +1 -1
- package/lib/slot/upgradeStateToCapella.js.map +1 -1
- package/lib/slot/upgradeStateToDeneb.js.map +1 -1
- package/lib/slot/upgradeStateToElectra.js.map +1 -1
- package/lib/slot/upgradeStateToFulu.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +1 -1
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/slot/upgradeStateToHeze.d.ts +7 -0
- package/lib/slot/upgradeStateToHeze.d.ts.map +1 -0
- package/lib/slot/upgradeStateToHeze.js +83 -0
- package/lib/slot/upgradeStateToHeze.js.map +1 -0
- package/lib/stateTransition.d.ts.map +1 -1
- package/lib/stateTransition.js +6 -5
- package/lib/stateTransition.js.map +1 -1
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +8 -3
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js +4 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/stateView/nativeBeaconStateView.js.map +1 -1
- package/lib/stateView/stateViewFactory.js.map +1 -1
- package/lib/testUtils/infura.js.map +1 -1
- package/lib/testUtils/interop.js.map +1 -1
- package/lib/testUtils/params.d.ts.map +1 -1
- package/lib/testUtils/state.js +1 -1
- package/lib/testUtils/state.js.map +1 -1
- package/lib/testUtils/testFileCache.js.map +1 -1
- package/lib/testUtils/util.d.ts +1 -1
- package/lib/testUtils/util.d.ts.map +1 -1
- package/lib/testUtils/util.js +2 -2
- package/lib/testUtils/util.js.map +1 -1
- package/lib/types.d.ts +2 -2
- package/lib/types.d.ts.map +1 -1
- package/lib/util/aggregator.js.map +1 -1
- package/lib/util/altair.js.map +1 -1
- package/lib/util/array.js.map +1 -1
- package/lib/util/attestation.js.map +1 -1
- package/lib/util/attesterStatus.js.map +1 -1
- package/lib/util/balance.js.map +1 -1
- package/lib/util/blindedBlock.js.map +1 -1
- package/lib/util/blockRoot.js.map +1 -1
- package/lib/util/capella.js.map +1 -1
- package/lib/util/clock.d.ts +61 -0
- package/lib/util/clock.d.ts.map +1 -0
- package/lib/util/clock.js +141 -0
- package/lib/util/clock.js.map +1 -0
- package/lib/util/computeAnchorCheckpoint.js.map +1 -1
- package/lib/util/deposit.d.ts.map +1 -1
- package/lib/util/deposit.js +10 -8
- package/lib/util/deposit.js.map +1 -1
- package/lib/util/domain.js.map +1 -1
- package/lib/util/electra.js.map +1 -1
- package/lib/util/epoch.js.map +1 -1
- package/lib/util/epochShuffling.js.map +1 -1
- package/lib/util/execution.js.map +1 -1
- package/lib/util/finality.js.map +1 -1
- package/lib/util/fulu.js.map +1 -1
- package/lib/util/genesis.d.ts.map +1 -1
- package/lib/util/genesis.js +7 -2
- package/lib/util/genesis.js.map +1 -1
- package/lib/util/gloas.d.ts +2 -1
- package/lib/util/gloas.d.ts.map +1 -1
- package/lib/util/gloas.js +7 -4
- package/lib/util/gloas.js.map +1 -1
- package/lib/util/index.d.ts +1 -0
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +1 -0
- package/lib/util/index.js.map +1 -1
- package/lib/util/interop.js.map +1 -1
- package/lib/util/loadState/findModifiedInactivityScores.js.map +1 -1
- package/lib/util/loadState/findModifiedValidators.js.map +1 -1
- package/lib/util/loadState/loadState.d.ts.map +1 -1
- package/lib/util/loadState/loadState.js +36 -5
- package/lib/util/loadState/loadState.js.map +1 -1
- package/lib/util/loadState/loadValidator.js.map +1 -1
- package/lib/util/pendingDepositsLookup.js.map +1 -1
- package/lib/util/rootCache.js.map +1 -1
- package/lib/util/seed.js.map +1 -1
- package/lib/util/shuffling.js +1 -2
- package/lib/util/shuffling.js.map +1 -1
- package/lib/util/signatureSets.js +1 -2
- package/lib/util/signatureSets.js.map +1 -1
- package/lib/util/signingRoot.js.map +1 -1
- package/lib/util/slot.js.map +1 -1
- package/lib/util/ssz.d.ts +5 -0
- package/lib/util/ssz.d.ts.map +1 -1
- package/lib/util/ssz.js +8 -1
- package/lib/util/ssz.js.map +1 -1
- package/lib/util/sszBytes.js.map +1 -1
- package/lib/util/syncCommittee.js.map +1 -1
- package/lib/util/targetUnslashedBalance.js.map +1 -1
- package/lib/util/validator.d.ts +5 -0
- package/lib/util/validator.d.ts.map +1 -1
- package/lib/util/validator.js +9 -0
- package/lib/util/validator.js.map +1 -1
- package/lib/util/weakSubjectivity.d.ts +1 -0
- package/lib/util/weakSubjectivity.d.ts.map +1 -1
- package/lib/util/weakSubjectivity.js +20 -8
- package/lib/util/weakSubjectivity.js.map +1 -1
- package/package.json +15 -15
- package/src/block/index.ts +4 -3
- package/src/block/processAttestations.ts +10 -2
- package/src/block/processAttestationsAltair.ts +10 -4
- package/src/block/processExecutionPayloadBid.ts +22 -9
- package/src/block/processOperations.ts +3 -2
- package/src/block/processWithdrawalRequest.ts +6 -2
- package/src/cache/epochCache.ts +19 -22
- package/src/cache/stateCache.ts +5 -2
- package/src/cache/types.ts +1 -0
- package/src/index.ts +4 -0
- package/src/lightClient/spec/utils.ts +9 -2
- package/src/metrics.ts +3 -2
- package/src/rewards/blockRewards.ts +20 -5
- package/src/signatureSets/executionPayloadBid.ts +7 -9
- package/src/slot/index.ts +1 -0
- package/src/slot/upgradeStateToAltair.ts +1 -0
- package/src/slot/upgradeStateToGloas.ts +1 -1
- package/src/slot/upgradeStateToHeze.ts +91 -0
- package/src/stateTransition.ts +5 -0
- package/src/stateView/interface.ts +13 -2
- package/src/testUtils/state.ts +1 -1
- package/src/testUtils/util.ts +2 -2
- package/src/types.ts +2 -0
- package/src/util/clock.ts +183 -0
- package/src/util/deposit.ts +11 -9
- package/src/util/genesis.ts +8 -2
- package/src/util/gloas.ts +9 -5
- package/src/util/index.ts +1 -0
- package/src/util/loadState/loadState.ts +50 -11
- package/src/util/ssz.ts +9 -1
- package/src/util/validator.ts +17 -0
- package/src/util/weakSubjectivity.ts +61 -22
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
+
import {GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
3
|
+
import {Epoch, Slot, TimeSeconds} from "@lodestar/types";
|
|
4
|
+
import {ErrorAborted, Logger, isErrorAborted, sleep} from "@lodestar/utils";
|
|
5
|
+
import {computeEpochAtSlot} from "./epoch.js";
|
|
6
|
+
import {computeTimeAtSlot, getCurrentSlot} from "./slot.js";
|
|
7
|
+
|
|
8
|
+
type RunEveryFn = (slot: Slot, signal: AbortSignal) => Promise<void>;
|
|
9
|
+
|
|
10
|
+
export type ClockOptions = {
|
|
11
|
+
skipSlots?: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export interface IClock {
|
|
15
|
+
readonly genesisTime: number;
|
|
16
|
+
readonly secondsPerSlot: number;
|
|
17
|
+
|
|
18
|
+
readonly currentEpoch: number;
|
|
19
|
+
|
|
20
|
+
start(signal: AbortSignal): void;
|
|
21
|
+
runEverySlot(fn: (slot: Slot, signal: AbortSignal) => Promise<void>): void;
|
|
22
|
+
runEveryEpoch(fn: (epoch: Epoch, signal: AbortSignal) => Promise<void>): void;
|
|
23
|
+
msToSlot(slot: Slot): number;
|
|
24
|
+
msFromSlot(slot: Slot): number;
|
|
25
|
+
secFromSlot(slot: Slot): number;
|
|
26
|
+
getCurrentSlot(): Slot;
|
|
27
|
+
getCurrentEpoch(): Epoch;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export enum TimeItem {
|
|
31
|
+
Slot,
|
|
32
|
+
Epoch,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class Clock implements IClock {
|
|
36
|
+
readonly genesisTime: number;
|
|
37
|
+
readonly secondsPerSlot: number;
|
|
38
|
+
private readonly config: ChainForkConfig;
|
|
39
|
+
private readonly logger: Logger;
|
|
40
|
+
private readonly fns: {timeItem: TimeItem; fn: RunEveryFn}[] = [];
|
|
41
|
+
|
|
42
|
+
constructor(
|
|
43
|
+
config: ChainForkConfig,
|
|
44
|
+
logger: Logger,
|
|
45
|
+
private readonly opts: {genesisTime: number} & ClockOptions
|
|
46
|
+
) {
|
|
47
|
+
this.genesisTime = opts.genesisTime;
|
|
48
|
+
this.secondsPerSlot = config.SLOT_DURATION_MS / 1000;
|
|
49
|
+
this.config = config;
|
|
50
|
+
this.logger = logger;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get currentEpoch(): Epoch {
|
|
54
|
+
return computeEpochAtSlot(getCurrentSlot(this.config, this.genesisTime));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
start(signal: AbortSignal): void {
|
|
58
|
+
for (const {timeItem, fn} of this.fns) {
|
|
59
|
+
this.runAtMostEvery(timeItem, signal, fn).catch((e: Error) => {
|
|
60
|
+
if (!isErrorAborted(e)) {
|
|
61
|
+
this.logger.error("runAtMostEvery", {}, e);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getCurrentSlot(): Slot {
|
|
68
|
+
return getCurrentSlot(this.config, this.genesisTime);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getCurrentEpoch(): Epoch {
|
|
72
|
+
return computeEpochAtSlot(getCurrentSlot(this.config, this.genesisTime));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
runEverySlot(fn: RunEveryFn): void {
|
|
76
|
+
this.fns.push({timeItem: TimeItem.Slot, fn});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
runEveryEpoch(fn: RunEveryFn): void {
|
|
80
|
+
this.fns.push({timeItem: TimeItem.Epoch, fn});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Milliseconds from now to a specific slot */
|
|
84
|
+
msToSlot(slot: Slot): number {
|
|
85
|
+
return computeTimeAtSlot(this.config, slot, this.genesisTime) * 1000 - Date.now();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Milliseconds elapsed from a specific slot to now */
|
|
89
|
+
msFromSlot(slot: Slot): number {
|
|
90
|
+
return Date.now() - computeTimeAtSlot(this.config, slot, this.genesisTime) * 1000;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Seconds elapsed from a specific slot to now */
|
|
94
|
+
secFromSlot(slot: Slot): number {
|
|
95
|
+
return Date.now() / 1000 - computeTimeAtSlot(this.config, slot, this.genesisTime);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* If a task happens to take more than one slot to run, we might skip a slot. This is unfortunate,
|
|
100
|
+
* however the alternative is to *always* process every slot, which has the chance of creating a
|
|
101
|
+
* theoretically unlimited backlog of tasks. It was a conscious decision to choose to drop tasks
|
|
102
|
+
* on an overloaded/latent system rather than overload it even more.
|
|
103
|
+
*/
|
|
104
|
+
private async runAtMostEvery(timeItem: TimeItem, signal: AbortSignal, fn: RunEveryFn): Promise<void> {
|
|
105
|
+
// Run immediately first
|
|
106
|
+
let slot = getCurrentSlot(this.config, this.genesisTime);
|
|
107
|
+
let slotOrEpoch = timeItem === TimeItem.Slot ? slot : computeEpochAtSlot(slot);
|
|
108
|
+
while (!signal.aborted) {
|
|
109
|
+
// Must catch fn() to ensure `sleep()` is awaited both for resolve and reject
|
|
110
|
+
const task = fn(slotOrEpoch, signal).catch((e: Error) => {
|
|
111
|
+
if (!isErrorAborted(e)) this.logger.error("Error on runEvery fn", {}, e);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (timeItem !== TimeItem.Slot || this.opts.skipSlots !== false) {
|
|
115
|
+
// await response to only continue with next task if current task finished within slot
|
|
116
|
+
await task;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await sleep(this.timeUntilNext(timeItem), signal);
|
|
121
|
+
// calling getCurrentSlot here may not be correct when we're close to the next slot
|
|
122
|
+
// it's safe to call getCurrentSlotAround after we sleep
|
|
123
|
+
const nextSlot = getCurrentSlotAround(this.config, this.genesisTime);
|
|
124
|
+
|
|
125
|
+
if (timeItem === TimeItem.Slot) {
|
|
126
|
+
if (nextSlot > slot + 1) {
|
|
127
|
+
// It's not very likely that we skip more than one slot as HTTP timeout is set
|
|
128
|
+
// to SLOT_DURATION_MS so we will fail task before skipping another slot.
|
|
129
|
+
this.logger.warn("Skipped slot due to task taking more than one slot to run", {
|
|
130
|
+
skippedSlot: slot + 1,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
slotOrEpoch = nextSlot;
|
|
134
|
+
} else {
|
|
135
|
+
slotOrEpoch = computeEpochAtSlot(nextSlot);
|
|
136
|
+
}
|
|
137
|
+
slot = nextSlot;
|
|
138
|
+
} catch (e) {
|
|
139
|
+
if (e instanceof ErrorAborted) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
throw e;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private timeUntilNext(timeItem: TimeItem): number {
|
|
148
|
+
const milliSecondsPerSlot = this.config.SLOT_DURATION_MS;
|
|
149
|
+
const msFromGenesis = Date.now() - this.genesisTime * 1000;
|
|
150
|
+
|
|
151
|
+
if (timeItem === TimeItem.Slot) {
|
|
152
|
+
if (msFromGenesis >= 0) {
|
|
153
|
+
return milliSecondsPerSlot - (msFromGenesis % milliSecondsPerSlot);
|
|
154
|
+
}
|
|
155
|
+
return Math.abs(msFromGenesis) % milliSecondsPerSlot;
|
|
156
|
+
}
|
|
157
|
+
const milliSecondsPerEpoch = SLOTS_PER_EPOCH * milliSecondsPerSlot;
|
|
158
|
+
if (msFromGenesis >= 0) {
|
|
159
|
+
return milliSecondsPerEpoch - (msFromGenesis % milliSecondsPerEpoch);
|
|
160
|
+
}
|
|
161
|
+
return Math.abs(msFromGenesis) % milliSecondsPerEpoch;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Same to the spec but we use Math.round instead of Math.floor.
|
|
167
|
+
*/
|
|
168
|
+
export function getCurrentSlotAround(config: ChainForkConfig, genesisTime: TimeSeconds): Slot {
|
|
169
|
+
const diffInSeconds = Date.now() / 1000 - genesisTime;
|
|
170
|
+
const slotsSinceGenesis = Math.round((diffInSeconds * 1000) / config.SLOT_DURATION_MS);
|
|
171
|
+
return GENESIS_SLOT + slotsSinceGenesis;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// function useEventStream() {
|
|
175
|
+
// this.stream = this.events.getEventStream([BeaconEventType.BLOCK, BeaconEventType.HEAD, BeaconEventType.CHAIN_REORG]);
|
|
176
|
+
// pipeToEmitter(this.stream, this).catch((e: Error) => {
|
|
177
|
+
// this.logger.error("Error on stream pipe", {}, e);
|
|
178
|
+
// });
|
|
179
|
+
|
|
180
|
+
// // On stop
|
|
181
|
+
// this.stream.stop();
|
|
182
|
+
// this.stream = null;
|
|
183
|
+
// }
|
package/src/util/deposit.ts
CHANGED
|
@@ -4,19 +4,21 @@ import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js";
|
|
|
4
4
|
|
|
5
5
|
export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: phase0.Eth1Data): UintNum64 {
|
|
6
6
|
const eth1DataToUse = eth1Data ?? state.eth1Data;
|
|
7
|
+
// Proposer can set any value, use in bigint until the result is bounded by MAX_DEPOSITS
|
|
8
|
+
const depositCount = eth1DataToUse.depositCount;
|
|
9
|
+
const eth1DepositIndex = BigInt(state.eth1DepositIndex);
|
|
10
|
+
const maxDeposits = BigInt(MAX_DEPOSITS);
|
|
7
11
|
if (state.config.getForkSeq(state.slot) >= ForkSeq.electra) {
|
|
8
12
|
const electraState = state as CachedBeaconStateElectra;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const eth1DataIndexLimit: UintNum64 =
|
|
12
|
-
eth1DataToUse.depositCount < electraState.depositRequestsStartIndex
|
|
13
|
-
? eth1DataToUse.depositCount
|
|
14
|
-
: Number(electraState.depositRequestsStartIndex);
|
|
13
|
+
const eth1DataIndexLimit =
|
|
14
|
+
depositCount < electraState.depositRequestsStartIndex ? depositCount : electraState.depositRequestsStartIndex;
|
|
15
15
|
|
|
16
|
-
if (
|
|
17
|
-
|
|
16
|
+
if (eth1DepositIndex < eth1DataIndexLimit) {
|
|
17
|
+
const available = eth1DataIndexLimit - eth1DepositIndex;
|
|
18
|
+
return Number(available < maxDeposits ? available : maxDeposits);
|
|
18
19
|
}
|
|
19
20
|
return 0;
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
+
const available = depositCount - eth1DepositIndex;
|
|
23
|
+
return Number(available < maxDeposits ? available : maxDeposits);
|
|
22
24
|
}
|
package/src/util/genesis.ts
CHANGED
|
@@ -139,7 +139,7 @@ export function applyDeposits(
|
|
|
139
139
|
const fullDepositDataRootArr = fullDepositDataRootList ? fullDepositDataRootList.getAllReadonlyValues() : null;
|
|
140
140
|
|
|
141
141
|
if (fullDepositDataRootArr) {
|
|
142
|
-
const depositCount = state.eth1Data.depositCount;
|
|
142
|
+
const depositCount = Number(state.eth1Data.depositCount);
|
|
143
143
|
for (let index = 0; index < depositCount; index++) {
|
|
144
144
|
depositDataRootList.push(fullDepositDataRootArr[index]);
|
|
145
145
|
}
|
|
@@ -160,7 +160,7 @@ export function applyDeposits(
|
|
|
160
160
|
);
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
state.eth1Data.depositCount +=
|
|
163
|
+
state.eth1Data.depositCount += 1n;
|
|
164
164
|
|
|
165
165
|
const fork = config.getForkSeq(GENESIS_SLOT);
|
|
166
166
|
processDeposit(fork, state, deposit);
|
|
@@ -334,6 +334,12 @@ export function initializeBeaconStateFromEth1(
|
|
|
334
334
|
stateGloas.fork.currentVersion = config.GLOAS_FORK_VERSION;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
if (fork >= ForkSeq.heze) {
|
|
338
|
+
const stateHeze = state as CompositeViewDU<typeof ssz.heze.BeaconState>;
|
|
339
|
+
stateHeze.fork.previousVersion = config.HEZE_FORK_VERSION;
|
|
340
|
+
stateHeze.fork.currentVersion = config.HEZE_FORK_VERSION;
|
|
341
|
+
}
|
|
342
|
+
|
|
337
343
|
state.commit();
|
|
338
344
|
|
|
339
345
|
return state;
|
package/src/util/gloas.ts
CHANGED
|
@@ -87,15 +87,19 @@ export function isActiveBuilder(builder: gloas.Builder, finalizedEpoch: Epoch):
|
|
|
87
87
|
* From https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
|
|
88
88
|
*/
|
|
89
89
|
export function getExpectedGasLimit(parentGasLimit: number, targetGasLimit: number): number {
|
|
90
|
-
|
|
90
|
+
return Number(getExpectedGasLimitBigint(BigInt(parentGasLimit), BigInt(targetGasLimit)));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getExpectedGasLimitBigint(parentGasLimit: bigint, targetGasLimit: bigint): bigint {
|
|
94
|
+
const maxGasLimitDifference = (parentGasLimit / 1024n > 1n ? parentGasLimit / 1024n : 1n) - 1n;
|
|
91
95
|
|
|
92
96
|
if (targetGasLimit > parentGasLimit) {
|
|
93
97
|
const gasDiff = targetGasLimit - parentGasLimit;
|
|
94
|
-
return parentGasLimit +
|
|
98
|
+
return parentGasLimit + (gasDiff < maxGasLimitDifference ? gasDiff : maxGasLimitDifference);
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
const gasDiff = parentGasLimit - targetGasLimit;
|
|
98
|
-
return parentGasLimit -
|
|
102
|
+
return parentGasLimit - (gasDiff < maxGasLimitDifference ? gasDiff : maxGasLimitDifference);
|
|
99
103
|
}
|
|
100
104
|
|
|
101
105
|
/**
|
|
@@ -104,8 +108,8 @@ export function getExpectedGasLimit(parentGasLimit: number, targetGasLimit: numb
|
|
|
104
108
|
* adjustment step of the parent, otherwise it must hit the clamped boundary.
|
|
105
109
|
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.8/specs/gloas/builder.md#new-is_gas_limit_target_compatible
|
|
106
110
|
*/
|
|
107
|
-
export function isGasLimitTargetCompatible(parentGasLimit:
|
|
108
|
-
return gasLimit ===
|
|
111
|
+
export function isGasLimitTargetCompatible(parentGasLimit: bigint, gasLimit: bigint, targetGasLimit: bigint): boolean {
|
|
112
|
+
return gasLimit === getExpectedGasLimitBigint(parentGasLimit, targetGasLimit);
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
/**
|
package/src/util/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from "./balance.js";
|
|
|
6
6
|
export * from "./blindedBlock.js";
|
|
7
7
|
export * from "./blockRoot.js";
|
|
8
8
|
export * from "./capella.js";
|
|
9
|
+
export * from "./clock.js";
|
|
9
10
|
export * from "./computeAnchorCheckpoint.js";
|
|
10
11
|
export * from "./deposit.js";
|
|
11
12
|
export * from "./domain.js";
|
|
@@ -25,10 +25,29 @@ export function loadState(
|
|
|
25
25
|
): MigrateStateOutput {
|
|
26
26
|
// casting only to make typescript happy
|
|
27
27
|
const stateType = getStateTypeFromBytes(config, stateBytes) as typeof ssz.capella.BeaconState;
|
|
28
|
+
const fork = getForkFromStateBytes(config, stateBytes);
|
|
29
|
+
const seedFork = config.getForkSeq(seedState.slot);
|
|
30
|
+
|
|
28
31
|
const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength);
|
|
29
32
|
const fieldRanges = stateType.getFieldRanges(dataView, 0, stateBytes.length);
|
|
30
33
|
const allFields = Object.keys(stateType.fields);
|
|
31
34
|
const validatorsFieldIndex = allFields.indexOf("validators");
|
|
35
|
+
const validatorsRange = fieldRanges[validatorsFieldIndex];
|
|
36
|
+
const newValidatorsBytes = stateBytes.subarray(validatorsRange.start, validatorsRange.end);
|
|
37
|
+
|
|
38
|
+
// EIP-7688 replaces List with ProgressiveList for validators and inactivityScores at gloas,
|
|
39
|
+
// changing the merkle tree shape. Seed nodes cannot be reused when one state is pre-gloas
|
|
40
|
+
// and the other post-gloas.
|
|
41
|
+
const crossesGloasFork =
|
|
42
|
+
(fork >= ForkSeq.gloas && seedFork < ForkSeq.gloas) || (fork < ForkSeq.gloas && seedFork >= ForkSeq.gloas);
|
|
43
|
+
if (crossesGloasFork) {
|
|
44
|
+
const migratedState = stateType.deserializeToViewDU(stateBytes) as BeaconStateAllForks;
|
|
45
|
+
// modified validators must still be reported so that the pubkey cache is refreshed for
|
|
46
|
+
// any index that differs from the seed state, which may not be an ancestor of this state
|
|
47
|
+
const modifiedValidators = findModifiedAndAppendedValidators(seedState, newValidatorsBytes, seedValidatorsBytes);
|
|
48
|
+
return {state: migratedState, modifiedValidators};
|
|
49
|
+
}
|
|
50
|
+
|
|
32
51
|
// start with default view has the same performance to start with seed state
|
|
33
52
|
// and it is not fork dependent
|
|
34
53
|
const migratedState = deserializeContainerIgnoreFields(
|
|
@@ -39,19 +58,10 @@ export function loadState(
|
|
|
39
58
|
) as BeaconStateAllForks;
|
|
40
59
|
|
|
41
60
|
// validators are rarely changed
|
|
42
|
-
const
|
|
43
|
-
const modifiedValidators = loadValidators(
|
|
44
|
-
migratedState,
|
|
45
|
-
seedState,
|
|
46
|
-
stateBytes.subarray(validatorsRange.start, validatorsRange.end),
|
|
47
|
-
seedValidatorsBytes
|
|
48
|
-
);
|
|
61
|
+
const modifiedValidators = loadValidators(migratedState, seedState, newValidatorsBytes, seedValidatorsBytes);
|
|
49
62
|
|
|
50
63
|
// inactivityScores are rarely changed
|
|
51
64
|
// this saves ~500ms of hashTreeRoot() time of state
|
|
52
|
-
const fork = getForkFromStateBytes(config, stateBytes);
|
|
53
|
-
const seedFork = config.getForkSeq(seedState.slot);
|
|
54
|
-
|
|
55
65
|
if (fork >= ForkSeq.altair && seedFork >= ForkSeq.altair) {
|
|
56
66
|
const inactivityScoresIndex = allFields.indexOf("inactivityScores");
|
|
57
67
|
const inactivityScoresRange = fieldRanges[inactivityScoresIndex];
|
|
@@ -141,7 +151,9 @@ function loadInactivityScores(
|
|
|
141
151
|
}
|
|
142
152
|
} else {
|
|
143
153
|
if (newValidator - 1 < 0) {
|
|
144
|
-
|
|
154
|
+
// use the state's own field type, the list shape differs between altair (List) and gloas (ProgressiveList)
|
|
155
|
+
const inactivityScoresType = (migratedState.type as typeof ssz.altair.BeaconState).fields.inactivityScores;
|
|
156
|
+
migratedState.inactivityScores = inactivityScoresType.defaultViewDU();
|
|
145
157
|
} else {
|
|
146
158
|
migratedState.inactivityScores = migratedState.inactivityScores.sliceTo(newValidator - 1);
|
|
147
159
|
}
|
|
@@ -177,6 +189,33 @@ function loadInactivityScores(
|
|
|
177
189
|
* @param migratedState state to be migrated, the validators are loaded to this state
|
|
178
190
|
* @returns modified validator indices
|
|
179
191
|
*/
|
|
192
|
+
/**
|
|
193
|
+
* Find indices of validators whose serialized bytes differ from the seed state, plus indices
|
|
194
|
+
* appended past the seed state's validator count. Unlike loadValidators() this only diffs
|
|
195
|
+
* bytes and does not share the seed state's tree.
|
|
196
|
+
*/
|
|
197
|
+
function findModifiedAndAppendedValidators(
|
|
198
|
+
seedState: BeaconStateAllForks,
|
|
199
|
+
newValidatorsBytes: Uint8Array,
|
|
200
|
+
seedStateValidatorsBytes?: Uint8Array
|
|
201
|
+
): number[] {
|
|
202
|
+
const seedValidatorCount = seedState.validators.length;
|
|
203
|
+
const newValidatorCount = Math.floor(newValidatorsBytes.length / VALIDATOR_BYTES_SIZE);
|
|
204
|
+
const minValidatorCount = Math.min(seedValidatorCount, newValidatorCount);
|
|
205
|
+
const seedValidatorsBytes = seedStateValidatorsBytes ?? seedState.validators.serialize();
|
|
206
|
+
const modifiedValidators: number[] = [];
|
|
207
|
+
findModifiedValidators(
|
|
208
|
+
seedValidatorsBytes.subarray(0, minValidatorCount * VALIDATOR_BYTES_SIZE),
|
|
209
|
+
newValidatorsBytes.subarray(0, minValidatorCount * VALIDATOR_BYTES_SIZE),
|
|
210
|
+
modifiedValidators
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
for (let validatorIndex = seedValidatorCount; validatorIndex < newValidatorCount; validatorIndex++) {
|
|
214
|
+
modifiedValidators.push(validatorIndex);
|
|
215
|
+
}
|
|
216
|
+
return modifiedValidators;
|
|
217
|
+
}
|
|
218
|
+
|
|
180
219
|
function loadValidators(
|
|
181
220
|
migratedState: BeaconStateAllForks,
|
|
182
221
|
seedState: BeaconStateAllForks,
|
package/src/util/ssz.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {BranchNode, LeafNode, Node, zeroNode} from "@chainsafe/persistent-merkle-tree";
|
|
2
2
|
import {progressiveSubtreeFillToContents} from "@chainsafe/ssz";
|
|
3
3
|
|
|
4
|
-
// TODO: move these utils to @chainsafe/ssz
|
|
4
|
+
// TODO: move these utils to @chainsafe/ssz, see https://github.com/ChainSafe/ssz/issues/542
|
|
5
5
|
|
|
6
6
|
/** Root node (chunks + length mix-in) of a zero-filled ProgressiveListBasicType of `length` items */
|
|
7
7
|
export function zeroProgressiveListBasicRootNode(itemsPerChunk: number, length: number): Node {
|
|
@@ -15,6 +15,14 @@ export function zeroProgressiveListBasicRootNode(itemsPerChunk: number, length:
|
|
|
15
15
|
return new BranchNode(zeroProgressiveNode(numSubtrees), LeafNode.fromUint32(length));
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Check if an array-type ViewDU (ListBasic, ListComposite or their progressive equivalents) has its
|
|
20
|
+
* internal nodes cache populated. The flag is a private attribute maintained by all of these classes.
|
|
21
|
+
*/
|
|
22
|
+
export function isViewDUNodesPopulated(view: unknown): boolean {
|
|
23
|
+
return (view as {nodesPopulated?: boolean}).nodesPopulated === true;
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
/**
|
|
19
27
|
* Root node of a progressive list from its chunk/element nodes + length mix-in.
|
|
20
28
|
* `nodes` are packed 32-byte chunk leaves for basic lists, or element root nodes for composite lists.
|
package/src/util/validator.ts
CHANGED
|
@@ -128,6 +128,23 @@ export function getConsolidationChurnLimit(fork: ForkSeq, epochCtx: EpochCache):
|
|
|
128
128
|
return getBalanceChurnLimitFromCache(epochCtx) - getActivationExitChurnLimit(epochCtx);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// NOTE: duplicates the quotient/min choices in get{Exit,Activation,Consolidation}ChurnLimit.
|
|
132
|
+
export function getGloasChurnLimits(
|
|
133
|
+
config: ChainForkConfig,
|
|
134
|
+
totalActiveBalanceIncrements: number
|
|
135
|
+
): {exit: number; activation: number; consolidation: number} {
|
|
136
|
+
const exit = getBalanceChurnLimit(
|
|
137
|
+
totalActiveBalanceIncrements,
|
|
138
|
+
config.CHURN_LIMIT_QUOTIENT_GLOAS,
|
|
139
|
+
config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
|
|
140
|
+
);
|
|
141
|
+
return {
|
|
142
|
+
exit,
|
|
143
|
+
activation: Math.min(config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT_GLOAS, exit),
|
|
144
|
+
consolidation: getBalanceChurnLimit(totalActiveBalanceIncrements, config.CONSOLIDATION_CHURN_LIMIT_QUOTIENT, 0),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
131
148
|
export function getMaxEffectiveBalance(withdrawalCredentials: Uint8Array): number {
|
|
132
149
|
// Compounding withdrawal credential only available since Electra
|
|
133
150
|
if (hasCompoundingWithdrawalCredential(withdrawalCredentials)) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {BeaconConfig, ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {
|
|
3
3
|
EFFECTIVE_BALANCE_INCREMENT,
|
|
4
|
+
ForkSeq,
|
|
4
5
|
MAX_DEPOSITS,
|
|
5
6
|
MAX_EFFECTIVE_BALANCE,
|
|
6
7
|
SLOTS_PER_EPOCH,
|
|
7
8
|
isForkPostElectra,
|
|
9
|
+
isForkPostGloas,
|
|
8
10
|
} from "@lodestar/params";
|
|
9
11
|
import {Epoch, Root, ssz} from "@lodestar/types";
|
|
10
12
|
import {Checkpoint} from "@lodestar/types/phase0";
|
|
@@ -14,10 +16,14 @@ import {BeaconStateAllForks, CachedBeaconStateAllForks} from "../types.js";
|
|
|
14
16
|
import {computeCheckpointEpochAtStateSlot, computeEpochAtSlot, getCurrentEpoch} from "./epoch.js";
|
|
15
17
|
import {getCurrentSlot} from "./slot.js";
|
|
16
18
|
import {
|
|
19
|
+
getActivationChurnLimit,
|
|
17
20
|
getActiveValidatorIndices,
|
|
18
21
|
getBalanceChurnLimit,
|
|
19
22
|
getBalanceChurnLimitFromCache,
|
|
20
23
|
getChurnLimit,
|
|
24
|
+
getConsolidationChurnLimit,
|
|
25
|
+
getExitChurnLimit,
|
|
26
|
+
getGloasChurnLimits,
|
|
21
27
|
} from "./validator.js";
|
|
22
28
|
|
|
23
29
|
export const ETH_TO_GWEI = 10 ** 9;
|
|
@@ -49,18 +55,26 @@ export function computeWeakSubjectivityPeriodCachedState(
|
|
|
49
55
|
const activeValidatorCount = state.epochCtx.currentShuffling.activeIndices.length;
|
|
50
56
|
const fork = config.getForkName(state.slot);
|
|
51
57
|
|
|
52
|
-
return
|
|
53
|
-
?
|
|
58
|
+
return isForkPostGloas(fork)
|
|
59
|
+
? computeWeakSubjectivityPeriodFromConstituentsGloas(
|
|
54
60
|
state.epochCtx.totalActiveBalanceIncrements,
|
|
55
|
-
|
|
61
|
+
getExitChurnLimit(state.epochCtx),
|
|
62
|
+
getActivationChurnLimit(state.epochCtx),
|
|
63
|
+
getConsolidationChurnLimit(ForkSeq.gloas, state.epochCtx),
|
|
56
64
|
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
57
65
|
)
|
|
58
|
-
:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
: isForkPostElectra(fork)
|
|
67
|
+
? computeWeakSubjectivityPeriodFromConstituentsElectra(
|
|
68
|
+
state.epochCtx.totalActiveBalanceIncrements,
|
|
69
|
+
getBalanceChurnLimitFromCache(state.epochCtx),
|
|
70
|
+
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
71
|
+
)
|
|
72
|
+
: computeWeakSubjectivityPeriodFromConstituentsPhase0(
|
|
73
|
+
activeValidatorCount,
|
|
74
|
+
state.epochCtx.totalActiveBalanceIncrements,
|
|
75
|
+
getChurnLimit(config, activeValidatorCount),
|
|
76
|
+
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
77
|
+
);
|
|
64
78
|
}
|
|
65
79
|
|
|
66
80
|
/**
|
|
@@ -80,22 +94,32 @@ export function computeWeakSubjectivityPeriod(config: ChainForkConfig, state: Be
|
|
|
80
94
|
totalActiveBalanceIncrements = 1;
|
|
81
95
|
}
|
|
82
96
|
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
const churnLimitsGloas = getGloasChurnLimits(config, totalActiveBalanceIncrements);
|
|
98
|
+
|
|
99
|
+
return isForkPostGloas(fork)
|
|
100
|
+
? computeWeakSubjectivityPeriodFromConstituentsGloas(
|
|
85
101
|
totalActiveBalanceIncrements,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
|
|
90
|
-
),
|
|
102
|
+
churnLimitsGloas.exit,
|
|
103
|
+
churnLimitsGloas.activation,
|
|
104
|
+
churnLimitsGloas.consolidation,
|
|
91
105
|
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
92
106
|
)
|
|
93
|
-
:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
107
|
+
: isForkPostElectra(fork)
|
|
108
|
+
? computeWeakSubjectivityPeriodFromConstituentsElectra(
|
|
109
|
+
totalActiveBalanceIncrements,
|
|
110
|
+
getBalanceChurnLimit(
|
|
111
|
+
totalActiveBalanceIncrements,
|
|
112
|
+
config.CHURN_LIMIT_QUOTIENT,
|
|
113
|
+
config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
|
|
114
|
+
),
|
|
115
|
+
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
116
|
+
)
|
|
117
|
+
: computeWeakSubjectivityPeriodFromConstituentsPhase0(
|
|
118
|
+
activeIndices.length,
|
|
119
|
+
totalActiveBalanceIncrements,
|
|
120
|
+
getChurnLimit(config, activeIndices.length),
|
|
121
|
+
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
122
|
+
);
|
|
99
123
|
}
|
|
100
124
|
|
|
101
125
|
export function computeWeakSubjectivityPeriodFromConstituentsPhase0(
|
|
@@ -142,6 +166,21 @@ export function computeWeakSubjectivityPeriodFromConstituentsElectra(
|
|
|
142
166
|
return minWithdrawabilityDelay + epochsForValidatorSetChurn;
|
|
143
167
|
}
|
|
144
168
|
|
|
169
|
+
export function computeWeakSubjectivityPeriodFromConstituentsGloas(
|
|
170
|
+
totalBalanceByIncrement: number,
|
|
171
|
+
exitChurnLimit: number,
|
|
172
|
+
activationChurnLimit: number,
|
|
173
|
+
consolidationChurnLimit: number,
|
|
174
|
+
minWithdrawabilityDelay: number
|
|
175
|
+
): number {
|
|
176
|
+
// Keep t as increment for now. Multiply final result by EFFECTIVE_BALANCE_INCREMENT
|
|
177
|
+
const t = totalBalanceByIncrement;
|
|
178
|
+
const delta = Math.floor((2 * exitChurnLimit) / 3) + Math.floor(activationChurnLimit / 3) + consolidationChurnLimit;
|
|
179
|
+
const epochsForValidatorSetChurn = Math.floor(((SAFETY_DECAY * t) / (2 * delta * 100)) * EFFECTIVE_BALANCE_INCREMENT);
|
|
180
|
+
|
|
181
|
+
return minWithdrawabilityDelay + epochsForValidatorSetChurn;
|
|
182
|
+
}
|
|
183
|
+
|
|
145
184
|
export function getLatestBlockRoot(state: BeaconStateAllForks): Root {
|
|
146
185
|
const header = ssz.phase0.BeaconBlockHeader.clone(state.latestBlockHeader);
|
|
147
186
|
if (ssz.Root.equals(header.stateRoot, ZERO_HASH)) {
|