@lodestar/state-transition 1.35.0-dev.e9dd48f165 → 1.35.0-dev.fcf8d024ea
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 +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/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 +3 -6
- 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 +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/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 +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,144 @@
|
|
|
1
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
+
import {
|
|
3
|
+
ForkName,
|
|
4
|
+
ForkPostBellatrix,
|
|
5
|
+
ForkPostDeneb,
|
|
6
|
+
ForkSeq,
|
|
7
|
+
isForkPostBellatrix,
|
|
8
|
+
isForkPostDeneb,
|
|
9
|
+
} from "@lodestar/params";
|
|
10
|
+
import {
|
|
11
|
+
BeaconBlock,
|
|
12
|
+
BeaconBlockHeader,
|
|
13
|
+
BlindedBeaconBlock,
|
|
14
|
+
BlobsBundle,
|
|
15
|
+
ExecutionPayload,
|
|
16
|
+
ExecutionPayloadAndBlobsBundle,
|
|
17
|
+
ExecutionPayloadHeader,
|
|
18
|
+
Root,
|
|
19
|
+
SignedBeaconBlock,
|
|
20
|
+
SignedBlindedBeaconBlock,
|
|
21
|
+
SignedBlockContents,
|
|
22
|
+
isBlindedBeaconBlock,
|
|
23
|
+
isExecutionPayloadAndBlobsBundle,
|
|
24
|
+
} from "@lodestar/types";
|
|
25
|
+
import {executionPayloadToPayloadHeader} from "./execution.js";
|
|
26
|
+
|
|
27
|
+
export function blindedOrFullBlockHashTreeRoot(
|
|
28
|
+
config: ChainForkConfig,
|
|
29
|
+
blindedOrFull: BeaconBlock | BlindedBeaconBlock
|
|
30
|
+
): Root {
|
|
31
|
+
return isBlindedBeaconBlock(blindedOrFull)
|
|
32
|
+
? // Blinded
|
|
33
|
+
config
|
|
34
|
+
.getPostBellatrixForkTypes(blindedOrFull.slot)
|
|
35
|
+
.BlindedBeaconBlock.hashTreeRoot(blindedOrFull)
|
|
36
|
+
: // Full
|
|
37
|
+
config
|
|
38
|
+
.getForkTypes(blindedOrFull.slot)
|
|
39
|
+
.BeaconBlock.hashTreeRoot(blindedOrFull);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function blindedOrFullBlockToHeader(
|
|
43
|
+
config: ChainForkConfig,
|
|
44
|
+
blindedOrFull: BeaconBlock | BlindedBeaconBlock
|
|
45
|
+
): BeaconBlockHeader {
|
|
46
|
+
const bodyRoot = isBlindedBeaconBlock(blindedOrFull)
|
|
47
|
+
? // Blinded
|
|
48
|
+
config
|
|
49
|
+
.getPostBellatrixForkTypes(blindedOrFull.slot)
|
|
50
|
+
.BlindedBeaconBlockBody.hashTreeRoot(blindedOrFull.body)
|
|
51
|
+
: // Full
|
|
52
|
+
config
|
|
53
|
+
.getForkTypes(blindedOrFull.slot)
|
|
54
|
+
.BeaconBlockBody.hashTreeRoot(blindedOrFull.body);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
slot: blindedOrFull.slot,
|
|
58
|
+
proposerIndex: blindedOrFull.proposerIndex,
|
|
59
|
+
parentRoot: blindedOrFull.parentRoot,
|
|
60
|
+
stateRoot: blindedOrFull.stateRoot,
|
|
61
|
+
bodyRoot,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function beaconBlockToBlinded(
|
|
66
|
+
config: ChainForkConfig,
|
|
67
|
+
block: BeaconBlock<ForkPostBellatrix>
|
|
68
|
+
): BlindedBeaconBlock {
|
|
69
|
+
const fork = config.getForkName(block.slot);
|
|
70
|
+
const executionPayloadHeader = executionPayloadToPayloadHeader(ForkSeq[fork], block.body.executionPayload);
|
|
71
|
+
const blindedBlock: BlindedBeaconBlock = {...block, body: {...block.body, executionPayloadHeader}};
|
|
72
|
+
return blindedBlock;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function signedBeaconBlockToBlinded(
|
|
76
|
+
config: ChainForkConfig,
|
|
77
|
+
signedBlock: SignedBeaconBlock<ForkPostBellatrix>
|
|
78
|
+
): SignedBlindedBeaconBlock {
|
|
79
|
+
return {
|
|
80
|
+
message: beaconBlockToBlinded(config, signedBlock.message),
|
|
81
|
+
signature: signedBlock.signature,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function signedBlindedBlockToFull(
|
|
86
|
+
fork: ForkName,
|
|
87
|
+
signedBlindedBlock: SignedBlindedBeaconBlock,
|
|
88
|
+
executionPayload: ExecutionPayload | null
|
|
89
|
+
): SignedBeaconBlock {
|
|
90
|
+
if (isForkPostBellatrix(fork) && executionPayload === null) {
|
|
91
|
+
throw Error("Missing executionPayload to reconstruct post-bellatrix full block");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const signedBlock = {
|
|
95
|
+
...signedBlindedBlock,
|
|
96
|
+
message: {
|
|
97
|
+
...signedBlindedBlock.message,
|
|
98
|
+
body: {
|
|
99
|
+
...signedBlindedBlock.message.body,
|
|
100
|
+
// state transition doesn't handle null value for executionPayload in pre-bellatrix blocks
|
|
101
|
+
executionPayload: executionPayload ?? undefined,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
} as SignedBeaconBlock;
|
|
105
|
+
|
|
106
|
+
// state transition can't seem to handle executionPayloadHeader presense in merge block
|
|
107
|
+
// so just delete the extra field we don't require
|
|
108
|
+
delete (signedBlock.message.body as {executionPayloadHeader?: ExecutionPayloadHeader}).executionPayloadHeader;
|
|
109
|
+
return signedBlock;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function parseExecutionPayloadAndBlobsBundle(data: ExecutionPayload | ExecutionPayloadAndBlobsBundle): {
|
|
113
|
+
executionPayload: ExecutionPayload;
|
|
114
|
+
blobsBundle: BlobsBundle | null;
|
|
115
|
+
} {
|
|
116
|
+
if (isExecutionPayloadAndBlobsBundle(data)) {
|
|
117
|
+
return data;
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
executionPayload: data,
|
|
121
|
+
blobsBundle: null,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function reconstructSignedBlockContents(
|
|
126
|
+
fork: ForkName,
|
|
127
|
+
signedBlindedBlock: SignedBlindedBeaconBlock,
|
|
128
|
+
executionPayload: ExecutionPayload | null,
|
|
129
|
+
blobsBundle: BlobsBundle | null
|
|
130
|
+
): SignedBlockContents {
|
|
131
|
+
const signedBlock = signedBlindedBlockToFull(fork, signedBlindedBlock, executionPayload);
|
|
132
|
+
|
|
133
|
+
if (isForkPostDeneb(fork)) {
|
|
134
|
+
if (blobsBundle === null) {
|
|
135
|
+
throw Error("Missing blobs bundle to reconstruct post-deneb block contents");
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
signedBlock: signedBlock as SignedBeaconBlock<ForkPostDeneb>,
|
|
139
|
+
kzgProofs: blobsBundle.proofs,
|
|
140
|
+
blobs: blobsBundle.blobs,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return {signedBlock};
|
|
144
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
+
import {SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
3
|
+
import {
|
|
4
|
+
BeaconBlock,
|
|
5
|
+
BeaconBlockHeader,
|
|
6
|
+
Epoch,
|
|
7
|
+
Root,
|
|
8
|
+
SignedBeaconBlock,
|
|
9
|
+
SignedBeaconBlockHeader,
|
|
10
|
+
Slot,
|
|
11
|
+
} from "@lodestar/types";
|
|
12
|
+
import {ZERO_HASH} from "../constants/index.js";
|
|
13
|
+
import {BeaconStateAllForks} from "../types.js";
|
|
14
|
+
import {computeStartSlotAtEpoch} from "./epoch.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Return the block root at a recent [[slot]].
|
|
18
|
+
*/
|
|
19
|
+
export function getBlockRootAtSlot(state: BeaconStateAllForks, slot: Slot): Root {
|
|
20
|
+
if (slot >= state.slot) {
|
|
21
|
+
throw Error(`Can only get block root in the past currentSlot=${state.slot} slot=${slot}`);
|
|
22
|
+
}
|
|
23
|
+
if (slot < state.slot - SLOTS_PER_HISTORICAL_ROOT) {
|
|
24
|
+
throw Error(`Cannot get block root more than ${SLOTS_PER_HISTORICAL_ROOT} in the past`);
|
|
25
|
+
}
|
|
26
|
+
return state.blockRoots.get(slot % SLOTS_PER_HISTORICAL_ROOT);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Return the block root at the start of a recent [[epoch]].
|
|
31
|
+
*/
|
|
32
|
+
export function getBlockRoot(state: BeaconStateAllForks, epoch: Epoch): Root {
|
|
33
|
+
return getBlockRootAtSlot(state, computeStartSlotAtEpoch(epoch));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Return the block header corresponding to a block with ``state_root`` set to ``ZERO_HASH``.
|
|
37
|
+
*/
|
|
38
|
+
export function getTemporaryBlockHeader(config: ChainForkConfig, block: BeaconBlock): BeaconBlockHeader {
|
|
39
|
+
return {
|
|
40
|
+
slot: block.slot,
|
|
41
|
+
proposerIndex: block.proposerIndex,
|
|
42
|
+
parentRoot: block.parentRoot,
|
|
43
|
+
// `state_root` is zeroed and overwritten in the next `process_slot` call
|
|
44
|
+
stateRoot: ZERO_HASH,
|
|
45
|
+
bodyRoot: config.getForkTypes(block.slot).BeaconBlockBody.hashTreeRoot(block.body),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Receives a BeaconBlock, and produces the corresponding BeaconBlockHeader.
|
|
51
|
+
*/
|
|
52
|
+
export function blockToHeader(config: ChainForkConfig, block: BeaconBlock): BeaconBlockHeader {
|
|
53
|
+
return {
|
|
54
|
+
stateRoot: block.stateRoot,
|
|
55
|
+
proposerIndex: block.proposerIndex,
|
|
56
|
+
slot: block.slot,
|
|
57
|
+
parentRoot: block.parentRoot,
|
|
58
|
+
bodyRoot: config.getForkTypes(block.slot).BeaconBlockBody.hashTreeRoot(block.body),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function signedBlockToSignedHeader(
|
|
63
|
+
config: ChainForkConfig,
|
|
64
|
+
signedBlock: SignedBeaconBlock
|
|
65
|
+
): SignedBeaconBlockHeader {
|
|
66
|
+
const message = blockToHeader(config, signedBlock.message);
|
|
67
|
+
const signature = signedBlock.signature;
|
|
68
|
+
return {
|
|
69
|
+
message,
|
|
70
|
+
signature,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import {CommitteeIndex, Slot, ValidatorIndex} from "@lodestar/types";
|
|
3
|
+
import {EpochShuffling} from "./epochShuffling.js";
|
|
4
|
+
|
|
5
|
+
// Copied from lodestar-api package to avoid depending on the package
|
|
6
|
+
export interface AttesterDuty {
|
|
7
|
+
validatorIndex: ValidatorIndex;
|
|
8
|
+
committeeIndex: CommitteeIndex;
|
|
9
|
+
committeeLength: number;
|
|
10
|
+
committeesAtSlot: number;
|
|
11
|
+
validatorCommitteeIndex: number;
|
|
12
|
+
slot: Slot;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function calculateCommitteeAssignments(
|
|
16
|
+
epochShuffling: EpochShuffling,
|
|
17
|
+
requestedValidatorIndices: ValidatorIndex[]
|
|
18
|
+
): Map<ValidatorIndex, AttesterDuty> {
|
|
19
|
+
const requestedValidatorIndicesSet = new Set(requestedValidatorIndices);
|
|
20
|
+
const duties = new Map<ValidatorIndex, AttesterDuty>();
|
|
21
|
+
|
|
22
|
+
const epochCommittees = epochShuffling.committees;
|
|
23
|
+
for (let epochSlot = 0; epochSlot < SLOTS_PER_EPOCH; epochSlot++) {
|
|
24
|
+
const slotCommittees = epochCommittees[epochSlot];
|
|
25
|
+
for (let i = 0, committeesAtSlot = slotCommittees.length; i < committeesAtSlot; i++) {
|
|
26
|
+
for (let j = 0, committeeLength = slotCommittees[i].length; j < committeeLength; j++) {
|
|
27
|
+
const validatorIndex = slotCommittees[i][j];
|
|
28
|
+
if (requestedValidatorIndicesSet.has(validatorIndex)) {
|
|
29
|
+
duties.set(validatorIndex, {
|
|
30
|
+
validatorIndex,
|
|
31
|
+
committeeLength,
|
|
32
|
+
committeesAtSlot,
|
|
33
|
+
validatorCommitteeIndex: j,
|
|
34
|
+
committeeIndex: i,
|
|
35
|
+
slot: epochShuffling.epoch * SLOTS_PER_EPOCH + epochSlot,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return duties;
|
|
43
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import {ETH1_ADDRESS_WITHDRAWAL_PREFIX} from "@lodestar/params";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/capella/beacon-chain.md#has_eth1_withdrawal_credential
|
|
5
|
+
*/
|
|
6
|
+
export function hasEth1WithdrawalCredential(withdrawalCredentials: Uint8Array): boolean {
|
|
7
|
+
return withdrawalCredentials[0] === ETH1_ADDRESS_WITHDRAWAL_PREFIX;
|
|
8
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
+
import {GENESIS_SLOT, ZERO_HASH} from "@lodestar/params";
|
|
3
|
+
import {phase0, ssz} from "@lodestar/types";
|
|
4
|
+
import {BeaconStateAllForks} from "../types.js";
|
|
5
|
+
import {blockToHeader} from "./blockRoot.js";
|
|
6
|
+
import {computeCheckpointEpochAtStateSlot} from "./epoch.js";
|
|
7
|
+
|
|
8
|
+
export function computeAnchorCheckpoint(
|
|
9
|
+
config: ChainForkConfig,
|
|
10
|
+
anchorState: BeaconStateAllForks
|
|
11
|
+
): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} {
|
|
12
|
+
let blockHeader: phase0.BeaconBlockHeader;
|
|
13
|
+
let root: Uint8Array;
|
|
14
|
+
const blockTypes = config.getForkTypes(anchorState.latestBlockHeader.slot);
|
|
15
|
+
|
|
16
|
+
if (anchorState.latestBlockHeader.slot === GENESIS_SLOT) {
|
|
17
|
+
const block = blockTypes.BeaconBlock.defaultValue();
|
|
18
|
+
block.stateRoot = anchorState.hashTreeRoot();
|
|
19
|
+
blockHeader = blockToHeader(config, block);
|
|
20
|
+
root = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader);
|
|
21
|
+
} else {
|
|
22
|
+
blockHeader = ssz.phase0.BeaconBlockHeader.clone(anchorState.latestBlockHeader);
|
|
23
|
+
if (ssz.Root.equals(blockHeader.stateRoot, ZERO_HASH)) {
|
|
24
|
+
blockHeader.stateRoot = anchorState.hashTreeRoot();
|
|
25
|
+
}
|
|
26
|
+
root = ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
checkpoint: {
|
|
31
|
+
root,
|
|
32
|
+
// the checkpoint epoch = computeEpochAtSlot(anchorState.slot) + 1 if slot is not at epoch boundary
|
|
33
|
+
// this is similar to a process_slots() call
|
|
34
|
+
epoch: computeCheckpointEpochAtStateSlot(anchorState.slot),
|
|
35
|
+
},
|
|
36
|
+
blockHeader,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {ForkSeq, MAX_DEPOSITS} from "@lodestar/params";
|
|
2
|
+
import {UintNum64, phase0} from "@lodestar/types";
|
|
3
|
+
import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js";
|
|
4
|
+
|
|
5
|
+
export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: phase0.Eth1Data): UintNum64 {
|
|
6
|
+
const eth1DataToUse = eth1Data ?? state.eth1Data;
|
|
7
|
+
if (state.config.getForkSeq(state.slot) >= ForkSeq.electra) {
|
|
8
|
+
const electraState = state as CachedBeaconStateElectra;
|
|
9
|
+
// eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64
|
|
10
|
+
// since the result lies within upper and lower bound of UintNum64
|
|
11
|
+
const eth1DataIndexLimit: UintNum64 =
|
|
12
|
+
eth1DataToUse.depositCount < electraState.depositRequestsStartIndex
|
|
13
|
+
? eth1DataToUse.depositCount
|
|
14
|
+
: Number(electraState.depositRequestsStartIndex);
|
|
15
|
+
|
|
16
|
+
if (state.eth1DepositIndex < eth1DataIndexLimit) {
|
|
17
|
+
return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex);
|
|
18
|
+
}
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
return Math.min(MAX_DEPOSITS, eth1DataToUse.depositCount - state.eth1DepositIndex);
|
|
22
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {DomainType, Epoch, Root, Version, phase0, ssz} from "@lodestar/types";
|
|
2
|
+
|
|
3
|
+
// Only used by processDeposit + lightclient
|
|
4
|
+
/**
|
|
5
|
+
* Return the domain for the [[domainType]] and [[forkVersion]].
|
|
6
|
+
*/
|
|
7
|
+
export function computeDomain(domainType: DomainType, forkVersion: Version, genesisValidatorRoot: Root): Uint8Array {
|
|
8
|
+
const forkDataRoot = computeForkDataRoot(forkVersion, genesisValidatorRoot);
|
|
9
|
+
const domain = new Uint8Array(32);
|
|
10
|
+
domain.set(domainType, 0);
|
|
11
|
+
domain.set(forkDataRoot.slice(0, 28), 4);
|
|
12
|
+
return domain;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Return the ForkVersion at an epoch from a Fork type
|
|
17
|
+
*/
|
|
18
|
+
export function getForkVersion(fork: phase0.Fork, epoch: Epoch): Version {
|
|
19
|
+
return epoch < fork.epoch ? fork.previousVersion : fork.currentVersion;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Used primarily in signature domains to avoid collisions across forks/chains.
|
|
24
|
+
*/
|
|
25
|
+
export function computeForkDataRoot(currentVersion: Version, genesisValidatorsRoot: Root): Uint8Array {
|
|
26
|
+
const forkData: phase0.ForkData = {
|
|
27
|
+
currentVersion,
|
|
28
|
+
genesisValidatorsRoot,
|
|
29
|
+
};
|
|
30
|
+
return ssz.phase0.ForkData.hashTreeRoot(forkData);
|
|
31
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {COMPOUNDING_WITHDRAWAL_PREFIX, GENESIS_SLOT, MIN_ACTIVATION_BALANCE} from "@lodestar/params";
|
|
2
|
+
import {ValidatorIndex, ssz} from "@lodestar/types";
|
|
3
|
+
import {G2_POINT_AT_INFINITY} from "../constants/constants.js";
|
|
4
|
+
import {CachedBeaconStateElectra} from "../types.js";
|
|
5
|
+
import {hasEth1WithdrawalCredential} from "./capella.js";
|
|
6
|
+
|
|
7
|
+
export function hasCompoundingWithdrawalCredential(withdrawalCredentials: Uint8Array): boolean {
|
|
8
|
+
return withdrawalCredentials[0] === COMPOUNDING_WITHDRAWAL_PREFIX;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function hasExecutionWithdrawalCredential(withdrawalCredentials: Uint8Array): boolean {
|
|
12
|
+
return (
|
|
13
|
+
hasCompoundingWithdrawalCredential(withdrawalCredentials) || hasEth1WithdrawalCredential(withdrawalCredentials)
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function switchToCompoundingValidator(state: CachedBeaconStateElectra, index: ValidatorIndex): void {
|
|
18
|
+
const validator = state.validators.get(index);
|
|
19
|
+
|
|
20
|
+
// directly modifying the byte leads to ssz missing the modification resulting into
|
|
21
|
+
// wrong root compute, although slicing can be avoided but anyway this is not going
|
|
22
|
+
// to be a hot path so its better to clean slice and avoid side effects
|
|
23
|
+
const newWithdrawalCredentials = Uint8Array.prototype.slice.call(
|
|
24
|
+
validator.withdrawalCredentials,
|
|
25
|
+
0,
|
|
26
|
+
validator.withdrawalCredentials.length
|
|
27
|
+
);
|
|
28
|
+
newWithdrawalCredentials[0] = COMPOUNDING_WITHDRAWAL_PREFIX;
|
|
29
|
+
validator.withdrawalCredentials = newWithdrawalCredentials;
|
|
30
|
+
queueExcessActiveBalance(state, index);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function queueExcessActiveBalance(state: CachedBeaconStateElectra, index: ValidatorIndex): void {
|
|
34
|
+
const balance = state.balances.get(index);
|
|
35
|
+
if (balance > MIN_ACTIVATION_BALANCE) {
|
|
36
|
+
const validator = state.validators.getReadonly(index);
|
|
37
|
+
const excessBalance = balance - MIN_ACTIVATION_BALANCE;
|
|
38
|
+
state.balances.set(index, MIN_ACTIVATION_BALANCE);
|
|
39
|
+
|
|
40
|
+
const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({
|
|
41
|
+
pubkey: validator.pubkey,
|
|
42
|
+
withdrawalCredentials: validator.withdrawalCredentials,
|
|
43
|
+
amount: excessBalance,
|
|
44
|
+
// Use bls.G2_POINT_AT_INFINITY as a signature field placeholder
|
|
45
|
+
signature: G2_POINT_AT_INFINITY,
|
|
46
|
+
// Use GENESIS_SLOT to distinguish from a pending deposit request
|
|
47
|
+
slot: GENESIS_SLOT,
|
|
48
|
+
});
|
|
49
|
+
state.pendingDeposits.push(pendingDeposit);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Since we share pubkey2index, pubkey maybe added by other epoch transition but we don't have that validator in this state
|
|
55
|
+
*/
|
|
56
|
+
export function isPubkeyKnown(state: CachedBeaconStateElectra, pubkey: Uint8Array): boolean {
|
|
57
|
+
return isValidatorKnown(state, state.epochCtx.getValidatorIndex(pubkey));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Since we share pubkey2index, validatorIndex maybe not null but we don't have that validator in this state
|
|
62
|
+
*/
|
|
63
|
+
export function isValidatorKnown(
|
|
64
|
+
state: CachedBeaconStateElectra,
|
|
65
|
+
index: ValidatorIndex | null
|
|
66
|
+
): index is ValidatorIndex {
|
|
67
|
+
return index !== null && index < state.validators.length;
|
|
68
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD, GENESIS_EPOCH, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
2
|
+
import {BeaconState, Epoch, Gwei, Slot, SyncPeriod} from "@lodestar/types";
|
|
3
|
+
import {CachedBeaconStateElectra} from "../types.js";
|
|
4
|
+
import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "./validator.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Return the epoch number at the given slot.
|
|
8
|
+
*/
|
|
9
|
+
export function computeEpochAtSlot(slot: Slot): Epoch {
|
|
10
|
+
return Math.floor(slot / SLOTS_PER_EPOCH);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Return the epoch at the state slot for purposes of checkpoint.
|
|
15
|
+
* Ideally this slot % SLOTS_PER_EPOCH === 0, but just to handle the improbable case of
|
|
16
|
+
* non boundary slot, using ceil so that the state's latestBlockHeader would always
|
|
17
|
+
* lie before this epooch
|
|
18
|
+
*/
|
|
19
|
+
export function computeCheckpointEpochAtStateSlot(slot: Slot): Epoch {
|
|
20
|
+
return Math.ceil(slot / SLOTS_PER_EPOCH);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Return the starting slot of the given epoch.
|
|
25
|
+
*/
|
|
26
|
+
export function computeStartSlotAtEpoch(epoch: Epoch): Slot {
|
|
27
|
+
return epoch * SLOTS_PER_EPOCH;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Return the end slot of the given epoch.
|
|
32
|
+
*/
|
|
33
|
+
export function computeEndSlotAtEpoch(epoch: Epoch): Slot {
|
|
34
|
+
return computeStartSlotAtEpoch(epoch + 1) - 1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
|
|
39
|
+
*/
|
|
40
|
+
export function computeActivationExitEpoch(epoch: Epoch): Epoch {
|
|
41
|
+
return epoch + 1 + MAX_SEED_LOOKAHEAD;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function computeExitEpochAndUpdateChurn(state: CachedBeaconStateElectra, exitBalance: Gwei): number {
|
|
45
|
+
let earliestExitEpoch = Math.max(state.earliestExitEpoch, computeActivationExitEpoch(state.epochCtx.epoch));
|
|
46
|
+
const perEpochChurn = getActivationExitChurnLimit(state.epochCtx);
|
|
47
|
+
|
|
48
|
+
// New epoch for exits.
|
|
49
|
+
let exitBalanceToConsume =
|
|
50
|
+
state.earliestExitEpoch < earliestExitEpoch ? perEpochChurn : Number(state.exitBalanceToConsume);
|
|
51
|
+
|
|
52
|
+
// Exit doesn't fit in the current earliest epoch.
|
|
53
|
+
if (exitBalance > exitBalanceToConsume) {
|
|
54
|
+
const balanceToProcess = Number(exitBalance) - exitBalanceToConsume;
|
|
55
|
+
const additionalEpochs = Math.floor((balanceToProcess - 1) / perEpochChurn) + 1;
|
|
56
|
+
earliestExitEpoch += additionalEpochs;
|
|
57
|
+
exitBalanceToConsume += additionalEpochs * perEpochChurn;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Consume the balance and update state variables.
|
|
61
|
+
state.exitBalanceToConsume = BigInt(exitBalanceToConsume) - exitBalance;
|
|
62
|
+
state.earliestExitEpoch = earliestExitEpoch;
|
|
63
|
+
|
|
64
|
+
return state.earliestExitEpoch;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function computeConsolidationEpochAndUpdateChurn(
|
|
68
|
+
state: CachedBeaconStateElectra,
|
|
69
|
+
consolidationBalance: Gwei
|
|
70
|
+
): number {
|
|
71
|
+
let earliestConsolidationEpoch = Math.max(
|
|
72
|
+
state.earliestConsolidationEpoch,
|
|
73
|
+
computeActivationExitEpoch(state.epochCtx.epoch)
|
|
74
|
+
);
|
|
75
|
+
const perEpochConsolidationChurn = getConsolidationChurnLimit(state.epochCtx);
|
|
76
|
+
|
|
77
|
+
// New epoch for consolidations
|
|
78
|
+
let consolidationBalanceToConsume =
|
|
79
|
+
state.earliestConsolidationEpoch < earliestConsolidationEpoch
|
|
80
|
+
? perEpochConsolidationChurn
|
|
81
|
+
: Number(state.consolidationBalanceToConsume);
|
|
82
|
+
|
|
83
|
+
// Consolidation doesn't fit in the current earliest epoch.
|
|
84
|
+
if (consolidationBalance > consolidationBalanceToConsume) {
|
|
85
|
+
const balanceToProcess = Number(consolidationBalance) - consolidationBalanceToConsume;
|
|
86
|
+
const additionalEpochs = Math.floor((balanceToProcess - 1) / perEpochConsolidationChurn) + 1;
|
|
87
|
+
earliestConsolidationEpoch += additionalEpochs;
|
|
88
|
+
consolidationBalanceToConsume += additionalEpochs * perEpochConsolidationChurn;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Consume the balance and update state variables.
|
|
92
|
+
state.consolidationBalanceToConsume = BigInt(consolidationBalanceToConsume) - consolidationBalance;
|
|
93
|
+
state.earliestConsolidationEpoch = earliestConsolidationEpoch;
|
|
94
|
+
|
|
95
|
+
return state.earliestConsolidationEpoch;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Return the current epoch of the given state.
|
|
100
|
+
*/
|
|
101
|
+
export function getCurrentEpoch(state: Pick<BeaconState, "slot">): Epoch {
|
|
102
|
+
return computeEpochAtSlot(state.slot);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Return the previous epoch of the given state.
|
|
107
|
+
*/
|
|
108
|
+
export function getPreviousEpoch(state: Pick<BeaconState, "slot">): Epoch {
|
|
109
|
+
const currentEpoch = getCurrentEpoch(state);
|
|
110
|
+
if (currentEpoch === GENESIS_EPOCH) {
|
|
111
|
+
return GENESIS_EPOCH;
|
|
112
|
+
}
|
|
113
|
+
return currentEpoch - 1;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Return the sync committee period at slot
|
|
118
|
+
*/
|
|
119
|
+
export function computeSyncPeriodAtSlot(slot: Slot): SyncPeriod {
|
|
120
|
+
return computeSyncPeriodAtEpoch(computeEpochAtSlot(slot));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Return the sync committee period at epoch
|
|
125
|
+
*/
|
|
126
|
+
export function computeSyncPeriodAtEpoch(epoch: Epoch): SyncPeriod {
|
|
127
|
+
return Math.floor(epoch / EPOCHS_PER_SYNC_COMMITTEE_PERIOD);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Determine if the given slot is start slot of an epoch
|
|
132
|
+
*/
|
|
133
|
+
export function isStartSlotOfEpoch(slot: Slot): boolean {
|
|
134
|
+
return slot % SLOTS_PER_EPOCH === 0;
|
|
135
|
+
}
|