@lodestar/state-transition 1.35.0-dev.e18102ed8c → 1.35.0-dev.f45a2be721
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.d.ts.map +1 -0
- package/lib/block/index.d.ts.map +1 -0
- package/lib/block/initiateValidatorExit.d.ts.map +1 -0
- package/lib/block/isValidIndexedAttestation.d.ts.map +1 -0
- package/lib/block/processAttestationPhase0.d.ts.map +1 -0
- package/lib/block/processAttestations.d.ts.map +1 -0
- package/lib/block/processAttestationsAltair.d.ts.map +1 -0
- package/lib/block/processAttesterSlashing.d.ts.map +1 -0
- package/lib/block/processBlobKzgCommitments.d.ts.map +1 -0
- package/lib/block/processBlockHeader.d.ts.map +1 -0
- package/lib/block/processBlsToExecutionChange.d.ts.map +1 -0
- package/lib/block/processConsolidationRequest.d.ts.map +1 -0
- package/lib/block/processDeposit.d.ts.map +1 -0
- package/lib/block/processDepositRequest.d.ts.map +1 -0
- package/lib/block/processEth1Data.d.ts.map +1 -0
- package/lib/block/processExecutionPayload.d.ts.map +1 -0
- package/lib/block/processExecutionPayload.js +3 -3
- package/lib/block/processExecutionPayload.js.map +1 -1
- package/lib/block/processOperations.d.ts.map +1 -0
- package/lib/block/processProposerSlashing.d.ts.map +1 -0
- package/lib/block/processRandao.d.ts.map +1 -0
- package/lib/block/processSyncCommittee.d.ts.map +1 -0
- package/lib/block/processVoluntaryExit.d.ts.map +1 -0
- package/lib/block/processWithdrawalRequest.d.ts.map +1 -0
- package/lib/block/processWithdrawals.d.ts.map +1 -0
- package/lib/block/slashValidator.d.ts.map +1 -0
- package/lib/block/types.d.ts.map +1 -0
- package/lib/cache/effectiveBalanceIncrements.d.ts.map +1 -0
- package/lib/cache/epochCache.d.ts.map +1 -0
- package/lib/cache/epochTransitionCache.d.ts.map +1 -0
- package/lib/cache/pubkeyCache.d.ts.map +1 -0
- package/lib/cache/rewardCache.d.ts.map +1 -0
- package/lib/cache/stateCache.d.ts.map +1 -0
- package/lib/cache/syncCommitteeCache.d.ts.map +1 -0
- package/lib/cache/types.d.ts +2 -2
- package/lib/cache/types.d.ts.map +1 -0
- package/lib/constants/constants.d.ts.map +1 -0
- package/lib/constants/index.d.ts.map +1 -0
- package/lib/epoch/computeUnrealizedCheckpoints.d.ts.map +1 -0
- package/lib/epoch/getAttestationDeltas.d.ts.map +1 -0
- package/lib/epoch/getRewardsAndPenalties.d.ts.map +1 -0
- package/lib/epoch/index.d.ts.map +1 -0
- package/lib/epoch/processEffectiveBalanceUpdates.d.ts.map +1 -0
- package/lib/epoch/processEth1DataReset.d.ts.map +1 -0
- package/lib/epoch/processHistoricalRootsUpdate.d.ts.map +1 -0
- package/lib/epoch/processHistoricalSummariesUpdate.d.ts.map +1 -0
- package/lib/epoch/processInactivityUpdates.d.ts.map +1 -0
- package/lib/epoch/processJustificationAndFinalization.d.ts.map +1 -0
- package/lib/epoch/processParticipationFlagUpdates.d.ts.map +1 -0
- package/lib/epoch/processParticipationRecordUpdates.d.ts.map +1 -0
- package/lib/epoch/processPendingAttestations.d.ts.map +1 -0
- package/lib/epoch/processPendingConsolidations.d.ts.map +1 -0
- package/lib/epoch/processPendingDeposits.d.ts.map +1 -0
- package/lib/epoch/processProposerLookahead.d.ts.map +1 -0
- package/lib/epoch/processRandaoMixesReset.d.ts.map +1 -0
- package/lib/epoch/processRegistryUpdates.d.ts.map +1 -0
- package/lib/epoch/processRewardsAndPenalties.d.ts.map +1 -0
- package/lib/epoch/processSlashings.d.ts.map +1 -0
- package/lib/epoch/processSlashingsReset.d.ts.map +1 -0
- package/lib/epoch/processSyncCommitteeUpdates.d.ts.map +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/metrics.d.ts.map +1 -0
- package/lib/signatureSets/attesterSlashings.d.ts.map +1 -0
- package/lib/signatureSets/blsToExecutionChange.d.ts.map +1 -0
- package/lib/signatureSets/index.d.ts.map +1 -0
- package/lib/signatureSets/indexedAttestation.d.ts.map +1 -0
- package/lib/signatureSets/proposer.d.ts.map +1 -0
- package/lib/signatureSets/proposerSlashings.d.ts.map +1 -0
- package/lib/signatureSets/randao.d.ts.map +1 -0
- package/lib/signatureSets/voluntaryExits.d.ts.map +1 -0
- package/lib/slot/index.d.ts.map +1 -0
- package/lib/slot/upgradeStateToAltair.d.ts.map +1 -0
- package/lib/slot/upgradeStateToBellatrix.d.ts.map +1 -0
- package/lib/slot/upgradeStateToCapella.d.ts.map +1 -0
- package/lib/slot/upgradeStateToDeneb.d.ts.map +1 -0
- package/lib/slot/upgradeStateToElectra.d.ts.map +1 -0
- package/lib/slot/upgradeStateToFulu.d.ts.map +1 -0
- package/lib/slot/upgradeStateToGloas.d.ts.map +1 -0
- package/lib/stateTransition.d.ts.map +1 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/util/aggregator.d.ts.map +1 -0
- package/lib/util/altair.d.ts.map +1 -0
- package/lib/util/array.d.ts.map +1 -0
- package/lib/util/attestation.d.ts.map +1 -0
- package/lib/util/attesterStatus.d.ts.map +1 -0
- package/lib/util/balance.d.ts.map +1 -0
- package/lib/util/blindedBlock.d.ts +3 -3
- package/lib/util/blindedBlock.d.ts.map +1 -0
- package/lib/util/blindedBlock.js.map +1 -1
- package/lib/util/blockRoot.d.ts.map +1 -0
- package/lib/util/calculateCommitteeAssignments.d.ts.map +1 -0
- package/lib/util/capella.d.ts.map +1 -0
- package/lib/util/computeAnchorCheckpoint.d.ts.map +1 -0
- package/lib/util/deposit.d.ts.map +1 -0
- package/lib/util/domain.d.ts.map +1 -0
- package/lib/util/electra.d.ts.map +1 -0
- package/lib/util/epoch.d.ts.map +1 -0
- package/lib/util/epochShuffling.d.ts.map +1 -0
- package/lib/util/execution.d.ts +2 -2
- package/lib/util/execution.d.ts.map +1 -0
- package/lib/util/execution.js.map +1 -1
- package/lib/util/finality.d.ts.map +1 -0
- package/lib/util/fulu.d.ts.map +1 -0
- package/lib/util/genesis.d.ts.map +1 -0
- package/lib/util/genesis.js +0 -3
- package/lib/util/genesis.js.map +1 -1
- package/lib/util/index.d.ts.map +1 -0
- package/lib/util/interop.d.ts.map +1 -0
- package/lib/util/loadState/findModifiedInactivityScores.d.ts.map +1 -0
- package/lib/util/loadState/findModifiedValidators.d.ts.map +1 -0
- package/lib/util/loadState/index.d.ts.map +1 -0
- package/lib/util/loadState/loadState.d.ts.map +1 -0
- package/lib/util/loadState/loadValidator.d.ts.map +1 -0
- package/lib/util/rootCache.d.ts.map +1 -0
- package/lib/util/seed.d.ts.map +1 -0
- package/lib/util/shufflingDecisionRoot.d.ts.map +1 -0
- package/lib/util/signatureSets.d.ts.map +1 -0
- package/lib/util/signingRoot.d.ts.map +1 -0
- package/lib/util/slot.d.ts +0 -1
- package/lib/util/slot.d.ts.map +1 -0
- package/lib/util/slot.js +3 -7
- package/lib/util/slot.js.map +1 -1
- package/lib/util/sszBytes.d.ts.map +1 -0
- package/lib/util/syncCommittee.d.ts.map +1 -0
- package/lib/util/targetUnslashedBalance.d.ts.map +1 -0
- package/lib/util/validator.d.ts.map +1 -0
- package/lib/util/weakSubjectivity.d.ts.map +1 -0
- package/package.json +13 -11
- package/src/block/externalData.ts +26 -0
- package/src/block/index.ts +81 -0
- package/src/block/initiateValidatorExit.ts +62 -0
- package/src/block/isValidIndexedAttestation.ts +70 -0
- package/src/block/processAttestationPhase0.ts +158 -0
- package/src/block/processAttestations.ts +25 -0
- package/src/block/processAttestationsAltair.ts +184 -0
- package/src/block/processAttesterSlashing.ts +59 -0
- package/src/block/processBlobKzgCommitments.ts +21 -0
- package/src/block/processBlockHeader.ts +54 -0
- package/src/block/processBlsToExecutionChange.ts +78 -0
- package/src/block/processConsolidationRequest.ts +147 -0
- package/src/block/processDeposit.ts +166 -0
- package/src/block/processDepositRequest.ts +19 -0
- package/src/block/processEth1Data.ts +86 -0
- package/src/block/processExecutionPayload.ts +84 -0
- package/src/block/processOperations.ts +83 -0
- package/src/block/processProposerSlashing.ts +66 -0
- package/src/block/processRandao.ts +27 -0
- package/src/block/processSyncCommittee.ts +117 -0
- package/src/block/processVoluntaryExit.ts +55 -0
- package/src/block/processWithdrawalRequest.ts +98 -0
- package/src/block/processWithdrawals.ts +207 -0
- package/src/block/slashValidator.ts +98 -0
- package/src/block/types.ts +9 -0
- package/src/cache/effectiveBalanceIncrements.ts +39 -0
- package/src/cache/epochCache.ts +1213 -0
- package/src/cache/epochTransitionCache.ts +542 -0
- package/src/cache/pubkeyCache.ts +33 -0
- package/src/cache/rewardCache.ts +19 -0
- package/src/cache/stateCache.ts +268 -0
- package/src/cache/syncCommitteeCache.ts +96 -0
- package/src/cache/types.ts +18 -0
- package/src/constants/constants.ts +12 -0
- package/src/constants/index.ts +1 -0
- package/src/epoch/computeUnrealizedCheckpoints.ts +55 -0
- package/src/epoch/getAttestationDeltas.ts +169 -0
- package/src/epoch/getRewardsAndPenalties.ts +137 -0
- package/src/epoch/index.ts +202 -0
- package/src/epoch/processEffectiveBalanceUpdates.ts +111 -0
- package/src/epoch/processEth1DataReset.ts +17 -0
- package/src/epoch/processHistoricalRootsUpdate.ts +25 -0
- package/src/epoch/processHistoricalSummariesUpdate.ts +23 -0
- package/src/epoch/processInactivityUpdates.ts +60 -0
- package/src/epoch/processJustificationAndFinalization.ts +90 -0
- package/src/epoch/processParticipationFlagUpdates.ts +27 -0
- package/src/epoch/processParticipationRecordUpdates.ts +14 -0
- package/src/epoch/processPendingAttestations.ts +75 -0
- package/src/epoch/processPendingConsolidations.ts +59 -0
- package/src/epoch/processPendingDeposits.ts +136 -0
- package/src/epoch/processProposerLookahead.ts +39 -0
- package/src/epoch/processRandaoMixesReset.ts +18 -0
- package/src/epoch/processRegistryUpdates.ts +65 -0
- package/src/epoch/processRewardsAndPenalties.ts +58 -0
- package/src/epoch/processSlashings.ts +97 -0
- package/src/epoch/processSlashingsReset.ts +20 -0
- package/src/epoch/processSyncCommitteeUpdates.ts +44 -0
- package/src/index.ts +67 -0
- package/src/metrics.ts +169 -0
- package/src/signatureSets/attesterSlashings.ts +39 -0
- package/src/signatureSets/blsToExecutionChange.ts +43 -0
- package/src/signatureSets/index.ts +73 -0
- package/src/signatureSets/indexedAttestation.ts +51 -0
- package/src/signatureSets/proposer.ts +47 -0
- package/src/signatureSets/proposerSlashings.ts +41 -0
- package/src/signatureSets/randao.ts +31 -0
- package/src/signatureSets/voluntaryExits.ts +44 -0
- package/src/slot/index.ts +32 -0
- package/src/slot/upgradeStateToAltair.ts +149 -0
- package/src/slot/upgradeStateToBellatrix.ts +63 -0
- package/src/slot/upgradeStateToCapella.ts +71 -0
- package/src/slot/upgradeStateToDeneb.ts +40 -0
- package/src/slot/upgradeStateToElectra.ts +126 -0
- package/src/slot/upgradeStateToFulu.ts +31 -0
- package/src/slot/upgradeStateToGloas.ts +29 -0
- package/src/stateTransition.ts +305 -0
- package/src/types.ts +26 -0
- package/src/util/aggregator.ts +33 -0
- package/src/util/altair.ts +13 -0
- package/src/util/array.ts +53 -0
- package/src/util/attestation.ts +36 -0
- package/src/util/attesterStatus.ts +83 -0
- package/src/util/balance.ts +83 -0
- package/src/util/blindedBlock.ts +145 -0
- package/src/util/blockRoot.ts +72 -0
- package/src/util/calculateCommitteeAssignments.ts +43 -0
- package/src/util/capella.ts +8 -0
- package/src/util/computeAnchorCheckpoint.ts +38 -0
- package/src/util/deposit.ts +22 -0
- package/src/util/domain.ts +31 -0
- package/src/util/electra.ts +68 -0
- package/src/util/epoch.ts +135 -0
- package/src/util/epochShuffling.ts +185 -0
- package/src/util/execution.ts +179 -0
- package/src/util/finality.ts +17 -0
- package/src/util/fulu.ts +43 -0
- package/src/util/genesis.ts +340 -0
- package/src/util/index.ts +29 -0
- package/src/util/interop.ts +22 -0
- package/src/util/loadState/findModifiedInactivityScores.ts +47 -0
- package/src/util/loadState/findModifiedValidators.ts +46 -0
- package/src/util/loadState/index.ts +2 -0
- package/src/util/loadState/loadState.ts +225 -0
- package/src/util/loadState/loadValidator.ts +77 -0
- package/src/util/rootCache.ts +37 -0
- package/src/util/seed.ts +381 -0
- package/src/util/shufflingDecisionRoot.ts +78 -0
- package/src/util/signatureSets.ts +65 -0
- package/src/util/signingRoot.ts +13 -0
- package/src/util/slot.ts +22 -0
- package/src/util/sszBytes.ts +52 -0
- package/src/util/syncCommittee.ts +69 -0
- package/src/util/targetUnslashedBalance.ts +30 -0
- package/src/util/validator.ts +105 -0
- package/src/util/weakSubjectivity.ts +186 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {EFFECTIVE_BALANCE_INCREMENT, TIMELY_TARGET_FLAG_INDEX} from "@lodestar/params";
|
|
2
|
+
import {Epoch, phase0} from "@lodestar/types";
|
|
3
|
+
import {isActiveValidator} from "./validator.js";
|
|
4
|
+
|
|
5
|
+
/** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */
|
|
6
|
+
const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* TODO: describe issue. Compute progressive target balances
|
|
10
|
+
* Compute balances from zero, note this state could be mid-epoch so target balances != 0
|
|
11
|
+
* @param participation from `state.previousEpochParticipation.getAll()`
|
|
12
|
+
* @param epoch either currentEpoch or previousEpoch
|
|
13
|
+
* @param validators from `state.validators.getAllReadonlyValues()`
|
|
14
|
+
*/
|
|
15
|
+
export function sumTargetUnslashedBalanceIncrements(
|
|
16
|
+
participation: number[],
|
|
17
|
+
epoch: Epoch,
|
|
18
|
+
validators: phase0.Validator[]
|
|
19
|
+
): number {
|
|
20
|
+
let total = 0;
|
|
21
|
+
for (let i = 0; i < participation.length; i++) {
|
|
22
|
+
if ((participation[i] & TIMELY_TARGET) === TIMELY_TARGET) {
|
|
23
|
+
const validator = validators[i];
|
|
24
|
+
if (isActiveValidator(validator, epoch) && !validator.slashed) {
|
|
25
|
+
total += Math.floor(validator.effectiveBalance / EFFECTIVE_BALANCE_INCREMENT);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return total;
|
|
30
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
+
import {
|
|
3
|
+
EFFECTIVE_BALANCE_INCREMENT,
|
|
4
|
+
ForkSeq,
|
|
5
|
+
MAX_EFFECTIVE_BALANCE_ELECTRA,
|
|
6
|
+
MIN_ACTIVATION_BALANCE,
|
|
7
|
+
} from "@lodestar/params";
|
|
8
|
+
import {Epoch, ValidatorIndex, phase0} from "@lodestar/types";
|
|
9
|
+
import {intDiv} from "@lodestar/utils";
|
|
10
|
+
import {BeaconStateAllForks, CachedBeaconStateElectra, EpochCache} from "../types.js";
|
|
11
|
+
import {hasCompoundingWithdrawalCredential} from "./electra.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check if [[validator]] is active
|
|
15
|
+
*/
|
|
16
|
+
export function isActiveValidator(validator: phase0.Validator, epoch: Epoch): boolean {
|
|
17
|
+
return validator.activationEpoch <= epoch && epoch < validator.exitEpoch;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if [[validator]] is slashable
|
|
22
|
+
*/
|
|
23
|
+
export function isSlashableValidator(validator: phase0.Validator, epoch: Epoch): boolean {
|
|
24
|
+
return !validator.slashed && validator.activationEpoch <= epoch && epoch < validator.withdrawableEpoch;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Return the sequence of active validator indices at [[epoch]].
|
|
29
|
+
*
|
|
30
|
+
* NAIVE - SLOW CODE 🐢
|
|
31
|
+
*/
|
|
32
|
+
export function getActiveValidatorIndices(state: BeaconStateAllForks, epoch: Epoch): Uint32Array {
|
|
33
|
+
const indices: ValidatorIndex[] = [];
|
|
34
|
+
|
|
35
|
+
const validatorsArr = state.validators.getAllReadonlyValues();
|
|
36
|
+
for (let i = 0; i < validatorsArr.length; i++) {
|
|
37
|
+
if (isActiveValidator(validatorsArr[i], epoch)) {
|
|
38
|
+
indices.push(i);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return new Uint32Array(indices);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getActivationChurnLimit(config: ChainForkConfig, fork: ForkSeq, activeValidatorCount: number): number {
|
|
46
|
+
if (fork >= ForkSeq.deneb) {
|
|
47
|
+
return Math.min(config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, getChurnLimit(config, activeValidatorCount));
|
|
48
|
+
}
|
|
49
|
+
return getChurnLimit(config, activeValidatorCount);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getChurnLimit(config: ChainForkConfig, activeValidatorCount: number): number {
|
|
53
|
+
return Math.max(config.MIN_PER_EPOCH_CHURN_LIMIT, intDiv(activeValidatorCount, config.CHURN_LIMIT_QUOTIENT));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get combined churn limit of activation-exit and consolidation
|
|
58
|
+
*/
|
|
59
|
+
export function getBalanceChurnLimit(
|
|
60
|
+
totalActiveBalanceIncrements: number,
|
|
61
|
+
churnLimitQuotient: number,
|
|
62
|
+
minPerEpochChurnLimit: number
|
|
63
|
+
): number {
|
|
64
|
+
const churnLimitByTotalActiveBalance = Math.floor(
|
|
65
|
+
(totalActiveBalanceIncrements / churnLimitQuotient) * EFFECTIVE_BALANCE_INCREMENT
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const churn = Math.max(churnLimitByTotalActiveBalance, minPerEpochChurnLimit);
|
|
69
|
+
|
|
70
|
+
return churn - (churn % EFFECTIVE_BALANCE_INCREMENT);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getBalanceChurnLimitFromCache(epochCtx: EpochCache): number {
|
|
74
|
+
return getBalanceChurnLimit(
|
|
75
|
+
epochCtx.totalActiveBalanceIncrements,
|
|
76
|
+
epochCtx.config.CHURN_LIMIT_QUOTIENT,
|
|
77
|
+
epochCtx.config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function getActivationExitChurnLimit(epochCtx: EpochCache): number {
|
|
82
|
+
return Math.min(epochCtx.config.MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT, getBalanceChurnLimitFromCache(epochCtx));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function getConsolidationChurnLimit(epochCtx: EpochCache): number {
|
|
86
|
+
return getBalanceChurnLimitFromCache(epochCtx) - getActivationExitChurnLimit(epochCtx);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function getMaxEffectiveBalance(withdrawalCredentials: Uint8Array): number {
|
|
90
|
+
// Compounding withdrawal credential only available since Electra
|
|
91
|
+
if (hasCompoundingWithdrawalCredential(withdrawalCredentials)) {
|
|
92
|
+
return MAX_EFFECTIVE_BALANCE_ELECTRA;
|
|
93
|
+
}
|
|
94
|
+
return MIN_ACTIVATION_BALANCE;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function getPendingBalanceToWithdraw(state: CachedBeaconStateElectra, validatorIndex: ValidatorIndex): number {
|
|
98
|
+
let total = 0;
|
|
99
|
+
for (const item of state.pendingPartialWithdrawals.getAllReadonly()) {
|
|
100
|
+
if (item.validatorIndex === validatorIndex) {
|
|
101
|
+
total += Number(item.amount);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return total;
|
|
105
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {BeaconConfig, ChainForkConfig} from "@lodestar/config";
|
|
2
|
+
import {
|
|
3
|
+
EFFECTIVE_BALANCE_INCREMENT,
|
|
4
|
+
MAX_DEPOSITS,
|
|
5
|
+
MAX_EFFECTIVE_BALANCE,
|
|
6
|
+
SLOTS_PER_EPOCH,
|
|
7
|
+
isForkPostElectra,
|
|
8
|
+
} from "@lodestar/params";
|
|
9
|
+
import {Epoch, Root, ssz} from "@lodestar/types";
|
|
10
|
+
import {Checkpoint} from "@lodestar/types/phase0";
|
|
11
|
+
import {toRootHex} from "@lodestar/utils";
|
|
12
|
+
import {ZERO_HASH} from "../constants/constants.js";
|
|
13
|
+
import {BeaconStateAllForks, CachedBeaconStateAllForks} from "../types.js";
|
|
14
|
+
import {computeCheckpointEpochAtStateSlot, computeEpochAtSlot, getCurrentEpoch} from "./epoch.js";
|
|
15
|
+
import {getCurrentSlot} from "./slot.js";
|
|
16
|
+
import {
|
|
17
|
+
getActiveValidatorIndices,
|
|
18
|
+
getBalanceChurnLimit,
|
|
19
|
+
getBalanceChurnLimitFromCache,
|
|
20
|
+
getChurnLimit,
|
|
21
|
+
} from "./validator.js";
|
|
22
|
+
|
|
23
|
+
export const ETH_TO_GWEI = 10 ** 9;
|
|
24
|
+
const SAFETY_DECAY = 10;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns the epoch of the latest weak subjectivity checkpoint for the given
|
|
28
|
+
`state` and `safetyDecay`. The default `safetyDecay` used should be 10% (= 0.1)
|
|
29
|
+
*/
|
|
30
|
+
export function getLatestWeakSubjectivityCheckpointEpoch(
|
|
31
|
+
config: ChainForkConfig,
|
|
32
|
+
state: CachedBeaconStateAllForks
|
|
33
|
+
): Epoch {
|
|
34
|
+
return state.epochCtx.epoch - computeWeakSubjectivityPeriodCachedState(config, state);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
Returns the weak subjectivity period for the current `state`.
|
|
39
|
+
This computation takes into account the effect of:
|
|
40
|
+
- validator set churn (bounded by `get_validator_churn_limit()` per epoch), and
|
|
41
|
+
- validator balance top-ups (bounded by `MAX_DEPOSITS * SLOTS_PER_EPOCH` per epoch).
|
|
42
|
+
A detailed calculation can be found at:
|
|
43
|
+
https://github.com/runtimeverification/beacon-chain-verification/blob/master/weak-subjectivity/weak-subjectivity-analysis.pdf
|
|
44
|
+
*/
|
|
45
|
+
export function computeWeakSubjectivityPeriodCachedState(
|
|
46
|
+
config: ChainForkConfig,
|
|
47
|
+
state: CachedBeaconStateAllForks
|
|
48
|
+
): number {
|
|
49
|
+
const activeValidatorCount = state.epochCtx.currentShuffling.activeIndices.length;
|
|
50
|
+
const fork = state.config.getForkName(state.slot);
|
|
51
|
+
|
|
52
|
+
return isForkPostElectra(fork)
|
|
53
|
+
? computeWeakSubjectivityPeriodFromConstituentsElectra(
|
|
54
|
+
state.epochCtx.totalActiveBalanceIncrements,
|
|
55
|
+
getBalanceChurnLimitFromCache(state.epochCtx),
|
|
56
|
+
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
57
|
+
)
|
|
58
|
+
: computeWeakSubjectivityPeriodFromConstituentsPhase0(
|
|
59
|
+
activeValidatorCount,
|
|
60
|
+
state.epochCtx.totalActiveBalanceIncrements,
|
|
61
|
+
getChurnLimit(config, activeValidatorCount),
|
|
62
|
+
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Same to computeWeakSubjectivityPeriodCachedState but for normal state
|
|
68
|
+
* This is called only 1 time at app startup so it's ok to calculate totalActiveBalanceIncrements manually
|
|
69
|
+
*/
|
|
70
|
+
export function computeWeakSubjectivityPeriod(config: ChainForkConfig, state: BeaconStateAllForks): number {
|
|
71
|
+
const activeIndices = getActiveValidatorIndices(state, getCurrentEpoch(state));
|
|
72
|
+
const validators = state.validators.getAllReadonlyValues();
|
|
73
|
+
const fork = config.getForkName(state.slot);
|
|
74
|
+
|
|
75
|
+
let totalActiveBalanceIncrements = 0;
|
|
76
|
+
for (const index of activeIndices) {
|
|
77
|
+
totalActiveBalanceIncrements += Math.floor(validators[index].effectiveBalance / EFFECTIVE_BALANCE_INCREMENT);
|
|
78
|
+
}
|
|
79
|
+
if (totalActiveBalanceIncrements <= 1) {
|
|
80
|
+
totalActiveBalanceIncrements = 1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return isForkPostElectra(fork)
|
|
84
|
+
? computeWeakSubjectivityPeriodFromConstituentsElectra(
|
|
85
|
+
totalActiveBalanceIncrements,
|
|
86
|
+
getBalanceChurnLimit(
|
|
87
|
+
totalActiveBalanceIncrements,
|
|
88
|
+
config.CHURN_LIMIT_QUOTIENT,
|
|
89
|
+
config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
|
|
90
|
+
),
|
|
91
|
+
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
92
|
+
)
|
|
93
|
+
: computeWeakSubjectivityPeriodFromConstituentsPhase0(
|
|
94
|
+
activeIndices.length,
|
|
95
|
+
totalActiveBalanceIncrements,
|
|
96
|
+
getChurnLimit(config, activeIndices.length),
|
|
97
|
+
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function computeWeakSubjectivityPeriodFromConstituentsPhase0(
|
|
102
|
+
activeValidatorCount: number,
|
|
103
|
+
totalBalanceByIncrement: number,
|
|
104
|
+
churnLimit: number,
|
|
105
|
+
minWithdrawabilityDelay: number
|
|
106
|
+
): number {
|
|
107
|
+
const N = activeValidatorCount;
|
|
108
|
+
// originally const t = Number(totalBalance / BigInt(N) / BigInt(ETH_TO_GWEI));
|
|
109
|
+
// totalBalanceByIncrement = totalBalance / MAX_EFFECTIVE_BALANCE and MAX_EFFECTIVE_BALANCE = ETH_TO_GWEI atm
|
|
110
|
+
// we need to change this calculation just in case MAX_EFFECTIVE_BALANCE != ETH_TO_GWEI
|
|
111
|
+
const t = Math.floor(totalBalanceByIncrement / N);
|
|
112
|
+
const T = MAX_EFFECTIVE_BALANCE / ETH_TO_GWEI;
|
|
113
|
+
const delta = churnLimit;
|
|
114
|
+
const Delta = MAX_DEPOSITS * SLOTS_PER_EPOCH;
|
|
115
|
+
const D = SAFETY_DECAY;
|
|
116
|
+
|
|
117
|
+
let wsPeriod = minWithdrawabilityDelay;
|
|
118
|
+
if (T * (200 + 3 * D) < t * (200 + 12 * D)) {
|
|
119
|
+
const epochsForValidatorSetChurn = Math.floor(
|
|
120
|
+
(N * (t * (200 + 12 * D) - T * (200 + 3 * D))) / (600 * delta * (2 * t + T))
|
|
121
|
+
);
|
|
122
|
+
const epochsForBalanceTopUps = Math.floor((N * (200 + 3 * D)) / (600 * Delta));
|
|
123
|
+
wsPeriod +=
|
|
124
|
+
epochsForValidatorSetChurn > epochsForBalanceTopUps ? epochsForValidatorSetChurn : epochsForBalanceTopUps;
|
|
125
|
+
} else {
|
|
126
|
+
wsPeriod += Math.floor((3 * N * D * t) / (200 * Delta * (T - t)));
|
|
127
|
+
}
|
|
128
|
+
return wsPeriod;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function computeWeakSubjectivityPeriodFromConstituentsElectra(
|
|
132
|
+
totalBalanceByIncrement: number,
|
|
133
|
+
// Note this is not the same as churnLimit in `computeWeakSubjectivityPeriodFromConstituentsPhase0`
|
|
134
|
+
balanceChurnLimit: number,
|
|
135
|
+
minWithdrawabilityDelay: number
|
|
136
|
+
): number {
|
|
137
|
+
// Keep t as increment for now. Multiply final result by EFFECTIVE_BALANCE_INCREMENT
|
|
138
|
+
const t = totalBalanceByIncrement;
|
|
139
|
+
const delta = balanceChurnLimit;
|
|
140
|
+
const epochsForValidatorSetChurn = Math.floor(((SAFETY_DECAY * t) / (2 * delta * 100)) * EFFECTIVE_BALANCE_INCREMENT);
|
|
141
|
+
|
|
142
|
+
return minWithdrawabilityDelay + epochsForValidatorSetChurn;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function getLatestBlockRoot(state: BeaconStateAllForks): Root {
|
|
146
|
+
const header = ssz.phase0.BeaconBlockHeader.clone(state.latestBlockHeader);
|
|
147
|
+
if (ssz.Root.equals(header.stateRoot, ZERO_HASH)) {
|
|
148
|
+
header.stateRoot = state.hashTreeRoot();
|
|
149
|
+
}
|
|
150
|
+
return ssz.phase0.BeaconBlockHeader.hashTreeRoot(header);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function isWithinWeakSubjectivityPeriod(
|
|
154
|
+
config: BeaconConfig,
|
|
155
|
+
wsState: BeaconStateAllForks,
|
|
156
|
+
wsCheckpoint: Checkpoint
|
|
157
|
+
): boolean {
|
|
158
|
+
try {
|
|
159
|
+
ensureWithinWeakSubjectivityPeriod(config, wsState, wsCheckpoint);
|
|
160
|
+
return true;
|
|
161
|
+
} catch (_) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function ensureWithinWeakSubjectivityPeriod(
|
|
167
|
+
config: BeaconConfig,
|
|
168
|
+
wsState: BeaconStateAllForks,
|
|
169
|
+
wsCheckpoint: Checkpoint
|
|
170
|
+
): void {
|
|
171
|
+
const wsStateEpoch = computeCheckpointEpochAtStateSlot(wsState.slot);
|
|
172
|
+
const blockRoot = getLatestBlockRoot(wsState);
|
|
173
|
+
if (!ssz.Root.equals(blockRoot, wsCheckpoint.root)) {
|
|
174
|
+
throw new Error(`Roots do not match. expected=${toRootHex(wsCheckpoint.root)}, actual=${toRootHex(blockRoot)}`);
|
|
175
|
+
}
|
|
176
|
+
if (!ssz.Epoch.equals(wsStateEpoch, wsCheckpoint.epoch)) {
|
|
177
|
+
throw new Error(`Epochs do not match. expected=${wsCheckpoint.epoch}, actual=${wsStateEpoch}`);
|
|
178
|
+
}
|
|
179
|
+
const wsPeriod = computeWeakSubjectivityPeriod(config, wsState);
|
|
180
|
+
const clockEpoch = computeEpochAtSlot(getCurrentSlot(config, wsState.genesisTime));
|
|
181
|
+
if (clockEpoch > wsStateEpoch + wsPeriod) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`The downloaded state with epoch ${wsStateEpoch} is not within weak subjectivity period of ${wsPeriod} from the current epoch ${clockEpoch}. Please verify your checkpoint source`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|