@lodestar/state-transition 1.35.0-dev.47c570ab76 → 1.35.0-dev.549f58dd39
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/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.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.map +1 -0
- 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/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/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 +1 -5
- 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 +9 -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 +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,305 @@
|
|
|
1
|
+
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import {Epoch, SignedBeaconBlock, SignedBlindedBeaconBlock, Slot, ssz} from "@lodestar/types";
|
|
3
|
+
import {toRootHex} from "@lodestar/utils";
|
|
4
|
+
import {BlockExternalData, DataAvailabilityStatus, ExecutionPayloadStatus} from "./block/externalData.js";
|
|
5
|
+
import {processBlock} from "./block/index.js";
|
|
6
|
+
import {ProcessBlockOpts} from "./block/types.js";
|
|
7
|
+
import {EpochTransitionCache, EpochTransitionCacheOpts, beforeProcessEpoch} from "./cache/epochTransitionCache.js";
|
|
8
|
+
import {EpochTransitionStep, processEpoch} from "./epoch/index.js";
|
|
9
|
+
import {BeaconStateTransitionMetrics, onPostStateMetrics, onStateCloneMetrics} from "./metrics.js";
|
|
10
|
+
import {verifyProposerSignature} from "./signatureSets/index.js";
|
|
11
|
+
import {
|
|
12
|
+
processSlot,
|
|
13
|
+
upgradeStateToAltair,
|
|
14
|
+
upgradeStateToBellatrix,
|
|
15
|
+
upgradeStateToCapella,
|
|
16
|
+
upgradeStateToDeneb,
|
|
17
|
+
upgradeStateToElectra,
|
|
18
|
+
upgradeStateToGloas,
|
|
19
|
+
} from "./slot/index.js";
|
|
20
|
+
import {upgradeStateToFulu} from "./slot/upgradeStateToFulu.js";
|
|
21
|
+
import {
|
|
22
|
+
CachedBeaconStateAllForks,
|
|
23
|
+
CachedBeaconStateAltair,
|
|
24
|
+
CachedBeaconStateBellatrix,
|
|
25
|
+
CachedBeaconStateCapella,
|
|
26
|
+
CachedBeaconStateDeneb,
|
|
27
|
+
CachedBeaconStateElectra,
|
|
28
|
+
CachedBeaconStateFulu,
|
|
29
|
+
CachedBeaconStatePhase0,
|
|
30
|
+
} from "./types.js";
|
|
31
|
+
import {computeEpochAtSlot} from "./util/index.js";
|
|
32
|
+
|
|
33
|
+
// Multifork capable state transition
|
|
34
|
+
|
|
35
|
+
// NOTE DENEB: Mandatory BlockExternalData to decide if block is available or not
|
|
36
|
+
export type StateTransitionOpts = BlockExternalData &
|
|
37
|
+
EpochTransitionCacheOpts &
|
|
38
|
+
ProcessBlockOpts & {
|
|
39
|
+
verifyStateRoot?: boolean;
|
|
40
|
+
verifyProposer?: boolean;
|
|
41
|
+
verifySignatures?: boolean;
|
|
42
|
+
dontTransferCache?: boolean;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type StateTransitionModules = {
|
|
46
|
+
metrics?: BeaconStateTransitionMetrics | null;
|
|
47
|
+
validatorMonitor?: ValidatorMonitor | null;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
interface ValidatorMonitor {
|
|
51
|
+
registerValidatorStatuses(
|
|
52
|
+
currentEpoch: Epoch,
|
|
53
|
+
inclusionDelays: number[],
|
|
54
|
+
flags: number[],
|
|
55
|
+
isActiveCurrEpoch: boolean[],
|
|
56
|
+
isActivePrevEpoch: boolean[],
|
|
57
|
+
balances?: number[]
|
|
58
|
+
): void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* `state.clone()` invocation source tracked in metrics
|
|
63
|
+
*/
|
|
64
|
+
export enum StateCloneSource {
|
|
65
|
+
stateTransition = "stateTransition",
|
|
66
|
+
processSlots = "processSlots",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* `state.hashTreeRoot()` invocation source tracked in metrics
|
|
71
|
+
*/
|
|
72
|
+
export enum StateHashTreeRootSource {
|
|
73
|
+
stateTransition = "state_transition",
|
|
74
|
+
blockTransition = "block_transition",
|
|
75
|
+
prepareNextSlot = "prepare_next_slot",
|
|
76
|
+
prepareNextEpoch = "prepare_next_epoch",
|
|
77
|
+
regenState = "regen_state",
|
|
78
|
+
computeNewStateRoot = "compute_new_state_root",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Implementation Note: follows the optimizations in protolambda's eth2fastspec (https://github.com/protolambda/eth2fastspec)
|
|
83
|
+
*/
|
|
84
|
+
export function stateTransition(
|
|
85
|
+
state: CachedBeaconStateAllForks,
|
|
86
|
+
signedBlock: SignedBeaconBlock | SignedBlindedBeaconBlock,
|
|
87
|
+
options: StateTransitionOpts = {
|
|
88
|
+
// Assume default to be valid and available
|
|
89
|
+
executionPayloadStatus: ExecutionPayloadStatus.valid,
|
|
90
|
+
dataAvailabilityStatus: DataAvailabilityStatus.Available,
|
|
91
|
+
},
|
|
92
|
+
{metrics, validatorMonitor}: StateTransitionModules = {}
|
|
93
|
+
): CachedBeaconStateAllForks {
|
|
94
|
+
const {verifyStateRoot = true, verifyProposer = true} = options;
|
|
95
|
+
|
|
96
|
+
const block = signedBlock.message;
|
|
97
|
+
const blockSlot = block.slot;
|
|
98
|
+
|
|
99
|
+
// .clone() before mutating state in state transition
|
|
100
|
+
let postState = state.clone(options.dontTransferCache);
|
|
101
|
+
|
|
102
|
+
if (metrics) {
|
|
103
|
+
onStateCloneMetrics(postState, metrics, StateCloneSource.stateTransition);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// State is already a ViewDU, which won't commit changes. Equivalent to .setStateCachesAsTransient()
|
|
107
|
+
// postState.setStateCachesAsTransient();
|
|
108
|
+
|
|
109
|
+
// Process slots (including those with no blocks) since block.
|
|
110
|
+
// Includes state upgrades
|
|
111
|
+
postState = processSlotsWithTransientCache(postState, blockSlot, options, {metrics, validatorMonitor});
|
|
112
|
+
|
|
113
|
+
// Verify proposer signature only
|
|
114
|
+
if (verifyProposer && !verifyProposerSignature(postState, signedBlock)) {
|
|
115
|
+
throw new Error("Invalid block signature");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Process block
|
|
119
|
+
const fork = state.config.getForkSeq(block.slot);
|
|
120
|
+
|
|
121
|
+
// Note: time only on success
|
|
122
|
+
const processBlockTimer = metrics?.processBlockTime.startTimer();
|
|
123
|
+
|
|
124
|
+
processBlock(fork, postState, block, options, options, metrics);
|
|
125
|
+
|
|
126
|
+
const processBlockCommitTimer = metrics?.processBlockCommitTime.startTimer();
|
|
127
|
+
postState.commit();
|
|
128
|
+
processBlockCommitTimer?.();
|
|
129
|
+
|
|
130
|
+
// Note: time only on success. Include processBlock and commit
|
|
131
|
+
processBlockTimer?.();
|
|
132
|
+
|
|
133
|
+
if (metrics) {
|
|
134
|
+
onPostStateMetrics(postState, metrics);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Verify state root
|
|
138
|
+
if (verifyStateRoot) {
|
|
139
|
+
const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer({
|
|
140
|
+
source: StateHashTreeRootSource.stateTransition,
|
|
141
|
+
});
|
|
142
|
+
const stateRoot = postState.hashTreeRoot();
|
|
143
|
+
hashTreeRootTimer?.();
|
|
144
|
+
|
|
145
|
+
if (!ssz.Root.equals(block.stateRoot, stateRoot)) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Invalid state root at slot ${block.slot}, expected=${toRootHex(block.stateRoot)}, actual=${toRootHex(
|
|
148
|
+
stateRoot
|
|
149
|
+
)}`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return postState;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Like `processSlots` from the spec but additionally handles fork upgrades
|
|
159
|
+
*
|
|
160
|
+
* Implementation Note: follows the optimizations in protolambda's eth2fastspec (https://github.com/protolambda/eth2fastspec)
|
|
161
|
+
*/
|
|
162
|
+
export function processSlots(
|
|
163
|
+
state: CachedBeaconStateAllForks,
|
|
164
|
+
slot: Slot,
|
|
165
|
+
epochTransitionCacheOpts?: EpochTransitionCacheOpts & {dontTransferCache?: boolean},
|
|
166
|
+
{metrics, validatorMonitor}: StateTransitionModules = {}
|
|
167
|
+
): CachedBeaconStateAllForks {
|
|
168
|
+
// .clone() before mutating state in state transition
|
|
169
|
+
let postState = state.clone(epochTransitionCacheOpts?.dontTransferCache);
|
|
170
|
+
|
|
171
|
+
if (metrics) {
|
|
172
|
+
onStateCloneMetrics(postState, metrics, StateCloneSource.processSlots);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// State is already a ViewDU, which won't commit changes. Equivalent to .setStateCachesAsTransient()
|
|
176
|
+
// postState.setStateCachesAsTransient();
|
|
177
|
+
|
|
178
|
+
postState = processSlotsWithTransientCache(postState, slot, epochTransitionCacheOpts, {metrics, validatorMonitor});
|
|
179
|
+
|
|
180
|
+
// Apply changes to state, must do before hashing
|
|
181
|
+
postState.commit();
|
|
182
|
+
|
|
183
|
+
return postState;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* All processSlot() logic but separate so stateTransition() can recycle the caches
|
|
188
|
+
*
|
|
189
|
+
* Epoch transition will be processed at the last slot of an epoch. Note that compute_shuffling() is going
|
|
190
|
+
* to be executed in parallel (either by napi-rs or worker thread) with processEpoch() like below:
|
|
191
|
+
*
|
|
192
|
+
* state-transition
|
|
193
|
+
* ╔══════════════════════════════════════════════════════════════════════════════════╗
|
|
194
|
+
* ║ beforeProcessEpoch processEpoch afterPRocessEpoch ║
|
|
195
|
+
* ║ |-------------------------|--------------------|-------------------------------|║
|
|
196
|
+
* ║ | | | ║
|
|
197
|
+
* ╚═══════════════════════|═══════════════════════════════|══════════════════════════╝
|
|
198
|
+
* | |
|
|
199
|
+
* build() get()
|
|
200
|
+
* | |
|
|
201
|
+
* ╔═══════════════════════V═══════════════════════════════V═══════════════════════════╗
|
|
202
|
+
* ║ | | ║
|
|
203
|
+
* ║ |-------------------------------| ║
|
|
204
|
+
* ║ compute_shuffling() ║
|
|
205
|
+
* ╚═══════════════════════════════════════════════════════════════════════════════════╝
|
|
206
|
+
* beacon-node ShufflingCache
|
|
207
|
+
*/
|
|
208
|
+
function processSlotsWithTransientCache(
|
|
209
|
+
postState: CachedBeaconStateAllForks,
|
|
210
|
+
slot: Slot,
|
|
211
|
+
epochTransitionCacheOpts?: EpochTransitionCacheOpts,
|
|
212
|
+
{metrics, validatorMonitor}: StateTransitionModules = {}
|
|
213
|
+
): CachedBeaconStateAllForks {
|
|
214
|
+
const {config} = postState;
|
|
215
|
+
if (postState.slot > slot) {
|
|
216
|
+
throw Error(`Too old slot ${slot}, current=${postState.slot}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
while (postState.slot < slot) {
|
|
220
|
+
processSlot(postState);
|
|
221
|
+
|
|
222
|
+
// Process epoch on the first slot of the next epoch
|
|
223
|
+
if ((postState.slot + 1) % SLOTS_PER_EPOCH === 0) {
|
|
224
|
+
// At fork boundary we don't want to process "next fork" epoch before upgrading state
|
|
225
|
+
const fork = postState.config.getForkSeq(postState.slot);
|
|
226
|
+
|
|
227
|
+
const epochTransitionTimer = metrics?.epochTransitionTime.startTimer();
|
|
228
|
+
|
|
229
|
+
let epochTransitionCache: EpochTransitionCache;
|
|
230
|
+
{
|
|
231
|
+
const timer = metrics?.epochTransitionStepTime.startTimer({step: EpochTransitionStep.beforeProcessEpoch});
|
|
232
|
+
epochTransitionCache = beforeProcessEpoch(postState, epochTransitionCacheOpts);
|
|
233
|
+
timer?.();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
processEpoch(fork, postState, epochTransitionCache, metrics);
|
|
237
|
+
|
|
238
|
+
const {currentEpoch, inclusionDelays, flags, isActiveCurrEpoch, isActivePrevEpoch, balances} =
|
|
239
|
+
epochTransitionCache;
|
|
240
|
+
validatorMonitor?.registerValidatorStatuses(
|
|
241
|
+
currentEpoch,
|
|
242
|
+
inclusionDelays,
|
|
243
|
+
flags,
|
|
244
|
+
isActiveCurrEpoch,
|
|
245
|
+
isActivePrevEpoch,
|
|
246
|
+
balances
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
postState.slot++;
|
|
250
|
+
|
|
251
|
+
{
|
|
252
|
+
const timer = metrics?.epochTransitionStepTime.startTimer({step: EpochTransitionStep.afterProcessEpoch});
|
|
253
|
+
// this should be called before `upgradeState*()` below to prepare data for it
|
|
254
|
+
postState.epochCtx.afterProcessEpoch(postState, epochTransitionCache);
|
|
255
|
+
timer?.();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Upgrade state if exactly at epoch boundary
|
|
259
|
+
const stateEpoch = computeEpochAtSlot(postState.slot);
|
|
260
|
+
if (stateEpoch === config.ALTAIR_FORK_EPOCH) {
|
|
261
|
+
postState = upgradeStateToAltair(postState as CachedBeaconStatePhase0) as CachedBeaconStateAllForks;
|
|
262
|
+
}
|
|
263
|
+
if (stateEpoch === config.BELLATRIX_FORK_EPOCH) {
|
|
264
|
+
postState = upgradeStateToBellatrix(postState as CachedBeaconStateAltair) as CachedBeaconStateAllForks;
|
|
265
|
+
}
|
|
266
|
+
if (stateEpoch === config.CAPELLA_FORK_EPOCH) {
|
|
267
|
+
postState = upgradeStateToCapella(postState as CachedBeaconStateBellatrix) as CachedBeaconStateAllForks;
|
|
268
|
+
}
|
|
269
|
+
if (stateEpoch === config.DENEB_FORK_EPOCH) {
|
|
270
|
+
postState = upgradeStateToDeneb(postState as CachedBeaconStateCapella) as CachedBeaconStateAllForks;
|
|
271
|
+
}
|
|
272
|
+
if (stateEpoch === config.ELECTRA_FORK_EPOCH) {
|
|
273
|
+
postState = upgradeStateToElectra(postState as CachedBeaconStateDeneb) as CachedBeaconStateAllForks;
|
|
274
|
+
}
|
|
275
|
+
if (stateEpoch === config.FULU_FORK_EPOCH) {
|
|
276
|
+
postState = upgradeStateToFulu(postState as CachedBeaconStateElectra) as CachedBeaconStateAllForks;
|
|
277
|
+
}
|
|
278
|
+
if (stateEpoch === config.GLOAS_FORK_EPOCH) {
|
|
279
|
+
postState = upgradeStateToGloas(postState as CachedBeaconStateFulu) as CachedBeaconStateAllForks;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
{
|
|
283
|
+
const timer = metrics?.epochTransitionStepTime.startTimer({step: EpochTransitionStep.finalProcessEpoch});
|
|
284
|
+
// last step to prepare epoch data that depends on the upgraded state, for example proposerLookahead of BeaconStateFulu
|
|
285
|
+
postState.epochCtx.finalProcessEpoch(postState);
|
|
286
|
+
timer?.();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Running commit here is not strictly necessary. The cost of running commit twice (here + after process block)
|
|
290
|
+
// Should be negligible but gives better metrics to differentiate the cost of it for block and epoch proc.
|
|
291
|
+
{
|
|
292
|
+
const timer = metrics?.epochTransitionCommitTime.startTimer();
|
|
293
|
+
postState.commit();
|
|
294
|
+
timer?.();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Note: time only on success. Include beforeProcessEpoch, processEpoch, afterProcessEpoch, upgradeState*, finalProcessEpoch, commit
|
|
298
|
+
epochTransitionTimer?.();
|
|
299
|
+
} else {
|
|
300
|
+
postState.slot++;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return postState;
|
|
305
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export {EpochCache} from "./cache/epochCache.js";
|
|
2
|
+
export type {EpochTransitionCache} from "./cache/epochTransitionCache.js";
|
|
3
|
+
export type {
|
|
4
|
+
CachedBeaconStateAllForks,
|
|
5
|
+
CachedBeaconStateAltair,
|
|
6
|
+
CachedBeaconStateBellatrix,
|
|
7
|
+
CachedBeaconStateCapella,
|
|
8
|
+
CachedBeaconStateDeneb,
|
|
9
|
+
CachedBeaconStateElectra,
|
|
10
|
+
CachedBeaconStateExecutions,
|
|
11
|
+
CachedBeaconStateFulu,
|
|
12
|
+
CachedBeaconStateGloas,
|
|
13
|
+
CachedBeaconStatePhase0,
|
|
14
|
+
} from "./cache/stateCache.js";
|
|
15
|
+
export type {
|
|
16
|
+
BeaconStateAllForks,
|
|
17
|
+
BeaconStateAltair,
|
|
18
|
+
BeaconStateBellatrix,
|
|
19
|
+
BeaconStateCapella,
|
|
20
|
+
BeaconStateDeneb,
|
|
21
|
+
BeaconStateElectra,
|
|
22
|
+
BeaconStateExecutions,
|
|
23
|
+
BeaconStateFulu,
|
|
24
|
+
BeaconStateGloas,
|
|
25
|
+
BeaconStatePhase0,
|
|
26
|
+
} from "./cache/types.js";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {digest} from "@chainsafe/as-sha256";
|
|
2
|
+
import {
|
|
3
|
+
SYNC_COMMITTEE_SIZE,
|
|
4
|
+
SYNC_COMMITTEE_SUBNET_COUNT,
|
|
5
|
+
TARGET_AGGREGATORS_PER_COMMITTEE,
|
|
6
|
+
TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE,
|
|
7
|
+
} from "@lodestar/params";
|
|
8
|
+
import {BLSSignature} from "@lodestar/types";
|
|
9
|
+
import {bytesToBigInt, intDiv} from "@lodestar/utils";
|
|
10
|
+
|
|
11
|
+
const ZERO_BIGINT = BigInt(0);
|
|
12
|
+
|
|
13
|
+
export function isSyncCommitteeAggregator(selectionProof: BLSSignature): boolean {
|
|
14
|
+
const modulo = Math.max(
|
|
15
|
+
1,
|
|
16
|
+
intDiv(intDiv(SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT), TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE)
|
|
17
|
+
);
|
|
18
|
+
return isSelectionProofValid(selectionProof, modulo);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isAggregatorFromCommitteeLength(committeeLength: number, slotSignature: BLSSignature): boolean {
|
|
22
|
+
const modulo = Math.max(1, intDiv(committeeLength, TARGET_AGGREGATORS_PER_COMMITTEE));
|
|
23
|
+
return isSelectionProofValid(slotSignature, modulo);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Note: **must** use bytesToBigInt() otherwise a JS number is not able to represent the latest digits of
|
|
28
|
+
* the remainder, resulting in `14333559117764833000` for example, where the last three digits are always zero.
|
|
29
|
+
* Using bytesToInt() may cause isSelectionProofValid() to always return false.
|
|
30
|
+
*/
|
|
31
|
+
export function isSelectionProofValid(sig: BLSSignature, modulo: number): boolean {
|
|
32
|
+
return bytesToBigInt(digest(sig).slice(0, 8)) % BigInt(modulo) === ZERO_BIGINT;
|
|
33
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {BASE_REWARD_FACTOR, EFFECTIVE_BALANCE_INCREMENT} from "@lodestar/params";
|
|
2
|
+
import {bigIntSqrt, bnToNum} from "@lodestar/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Before we manage bigIntSqrt(totalActiveStake) as BigInt and return BigInt.
|
|
6
|
+
* bigIntSqrt(totalActiveStake) should fit a number (2 ** 53 -1 max)
|
|
7
|
+
**/
|
|
8
|
+
export function computeBaseRewardPerIncrement(totalActiveStakeByIncrement: number): number {
|
|
9
|
+
return Math.floor(
|
|
10
|
+
(EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR) /
|
|
11
|
+
bnToNum(bigIntSqrt(BigInt(totalActiveStakeByIncrement) * BigInt(EFFECTIVE_BALANCE_INCREMENT)))
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns an array of size `n` filled with 0
|
|
3
|
+
* 20 times faster than
|
|
4
|
+
* ```
|
|
5
|
+
* Array.from({length: n}, () => 0)
|
|
6
|
+
* ```
|
|
7
|
+
* - Array.from: 40ms / 200_000 elements
|
|
8
|
+
* - This fn: 2.2ms / 200_000 elements
|
|
9
|
+
*/
|
|
10
|
+
export function newZeroedArray(n: number): number[] {
|
|
11
|
+
const arr = new Array<number>(n);
|
|
12
|
+
for (let i = 0; i < n; ++i) {
|
|
13
|
+
arr[i] = 0;
|
|
14
|
+
}
|
|
15
|
+
return arr;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function newZeroedBigIntArray(n: number): bigint[] {
|
|
19
|
+
const arr = new Array<bigint>(n);
|
|
20
|
+
for (let i = 0; i < n; ++i) {
|
|
21
|
+
arr[i] = BigInt(0);
|
|
22
|
+
}
|
|
23
|
+
return arr;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function newFilledArray<T>(n: number, val: T): T[] {
|
|
27
|
+
const arr = new Array<T>(n);
|
|
28
|
+
for (let i = 0; i < n; ++i) {
|
|
29
|
+
arr[i] = val;
|
|
30
|
+
}
|
|
31
|
+
return arr;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns an array with all values not in the participants array.
|
|
36
|
+
* - All elements in values must be unique
|
|
37
|
+
* - Does NOT require sorting
|
|
38
|
+
*/
|
|
39
|
+
export function getUnparticipantValues<T>(participants: T[], values: T[]): T[] {
|
|
40
|
+
const unparticipants: T[] = [];
|
|
41
|
+
|
|
42
|
+
let j = 0;
|
|
43
|
+
for (let i = 0; i < values.length; i++) {
|
|
44
|
+
if (values[i] === participants[j]) {
|
|
45
|
+
// Included
|
|
46
|
+
j++;
|
|
47
|
+
} else {
|
|
48
|
+
unparticipants.push(values[i]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return unparticipants;
|
|
53
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import {AttesterSlashing, Slot, ValidatorIndex, phase0, ssz} from "@lodestar/types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check if [[data1]] and [[data2]] are slashable according to Casper FFG rules.
|
|
6
|
+
*/
|
|
7
|
+
export function isSlashableAttestationData(
|
|
8
|
+
data1: phase0.AttestationDataBigint,
|
|
9
|
+
data2: phase0.AttestationDataBigint
|
|
10
|
+
): boolean {
|
|
11
|
+
return (
|
|
12
|
+
// Double vote
|
|
13
|
+
(!ssz.phase0.AttestationDataBigint.equals(data1, data2) && data1.target.epoch === data2.target.epoch) ||
|
|
14
|
+
// Surround vote
|
|
15
|
+
(data1.source.epoch < data2.source.epoch && data2.target.epoch < data1.target.epoch)
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isValidAttestationSlot(attestationSlot: Slot, currentSlot: Slot): boolean {
|
|
20
|
+
return (
|
|
21
|
+
attestationSlot + MIN_ATTESTATION_INCLUSION_DELAY <= currentSlot && currentSlot <= attestationSlot + SLOTS_PER_EPOCH
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function getAttesterSlashableIndices(attesterSlashing: AttesterSlashing): ValidatorIndex[] {
|
|
26
|
+
const indices: ValidatorIndex[] = [];
|
|
27
|
+
const attSet1 = new Set(attesterSlashing.attestation1.attestingIndices);
|
|
28
|
+
const attArr2 = attesterSlashing.attestation2.attestingIndices;
|
|
29
|
+
for (let i = 0, len = attArr2.length; i < len; i++) {
|
|
30
|
+
const index = attArr2[i];
|
|
31
|
+
if (attSet1.has(index)) {
|
|
32
|
+
indices.push(index);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return indices;
|
|
36
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX} from "@lodestar/params";
|
|
2
|
+
|
|
3
|
+
// We pack both previous and current epoch attester flags
|
|
4
|
+
// as well as slashed and eligibility flags into a single number
|
|
5
|
+
// to save space in our epoch transition cache.
|
|
6
|
+
// Note: the order of the flags is important for efficiently translating
|
|
7
|
+
// from the BeaconState flags to our flags.
|
|
8
|
+
// [prevSource, prevTarget, prevHead, currSource, currTarget, currHead, unslashed, eligible]
|
|
9
|
+
export const FLAG_PREV_SOURCE_ATTESTER = 1 << TIMELY_SOURCE_FLAG_INDEX;
|
|
10
|
+
export const FLAG_PREV_TARGET_ATTESTER = 1 << TIMELY_TARGET_FLAG_INDEX;
|
|
11
|
+
export const FLAG_PREV_HEAD_ATTESTER = 1 << TIMELY_HEAD_FLAG_INDEX;
|
|
12
|
+
|
|
13
|
+
export const FLAG_CURR_SOURCE_ATTESTER = 1 << (3 + TIMELY_SOURCE_FLAG_INDEX);
|
|
14
|
+
export const FLAG_CURR_TARGET_ATTESTER = 1 << (3 + TIMELY_TARGET_FLAG_INDEX);
|
|
15
|
+
export const FLAG_CURR_HEAD_ATTESTER = 1 << (3 + TIMELY_HEAD_FLAG_INDEX);
|
|
16
|
+
|
|
17
|
+
export const FLAG_UNSLASHED = 1 << 6;
|
|
18
|
+
export const FLAG_ELIGIBLE_ATTESTER = 1 << 7;
|
|
19
|
+
|
|
20
|
+
// Precompute OR flags used in epoch processing
|
|
21
|
+
export const FLAG_PREV_SOURCE_ATTESTER_UNSLASHED = FLAG_PREV_SOURCE_ATTESTER | FLAG_UNSLASHED;
|
|
22
|
+
export const FLAG_PREV_TARGET_ATTESTER_UNSLASHED = FLAG_PREV_TARGET_ATTESTER | FLAG_UNSLASHED;
|
|
23
|
+
export const FLAG_PREV_HEAD_ATTESTER_UNSLASHED = FLAG_PREV_HEAD_ATTESTER | FLAG_UNSLASHED;
|
|
24
|
+
|
|
25
|
+
export function hasMarkers(flags: number, markers: number): boolean {
|
|
26
|
+
return (flags & markers) === markers;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type AttesterFlags = {
|
|
30
|
+
prevSourceAttester: boolean;
|
|
31
|
+
prevTargetAttester: boolean;
|
|
32
|
+
prevHeadAttester: boolean;
|
|
33
|
+
currSourceAttester: boolean;
|
|
34
|
+
currTargetAttester: boolean;
|
|
35
|
+
currHeadAttester: boolean;
|
|
36
|
+
unslashed: boolean;
|
|
37
|
+
eligibleAttester: boolean;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export function parseAttesterFlags(flags: number): AttesterFlags {
|
|
41
|
+
return {
|
|
42
|
+
prevSourceAttester: hasMarkers(flags, FLAG_PREV_SOURCE_ATTESTER),
|
|
43
|
+
prevTargetAttester: hasMarkers(flags, FLAG_PREV_TARGET_ATTESTER),
|
|
44
|
+
prevHeadAttester: hasMarkers(flags, FLAG_PREV_HEAD_ATTESTER),
|
|
45
|
+
currSourceAttester: hasMarkers(flags, FLAG_CURR_SOURCE_ATTESTER),
|
|
46
|
+
currTargetAttester: hasMarkers(flags, FLAG_CURR_TARGET_ATTESTER),
|
|
47
|
+
currHeadAttester: hasMarkers(flags, FLAG_CURR_HEAD_ATTESTER),
|
|
48
|
+
unslashed: hasMarkers(flags, FLAG_UNSLASHED),
|
|
49
|
+
eligibleAttester: hasMarkers(flags, FLAG_ELIGIBLE_ATTESTER),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function toAttesterFlags(flagsObj: AttesterFlags): number {
|
|
54
|
+
let flag = 0;
|
|
55
|
+
if (flagsObj.prevSourceAttester) flag |= FLAG_PREV_SOURCE_ATTESTER;
|
|
56
|
+
if (flagsObj.prevTargetAttester) flag |= FLAG_PREV_TARGET_ATTESTER;
|
|
57
|
+
if (flagsObj.prevHeadAttester) flag |= FLAG_PREV_HEAD_ATTESTER;
|
|
58
|
+
if (flagsObj.currSourceAttester) flag |= FLAG_CURR_SOURCE_ATTESTER;
|
|
59
|
+
if (flagsObj.currTargetAttester) flag |= FLAG_CURR_TARGET_ATTESTER;
|
|
60
|
+
if (flagsObj.currHeadAttester) flag |= FLAG_CURR_HEAD_ATTESTER;
|
|
61
|
+
if (flagsObj.unslashed) flag |= FLAG_UNSLASHED;
|
|
62
|
+
if (flagsObj.eligibleAttester) flag |= FLAG_ELIGIBLE_ATTESTER;
|
|
63
|
+
return flag;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */
|
|
67
|
+
const TIMELY_SOURCE = 1 << TIMELY_SOURCE_FLAG_INDEX;
|
|
68
|
+
const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX;
|
|
69
|
+
const TIMELY_HEAD = 1 << TIMELY_HEAD_FLAG_INDEX;
|
|
70
|
+
|
|
71
|
+
export type ParticipationFlags = {
|
|
72
|
+
timelySource: boolean;
|
|
73
|
+
timelyTarget: boolean;
|
|
74
|
+
timelyHead: boolean;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export function parseParticipationFlags(flags: number): ParticipationFlags {
|
|
78
|
+
return {
|
|
79
|
+
timelySource: hasMarkers(flags, TIMELY_SOURCE),
|
|
80
|
+
timelyTarget: hasMarkers(flags, TIMELY_TARGET),
|
|
81
|
+
timelyHead: hasMarkers(flags, TIMELY_HEAD),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {EFFECTIVE_BALANCE_INCREMENT} from "@lodestar/params";
|
|
2
|
+
import {Gwei, ValidatorIndex} from "@lodestar/types";
|
|
3
|
+
import {bigIntMax} from "@lodestar/utils";
|
|
4
|
+
import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
|
|
5
|
+
import {BeaconStateAllForks} from "../index.js";
|
|
6
|
+
import {CachedBeaconStateAllForks} from "../types.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Return the combined effective balance of the [[indices]].
|
|
10
|
+
* `EFFECTIVE_BALANCE_INCREMENT` Gwei minimum to avoid divisions by zero.
|
|
11
|
+
*
|
|
12
|
+
* SLOW CODE - 🐢
|
|
13
|
+
*/
|
|
14
|
+
export function getTotalBalance(state: BeaconStateAllForks, indices: ValidatorIndex[]): Gwei {
|
|
15
|
+
let total = BigInt(0);
|
|
16
|
+
|
|
17
|
+
// TODO: Use a fast cache to get the effective balance 🐢
|
|
18
|
+
const validatorsArr = state.validators.getAllReadonlyValues();
|
|
19
|
+
for (let i = 0; i < indices.length; i++) {
|
|
20
|
+
total += BigInt(validatorsArr[indices[i]].effectiveBalance);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return bigIntMax(BigInt(EFFECTIVE_BALANCE_INCREMENT), total);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Increase the balance for a validator with the given ``index`` by ``delta``.
|
|
28
|
+
*/
|
|
29
|
+
export function increaseBalance(state: BeaconStateAllForks, index: ValidatorIndex, delta: number): void {
|
|
30
|
+
// TODO: Inline this
|
|
31
|
+
state.balances.set(index, state.balances.get(index) + delta);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Decrease the balance for a validator with the given ``index`` by ``delta``.
|
|
36
|
+
*
|
|
37
|
+
* Set to ``0`` when underflow.
|
|
38
|
+
*/
|
|
39
|
+
export function decreaseBalance(state: BeaconStateAllForks, index: ValidatorIndex, delta: number): void {
|
|
40
|
+
const currentBalance = state.balances.get(index);
|
|
41
|
+
const newBalance = currentBalance > delta ? state.balances.get(index) - delta : 0;
|
|
42
|
+
// TODO: Is it necessary to protect against underflow here? Add unit test
|
|
43
|
+
state.balances.set(index, Math.max(0, newBalance));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* This method is used to get justified balances from a justified state.
|
|
48
|
+
* This is consumed by forkchoice which based on delta so we return "by increment" (in ether) value,
|
|
49
|
+
* ie [30, 31, 32] instead of [30e9, 31e9, 32e9]
|
|
50
|
+
*/
|
|
51
|
+
export function getEffectiveBalanceIncrementsZeroInactive(
|
|
52
|
+
justifiedState: CachedBeaconStateAllForks
|
|
53
|
+
): EffectiveBalanceIncrements {
|
|
54
|
+
const {activeIndices} = justifiedState.epochCtx.currentShuffling;
|
|
55
|
+
// 5x faster than reading from state.validators, with validator Nodes as values
|
|
56
|
+
const validatorCount = justifiedState.validators.length;
|
|
57
|
+
const {effectiveBalanceIncrements} = justifiedState.epochCtx;
|
|
58
|
+
// Slice up to `validatorCount` since it won't be mutated, nor accessed beyond `validatorCount`
|
|
59
|
+
// NOTE: Force to use Uint16Array.slice (copy) instead of Buffer.call (not copy)
|
|
60
|
+
const effectiveBalanceIncrementsZeroInactive = Uint16Array.prototype.slice.call(
|
|
61
|
+
effectiveBalanceIncrements,
|
|
62
|
+
0,
|
|
63
|
+
validatorCount
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
let j = 0;
|
|
67
|
+
justifiedState.validators.forEachValue((validator, i) => {
|
|
68
|
+
const {slashed} = validator;
|
|
69
|
+
if (i === activeIndices[j]) {
|
|
70
|
+
// active validator
|
|
71
|
+
j++;
|
|
72
|
+
if (slashed) {
|
|
73
|
+
// slashed validator
|
|
74
|
+
effectiveBalanceIncrementsZeroInactive[i] = 0;
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
// inactive validator
|
|
78
|
+
effectiveBalanceIncrementsZeroInactive[i] = 0;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return effectiveBalanceIncrementsZeroInactive;
|
|
83
|
+
}
|