@lodestar/state-transition 1.35.0-dev.955e9f89ed → 1.35.0-dev.98d359db41
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/README.md +1 -1
- package/lib/block/externalData.d.ts.map +1 -0
- package/lib/block/index.d.ts +2 -2
- package/lib/block/index.d.ts.map +1 -0
- package/lib/block/index.js +2 -2
- package/lib/block/index.js.map +1 -1
- 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/processAttestationPhase0.js +1 -2
- package/lib/block/processAttestationPhase0.js.map +1 -1
- package/lib/block/processAttestations.d.ts.map +1 -0
- package/lib/block/processAttestationsAltair.d.ts +1 -1
- package/lib/block/processAttestationsAltair.d.ts.map +1 -0
- package/lib/block/processAttestationsAltair.js +1 -1
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processAttesterSlashing.d.ts.map +1 -0
- package/lib/block/processAttesterSlashing.js.map +1 -1
- 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/processBlsToExecutionChange.js.map +1 -1
- package/lib/block/processConsolidationRequest.d.ts.map +1 -0
- package/lib/block/processConsolidationRequest.js.map +1 -1
- package/lib/block/processDeposit.d.ts +2 -2
- package/lib/block/processDeposit.d.ts.map +1 -0
- package/lib/block/processDeposit.js +1 -1
- package/lib/block/processDeposit.js.map +1 -1
- package/lib/block/processDepositRequest.d.ts.map +1 -0
- package/lib/block/processDepositRequest.js.map +1 -1
- package/lib/block/processEth1Data.d.ts.map +1 -0
- package/lib/block/processExecutionPayload.d.ts.map +1 -0
- package/lib/block/processOperations.d.ts.map +1 -0
- package/lib/block/processOperations.js.map +1 -1
- 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/processSyncCommittee.js +1 -2
- package/lib/block/processSyncCommittee.js.map +1 -1
- package/lib/block/processVoluntaryExit.d.ts.map +1 -0
- package/lib/block/processWithdrawalRequest.d.ts.map +1 -0
- package/lib/block/processWithdrawalRequest.js.map +1 -1
- package/lib/block/processWithdrawals.d.ts.map +1 -0
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/block/slashValidator.d.ts.map +1 -0
- package/lib/block/slashValidator.js.map +1 -1
- 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/epochCache.js +130 -0
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/cache/epochTransitionCache.d.ts.map +1 -0
- package/lib/cache/epochTransitionCache.js.map +1 -1
- 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.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/index.js.map +1 -1
- 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/processSlashings.js.map +1 -1
- package/lib/epoch/processSlashingsReset.d.ts.map +1 -0
- package/lib/epoch/processSyncCommitteeUpdates.d.ts.map +1 -0
- package/lib/index.d.ts +17 -17
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +16 -16
- package/lib/index.js.map +1 -1
- 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/blsToExecutionChange.js.map +1 -1
- package/lib/signatureSets/index.d.ts +1 -1
- package/lib/signatureSets/index.d.ts.map +1 -0
- package/lib/signatureSets/index.js +1 -1
- package/lib/signatureSets/index.js.map +1 -1
- 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 +1 -2
- package/lib/slot/upgradeStateToDeneb.d.ts.map +1 -0
- package/lib/slot/upgradeStateToDeneb.js.map +1 -1
- 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/slot/upgradeStateToGloas.js +2 -2
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/stateTransition.d.ts.map +1 -0
- package/lib/types.d.ts +2 -2
- 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.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.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 +4 -4
- package/lib/util/genesis.js.map +1 -1
- package/lib/util/index.d.ts +5 -5
- package/lib/util/index.d.ts.map +1 -0
- package/lib/util/index.js +5 -5
- package/lib/util/index.js.map +1 -1
- package/lib/util/interop.d.ts.map +1 -0
- package/lib/util/interop.js +1 -1
- package/lib/util/interop.js.map +1 -1
- 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/rootCache.js +5 -2
- package/lib/util/rootCache.js.map +1 -1
- package/lib/util/seed.d.ts.map +1 -0
- package/lib/util/seed.js +1 -2
- package/lib/util/seed.js.map +1 -1
- 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.map +1 -0
- 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/lib/util/weakSubjectivity.js.map +1 -1
- 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 +144 -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 +177 -0
- package/src/util/finality.ts +17 -0
- package/src/util/fulu.ts +43 -0
- package/src/util/genesis.ts +343 -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 +27 -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,343 @@
|
|
|
1
|
+
import {CompositeViewDU, ListCompositeType} from "@chainsafe/ssz";
|
|
2
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
+
import {
|
|
4
|
+
EFFECTIVE_BALANCE_INCREMENT,
|
|
5
|
+
EPOCHS_PER_HISTORICAL_VECTOR,
|
|
6
|
+
ForkName,
|
|
7
|
+
ForkSeq,
|
|
8
|
+
GENESIS_EPOCH,
|
|
9
|
+
GENESIS_SLOT,
|
|
10
|
+
MAX_EFFECTIVE_BALANCE,
|
|
11
|
+
UNSET_DEPOSIT_REQUESTS_START_INDEX,
|
|
12
|
+
} from "@lodestar/params";
|
|
13
|
+
import {Bytes32, Root, TimeSeconds, phase0, ssz} from "@lodestar/types";
|
|
14
|
+
import {processDeposit} from "../block/processDeposit.js";
|
|
15
|
+
import {EpochCacheImmutableData} from "../cache/epochCache.js";
|
|
16
|
+
import {createCachedBeaconState} from "../cache/stateCache.js";
|
|
17
|
+
import {increaseBalance} from "../index.js";
|
|
18
|
+
import {BeaconStateAllForks, CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js";
|
|
19
|
+
import {newFilledArray} from "./array.js";
|
|
20
|
+
import {getTemporaryBlockHeader} from "./blockRoot.js";
|
|
21
|
+
import {computeEpochAtSlot} from "./epoch.js";
|
|
22
|
+
import {getNextSyncCommittee} from "./syncCommittee.js";
|
|
23
|
+
import {getActiveValidatorIndices, getMaxEffectiveBalance} from "./validator.js";
|
|
24
|
+
|
|
25
|
+
type DepositDataRootListType = ListCompositeType<typeof ssz.Root>;
|
|
26
|
+
type DepositDataRootViewDU = CompositeViewDU<DepositDataRootListType>;
|
|
27
|
+
|
|
28
|
+
// TODO: Refactor to work with non-phase0 genesis state
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Check if it's valid genesis state.
|
|
32
|
+
* @param config
|
|
33
|
+
* @param state
|
|
34
|
+
*/
|
|
35
|
+
export function isValidGenesisState(config: ChainForkConfig, state: BeaconStateAllForks): boolean {
|
|
36
|
+
return state.genesisTime >= config.MIN_GENESIS_TIME && isValidGenesisValidators(config, state);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if it's valid genesis validators state.
|
|
41
|
+
* @param config
|
|
42
|
+
* @param state
|
|
43
|
+
*/
|
|
44
|
+
export function isValidGenesisValidators(config: ChainForkConfig, state: BeaconStateAllForks): boolean {
|
|
45
|
+
return (
|
|
46
|
+
getActiveValidatorIndices(state, computeEpochAtSlot(GENESIS_SLOT)).length >=
|
|
47
|
+
config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Generate the initial beacon chain state.
|
|
53
|
+
*
|
|
54
|
+
* SLOW CODE - 🐢
|
|
55
|
+
*/
|
|
56
|
+
export function getGenesisBeaconState(
|
|
57
|
+
config: ChainForkConfig,
|
|
58
|
+
genesisEth1Data: phase0.Eth1Data,
|
|
59
|
+
latestBlockHeader: phase0.BeaconBlockHeader
|
|
60
|
+
): BeaconStateAllForks {
|
|
61
|
+
// Seed RANDAO with Eth1 entropy
|
|
62
|
+
const randaoMixes = newFilledArray(EPOCHS_PER_HISTORICAL_VECTOR, genesisEth1Data.blockHash);
|
|
63
|
+
|
|
64
|
+
const beaconStateType = config.getForkTypes(GENESIS_SLOT).BeaconState;
|
|
65
|
+
const state = beaconStateType.defaultViewDU();
|
|
66
|
+
|
|
67
|
+
// MISC
|
|
68
|
+
state.slot = GENESIS_SLOT;
|
|
69
|
+
const version = config.getForkVersion(GENESIS_SLOT);
|
|
70
|
+
const forkName = config.getForkName(GENESIS_SLOT);
|
|
71
|
+
const allForkNames = Object.keys(config.forks) as ForkName[];
|
|
72
|
+
const forkIndex = allForkNames.findIndex((item) => item === forkName);
|
|
73
|
+
const previousForkIndex = Math.max(0, forkIndex - 1);
|
|
74
|
+
const previousForkName = allForkNames[previousForkIndex];
|
|
75
|
+
const previousFork = config.forks[previousForkName];
|
|
76
|
+
|
|
77
|
+
// the altair genesis spec test requires previous version to be phase0 although ALTAIR_FORK_EPOCH=0
|
|
78
|
+
state.fork = ssz.phase0.Fork.toViewDU({
|
|
79
|
+
previousVersion: previousFork.version,
|
|
80
|
+
currentVersion: version,
|
|
81
|
+
epoch: computeEpochAtSlot(GENESIS_SLOT),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Validator registry
|
|
85
|
+
|
|
86
|
+
// Randomness and committees
|
|
87
|
+
state.latestBlockHeader = ssz.phase0.BeaconBlockHeader.toViewDU(latestBlockHeader);
|
|
88
|
+
|
|
89
|
+
// Ethereum 1.0 chain data
|
|
90
|
+
state.eth1Data = ssz.phase0.Eth1Data.toViewDU(genesisEth1Data);
|
|
91
|
+
state.randaoMixes = ssz.phase0.RandaoMixes.toViewDU(randaoMixes);
|
|
92
|
+
|
|
93
|
+
return state;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Apply eth1 block hash to state.
|
|
98
|
+
* @param config ChainForkConfig
|
|
99
|
+
* @param state BeaconState
|
|
100
|
+
* @param eth1BlockHash eth1 block hash
|
|
101
|
+
*/
|
|
102
|
+
export function applyEth1BlockHash(state: CachedBeaconStateAllForks, eth1BlockHash: Bytes32): void {
|
|
103
|
+
state.eth1Data.blockHash = eth1BlockHash;
|
|
104
|
+
state.randaoMixes = ssz.phase0.RandaoMixes.toViewDU(newFilledArray(EPOCHS_PER_HISTORICAL_VECTOR, eth1BlockHash));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Apply eth1 block timestamp to state.
|
|
109
|
+
* @param config IBeaconState
|
|
110
|
+
* @param state BeaconState
|
|
111
|
+
* @param eth1Timestamp eth1 block timestamp
|
|
112
|
+
*/
|
|
113
|
+
export function applyTimestamp(config: ChainForkConfig, state: CachedBeaconStateAllForks, eth1Timestamp: number): void {
|
|
114
|
+
state.genesisTime = eth1Timestamp + config.GENESIS_DELAY;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Apply deposits to state.
|
|
119
|
+
* For spec test, fullDepositDataRootList is undefined.
|
|
120
|
+
* For genesis builder, fullDepositDataRootList is full list of deposit data root from index 0.
|
|
121
|
+
*
|
|
122
|
+
* SLOW CODE - 🐢
|
|
123
|
+
*
|
|
124
|
+
* @param config ChainForkConfig
|
|
125
|
+
* @param state BeaconState
|
|
126
|
+
* @param newDeposits new deposits
|
|
127
|
+
* @param fullDepositDataRootList full list of deposit data root from index 0
|
|
128
|
+
* @returns active validator indices
|
|
129
|
+
*/
|
|
130
|
+
export function applyDeposits(
|
|
131
|
+
config: ChainForkConfig,
|
|
132
|
+
state: CachedBeaconStateAllForks,
|
|
133
|
+
newDeposits: phase0.Deposit[],
|
|
134
|
+
fullDepositDataRootList?: DepositDataRootViewDU
|
|
135
|
+
): {activatedValidatorCount: number} {
|
|
136
|
+
const fork = config.getForkSeq(state.slot);
|
|
137
|
+
const depositDataRootList: Root[] = [];
|
|
138
|
+
|
|
139
|
+
const fullDepositDataRootArr = fullDepositDataRootList ? fullDepositDataRootList.getAllReadonlyValues() : null;
|
|
140
|
+
|
|
141
|
+
if (fullDepositDataRootArr) {
|
|
142
|
+
const depositCount = state.eth1Data.depositCount;
|
|
143
|
+
for (let index = 0; index < depositCount; index++) {
|
|
144
|
+
depositDataRootList.push(fullDepositDataRootArr[index]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const initDepositCount = depositDataRootList.length;
|
|
149
|
+
const depositDatas = fullDepositDataRootList ? null : newDeposits.map((deposit) => deposit.data);
|
|
150
|
+
const {DepositData, DepositDataRootList} = ssz.phase0;
|
|
151
|
+
|
|
152
|
+
for (const [index, deposit] of newDeposits.entries()) {
|
|
153
|
+
if (fullDepositDataRootArr) {
|
|
154
|
+
depositDataRootList.push(fullDepositDataRootArr[index + initDepositCount]);
|
|
155
|
+
state.eth1Data.depositRoot = DepositDataRootList.hashTreeRoot(depositDataRootList);
|
|
156
|
+
} else if (depositDatas) {
|
|
157
|
+
const depositDataList = depositDatas.slice(0, index + 1);
|
|
158
|
+
state.eth1Data.depositRoot = DepositDataRootList.hashTreeRoot(
|
|
159
|
+
depositDataList.map((d) => DepositData.hashTreeRoot(d))
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
state.eth1Data.depositCount += 1;
|
|
164
|
+
|
|
165
|
+
const fork = config.getForkSeq(GENESIS_SLOT);
|
|
166
|
+
processDeposit(fork, state, deposit);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Process deposit balance updates
|
|
170
|
+
if (fork >= ForkSeq.electra) {
|
|
171
|
+
const stateElectra = state as CachedBeaconStateElectra;
|
|
172
|
+
stateElectra.commit();
|
|
173
|
+
for (const {pubkey, amount} of stateElectra.pendingDeposits.getAllReadonly()) {
|
|
174
|
+
const validatorIndex = state.epochCtx.getValidatorIndex(pubkey);
|
|
175
|
+
if (validatorIndex === null) {
|
|
176
|
+
// Should not happen if the gensis state is correct
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
increaseBalance(state, validatorIndex, amount);
|
|
180
|
+
}
|
|
181
|
+
stateElectra.pendingDeposits = ssz.electra.PendingDeposits.defaultViewDU();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Process activations
|
|
185
|
+
const {epochCtx} = state;
|
|
186
|
+
const balancesArr = state.balances.getAll();
|
|
187
|
+
const validatorCount = state.validators.length;
|
|
188
|
+
let activatedValidatorCount = 0;
|
|
189
|
+
|
|
190
|
+
for (let i = 0; i < validatorCount; i++) {
|
|
191
|
+
// For the case if effective balance has to be updated, get a mutable view
|
|
192
|
+
const validator = state.validators.get(i);
|
|
193
|
+
|
|
194
|
+
// Already active, ignore
|
|
195
|
+
if (validator.activationEpoch === GENESIS_EPOCH) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const balance = balancesArr[i];
|
|
200
|
+
const effectiveBalance = Math.min(
|
|
201
|
+
balance - (balance % EFFECTIVE_BALANCE_INCREMENT),
|
|
202
|
+
getMaxEffectiveBalance(validator.withdrawalCredentials)
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
validator.effectiveBalance = effectiveBalance;
|
|
206
|
+
epochCtx.effectiveBalanceIncrementsSet(i, effectiveBalance);
|
|
207
|
+
|
|
208
|
+
if (validator.effectiveBalance >= MAX_EFFECTIVE_BALANCE) {
|
|
209
|
+
validator.activationEligibilityEpoch = GENESIS_EPOCH;
|
|
210
|
+
validator.activationEpoch = GENESIS_EPOCH;
|
|
211
|
+
activatedValidatorCount++;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Set genesis validators root for domain separation and chain versioning
|
|
216
|
+
// .hashTreeRoot() automatically commits()
|
|
217
|
+
state.genesisValidatorsRoot = state.validators.hashTreeRoot();
|
|
218
|
+
|
|
219
|
+
return {activatedValidatorCount};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Mainly used for spec test.
|
|
224
|
+
*
|
|
225
|
+
* SLOW CODE - 🐢
|
|
226
|
+
*/
|
|
227
|
+
export function initializeBeaconStateFromEth1(
|
|
228
|
+
config: ChainForkConfig,
|
|
229
|
+
immutableData: EpochCacheImmutableData,
|
|
230
|
+
eth1BlockHash: Bytes32,
|
|
231
|
+
eth1Timestamp: TimeSeconds,
|
|
232
|
+
deposits: phase0.Deposit[],
|
|
233
|
+
fullDepositDataRootList?: DepositDataRootViewDU,
|
|
234
|
+
executionPayloadHeader?: CompositeViewDU<
|
|
235
|
+
| typeof ssz.bellatrix.ExecutionPayloadHeader
|
|
236
|
+
| typeof ssz.capella.ExecutionPayloadHeader
|
|
237
|
+
| typeof ssz.deneb.ExecutionPayloadHeader
|
|
238
|
+
| typeof ssz.electra.ExecutionPayloadHeader
|
|
239
|
+
>
|
|
240
|
+
): CachedBeaconStateAllForks {
|
|
241
|
+
const stateView = getGenesisBeaconState(
|
|
242
|
+
// CachedBeaconcState is used for convinience only, we return BeaconStateAllForks anyway
|
|
243
|
+
// so it's safe to do a cast here, we can't use get domain until we have genesisValidatorRoot
|
|
244
|
+
config,
|
|
245
|
+
ssz.phase0.Eth1Data.defaultValue(),
|
|
246
|
+
getTemporaryBlockHeader(config, config.getForkTypes(GENESIS_SLOT).BeaconBlock.defaultValue())
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const fork = config.getForkSeq(GENESIS_SLOT);
|
|
250
|
+
|
|
251
|
+
// We need a CachedBeaconState to run processDeposit() which uses various caches.
|
|
252
|
+
// However at this point the state's syncCommittees are not known.
|
|
253
|
+
// This function can be called by:
|
|
254
|
+
// - 1. genesis spec tests: Don't care about the committee cache
|
|
255
|
+
// - 2. genesis builder: Only supports starting from genesis at phase0 fork
|
|
256
|
+
// - 3. interop state: Only supports starting from genesis at phase0 fork
|
|
257
|
+
// So it's okay to skip syncing the sync committee cache here and expect it to be
|
|
258
|
+
// populated latter when the altair fork happens for cases 2, 3.
|
|
259
|
+
const state = createCachedBeaconState(stateView, immutableData, {skipSyncCommitteeCache: true});
|
|
260
|
+
|
|
261
|
+
applyTimestamp(config, state, eth1Timestamp);
|
|
262
|
+
applyEth1BlockHash(state, eth1BlockHash);
|
|
263
|
+
|
|
264
|
+
// Process deposits
|
|
265
|
+
applyDeposits(config, state, deposits, fullDepositDataRootList);
|
|
266
|
+
|
|
267
|
+
// Commit before reading all validators in `getActiveValidatorIndices()`
|
|
268
|
+
state.commit();
|
|
269
|
+
const activeValidatorIndices = getActiveValidatorIndices(state, computeEpochAtSlot(GENESIS_SLOT));
|
|
270
|
+
|
|
271
|
+
if (fork >= ForkSeq.altair) {
|
|
272
|
+
const {syncCommittee} = getNextSyncCommittee(
|
|
273
|
+
fork,
|
|
274
|
+
state,
|
|
275
|
+
activeValidatorIndices,
|
|
276
|
+
state.epochCtx.effectiveBalanceIncrements
|
|
277
|
+
);
|
|
278
|
+
const stateAltair = state as CompositeViewDU<typeof ssz.altair.BeaconState>;
|
|
279
|
+
stateAltair.fork.previousVersion = config.ALTAIR_FORK_VERSION;
|
|
280
|
+
stateAltair.fork.currentVersion = config.ALTAIR_FORK_VERSION;
|
|
281
|
+
stateAltair.currentSyncCommittee = ssz.altair.SyncCommittee.toViewDU(syncCommittee);
|
|
282
|
+
stateAltair.nextSyncCommittee = ssz.altair.SyncCommittee.toViewDU(syncCommittee);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (fork >= ForkSeq.bellatrix) {
|
|
286
|
+
const stateBellatrix = state as CompositeViewDU<typeof ssz.bellatrix.BeaconState>;
|
|
287
|
+
stateBellatrix.fork.previousVersion = config.BELLATRIX_FORK_VERSION;
|
|
288
|
+
stateBellatrix.fork.currentVersion = config.BELLATRIX_FORK_VERSION;
|
|
289
|
+
stateBellatrix.latestExecutionPayloadHeader =
|
|
290
|
+
(executionPayloadHeader as CompositeViewDU<typeof ssz.bellatrix.ExecutionPayloadHeader>) ??
|
|
291
|
+
ssz.bellatrix.ExecutionPayloadHeader.defaultViewDU();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (fork >= ForkSeq.capella) {
|
|
295
|
+
const stateCapella = state as CompositeViewDU<typeof ssz.capella.BeaconState>;
|
|
296
|
+
stateCapella.fork.previousVersion = config.CAPELLA_FORK_VERSION;
|
|
297
|
+
stateCapella.fork.currentVersion = config.CAPELLA_FORK_VERSION;
|
|
298
|
+
stateCapella.latestExecutionPayloadHeader =
|
|
299
|
+
(executionPayloadHeader as CompositeViewDU<typeof ssz.capella.ExecutionPayloadHeader>) ??
|
|
300
|
+
ssz.capella.ExecutionPayloadHeader.defaultViewDU();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (fork >= ForkSeq.deneb) {
|
|
304
|
+
const stateDeneb = state as CompositeViewDU<typeof ssz.deneb.BeaconState>;
|
|
305
|
+
stateDeneb.fork.previousVersion = config.DENEB_FORK_VERSION;
|
|
306
|
+
stateDeneb.fork.currentVersion = config.DENEB_FORK_VERSION;
|
|
307
|
+
stateDeneb.latestExecutionPayloadHeader =
|
|
308
|
+
(executionPayloadHeader as CompositeViewDU<typeof ssz.deneb.ExecutionPayloadHeader>) ??
|
|
309
|
+
ssz.deneb.ExecutionPayloadHeader.defaultViewDU();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (fork >= ForkSeq.electra) {
|
|
313
|
+
const stateElectra = state as CompositeViewDU<typeof ssz.electra.BeaconState>;
|
|
314
|
+
stateElectra.fork.previousVersion = config.ELECTRA_FORK_VERSION;
|
|
315
|
+
stateElectra.fork.currentVersion = config.ELECTRA_FORK_VERSION;
|
|
316
|
+
stateElectra.latestExecutionPayloadHeader =
|
|
317
|
+
(executionPayloadHeader as CompositeViewDU<typeof ssz.electra.ExecutionPayloadHeader>) ??
|
|
318
|
+
ssz.electra.ExecutionPayloadHeader.defaultViewDU();
|
|
319
|
+
stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_REQUESTS_START_INDEX;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (fork >= ForkSeq.fulu) {
|
|
323
|
+
const stateFulu = state as CompositeViewDU<typeof ssz.fulu.BeaconState>;
|
|
324
|
+
stateFulu.fork.previousVersion = config.FULU_FORK_VERSION;
|
|
325
|
+
stateFulu.fork.currentVersion = config.FULU_FORK_VERSION;
|
|
326
|
+
stateFulu.latestExecutionPayloadHeader =
|
|
327
|
+
(executionPayloadHeader as CompositeViewDU<typeof ssz.fulu.ExecutionPayloadHeader>) ??
|
|
328
|
+
ssz.fulu.ExecutionPayloadHeader.defaultViewDU();
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (fork >= ForkSeq.gloas) {
|
|
332
|
+
const stateGloas = state as CompositeViewDU<typeof ssz.gloas.BeaconState>;
|
|
333
|
+
stateGloas.fork.previousVersion = config.GLOAS_FORK_VERSION;
|
|
334
|
+
stateGloas.fork.currentVersion = config.GLOAS_FORK_VERSION;
|
|
335
|
+
stateGloas.latestExecutionPayloadHeader =
|
|
336
|
+
(executionPayloadHeader as CompositeViewDU<typeof ssz.gloas.ExecutionPayloadHeader>) ??
|
|
337
|
+
ssz.gloas.ExecutionPayloadHeader.defaultViewDU();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
state.commit();
|
|
341
|
+
|
|
342
|
+
return state;
|
|
343
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export * from "./aggregator.js";
|
|
2
|
+
export * from "./array.js";
|
|
3
|
+
export * from "./attestation.js";
|
|
4
|
+
export * from "./attesterStatus.js";
|
|
5
|
+
export * from "./balance.js";
|
|
6
|
+
export * from "./blindedBlock.js";
|
|
7
|
+
export * from "./blockRoot.js";
|
|
8
|
+
export * from "./calculateCommitteeAssignments.js";
|
|
9
|
+
export * from "./capella.js";
|
|
10
|
+
export * from "./computeAnchorCheckpoint.js";
|
|
11
|
+
export * from "./deposit.js";
|
|
12
|
+
export * from "./domain.js";
|
|
13
|
+
export * from "./electra.js";
|
|
14
|
+
export * from "./epoch.js";
|
|
15
|
+
export * from "./epochShuffling.js";
|
|
16
|
+
export * from "./execution.js";
|
|
17
|
+
export * from "./finality.js";
|
|
18
|
+
export * from "./genesis.js";
|
|
19
|
+
export * from "./interop.js";
|
|
20
|
+
export * from "./loadState/index.js";
|
|
21
|
+
export * from "./rootCache.js";
|
|
22
|
+
export * from "./seed.js";
|
|
23
|
+
export * from "./shufflingDecisionRoot.js";
|
|
24
|
+
export * from "./signatureSets.js";
|
|
25
|
+
export * from "./signingRoot.js";
|
|
26
|
+
export * from "./slot.js";
|
|
27
|
+
export * from "./syncCommittee.js";
|
|
28
|
+
export * from "./validator.js";
|
|
29
|
+
export * from "./weakSubjectivity.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {toBufferBE} from "bigint-buffer";
|
|
2
|
+
import {digest} from "@chainsafe/as-sha256";
|
|
3
|
+
import {SecretKey} from "@chainsafe/blst";
|
|
4
|
+
import {bytesToBigInt, intToBytes} from "@lodestar/utils";
|
|
5
|
+
|
|
6
|
+
let curveOrder: bigint;
|
|
7
|
+
function getCurveOrder(): bigint {
|
|
8
|
+
if (!curveOrder) curveOrder = BigInt("52435875175126190479447740508185965837690552500527637822603658699938581184513");
|
|
9
|
+
return curveOrder;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function interopSecretKeys(validatorCount: number): SecretKey[] {
|
|
13
|
+
return Array.from({length: validatorCount}, (_, i) => {
|
|
14
|
+
return interopSecretKey(i);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function interopSecretKey(index: number): SecretKey {
|
|
19
|
+
const CURVE_ORDER = getCurveOrder();
|
|
20
|
+
const secretKeyBytes = toBufferBE(bytesToBigInt(digest(intToBytes(index, 32))) % CURVE_ORDER, 32);
|
|
21
|
+
return SecretKey.fromBytes(secretKeyBytes);
|
|
22
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// UintNum64 = 8 bytes
|
|
2
|
+
export const INACTIVITY_SCORE_SIZE = 8;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* As monitored on mainnet, inactivityScores are not changed much and they are mostly 0
|
|
6
|
+
* Using Buffer.compare is the fastest way as noted in `./findModifiedValidators.ts`
|
|
7
|
+
* @returns output parameter modifiedValidators: validator indices that are modified
|
|
8
|
+
*/
|
|
9
|
+
export function findModifiedInactivityScores(
|
|
10
|
+
inactivityScoresBytes: Uint8Array,
|
|
11
|
+
inactivityScoresBytes2: Uint8Array,
|
|
12
|
+
modifiedValidators: number[],
|
|
13
|
+
validatorOffset = 0
|
|
14
|
+
): void {
|
|
15
|
+
if (inactivityScoresBytes.length !== inactivityScoresBytes2.length) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
"inactivityScoresBytes.length !== inactivityScoresBytes2.length " +
|
|
18
|
+
inactivityScoresBytes.length +
|
|
19
|
+
" vs " +
|
|
20
|
+
inactivityScoresBytes2.length
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (Buffer.compare(inactivityScoresBytes, inactivityScoresBytes2) === 0) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (inactivityScoresBytes.length === INACTIVITY_SCORE_SIZE) {
|
|
29
|
+
modifiedValidators.push(validatorOffset);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const numValidator = Math.floor(inactivityScoresBytes.length / INACTIVITY_SCORE_SIZE);
|
|
34
|
+
const halfValidator = Math.floor(numValidator / 2);
|
|
35
|
+
findModifiedInactivityScores(
|
|
36
|
+
inactivityScoresBytes.subarray(0, halfValidator * INACTIVITY_SCORE_SIZE),
|
|
37
|
+
inactivityScoresBytes2.subarray(0, halfValidator * INACTIVITY_SCORE_SIZE),
|
|
38
|
+
modifiedValidators,
|
|
39
|
+
validatorOffset
|
|
40
|
+
);
|
|
41
|
+
findModifiedInactivityScores(
|
|
42
|
+
inactivityScoresBytes.subarray(halfValidator * INACTIVITY_SCORE_SIZE),
|
|
43
|
+
inactivityScoresBytes2.subarray(halfValidator * INACTIVITY_SCORE_SIZE),
|
|
44
|
+
modifiedValidators,
|
|
45
|
+
validatorOffset + halfValidator
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {VALIDATOR_BYTES_SIZE} from "../sszBytes.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Find modified validators by comparing two validators bytes using Buffer.compare() recursively
|
|
5
|
+
* - As noted in packages/state-transition/test/perf/util/loadState/findModifiedValidators.test.ts, serializing validators and compare Uint8Array is the fastest way
|
|
6
|
+
* - The performance is quite stable and can afford a lot of difference in validators (the benchmark tested up to 10k but it's not likely we have that difference in mainnet)
|
|
7
|
+
* - Also packages/state-transition/test/perf/misc/byteArrayEquals.test.ts shows that Buffer.compare() is very efficient for large Uint8Array
|
|
8
|
+
*
|
|
9
|
+
* @returns output parameter modifiedValidators: validator indices that are modified
|
|
10
|
+
*/
|
|
11
|
+
export function findModifiedValidators(
|
|
12
|
+
validatorsBytes: Uint8Array,
|
|
13
|
+
validatorsBytes2: Uint8Array,
|
|
14
|
+
modifiedValidators: number[],
|
|
15
|
+
validatorOffset = 0
|
|
16
|
+
): void {
|
|
17
|
+
if (validatorsBytes.length !== validatorsBytes2.length) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
"validatorsBytes.length !== validatorsBytes2.length " + validatorsBytes.length + " vs " + validatorsBytes2.length
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (Buffer.compare(validatorsBytes, validatorsBytes2) === 0) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (validatorsBytes.length === VALIDATOR_BYTES_SIZE) {
|
|
28
|
+
modifiedValidators.push(validatorOffset);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const numValidator = Math.floor(validatorsBytes.length / VALIDATOR_BYTES_SIZE);
|
|
33
|
+
const halfValidator = Math.floor(numValidator / 2);
|
|
34
|
+
findModifiedValidators(
|
|
35
|
+
validatorsBytes.subarray(0, halfValidator * VALIDATOR_BYTES_SIZE),
|
|
36
|
+
validatorsBytes2.subarray(0, halfValidator * VALIDATOR_BYTES_SIZE),
|
|
37
|
+
modifiedValidators,
|
|
38
|
+
validatorOffset
|
|
39
|
+
);
|
|
40
|
+
findModifiedValidators(
|
|
41
|
+
validatorsBytes.subarray(halfValidator * VALIDATOR_BYTES_SIZE),
|
|
42
|
+
validatorsBytes2.subarray(halfValidator * VALIDATOR_BYTES_SIZE),
|
|
43
|
+
modifiedValidators,
|
|
44
|
+
validatorOffset + halfValidator
|
|
45
|
+
);
|
|
46
|
+
}
|