@lodestar/state-transition 1.43.0-dev.4fb05c546d → 1.43.0-dev.4fe6b362c9
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/index.d.ts +2 -2
- package/lib/block/index.d.ts.map +1 -1
- package/lib/block/index.js +11 -4
- package/lib/block/index.js.map +1 -1
- package/lib/block/processConsolidationRequest.d.ts.map +1 -1
- package/lib/block/processConsolidationRequest.js +2 -1
- package/lib/block/processConsolidationRequest.js.map +1 -1
- package/lib/block/processDepositRequest.d.ts +3 -11
- package/lib/block/processDepositRequest.d.ts.map +1 -1
- package/lib/block/processDepositRequest.js +27 -35
- package/lib/block/processDepositRequest.js.map +1 -1
- package/lib/block/processParentExecutionPayload.d.ts +20 -0
- package/lib/block/processParentExecutionPayload.d.ts.map +1 -0
- package/lib/block/processParentExecutionPayload.js +101 -0
- package/lib/block/processParentExecutionPayload.js.map +1 -0
- package/lib/block/processWithdrawals.d.ts.map +1 -1
- package/lib/block/processWithdrawals.js +10 -4
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/cache/epochCache.js +3 -3
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/epoch/processPendingDeposits.d.ts.map +1 -1
- package/lib/epoch/processPendingDeposits.js +4 -2
- package/lib/epoch/processPendingDeposits.js.map +1 -1
- package/lib/lightClient/spec/index.d.ts +22 -0
- package/lib/lightClient/spec/index.d.ts.map +1 -0
- package/lib/lightClient/spec/index.js +58 -0
- package/lib/lightClient/spec/index.js.map +1 -0
- package/lib/lightClient/spec/isBetterUpdate.d.ts +23 -0
- package/lib/lightClient/spec/isBetterUpdate.d.ts.map +1 -0
- package/lib/lightClient/spec/isBetterUpdate.js +66 -0
- package/lib/lightClient/spec/isBetterUpdate.js.map +1 -0
- package/lib/lightClient/spec/processLightClientUpdate.d.ts +12 -0
- package/lib/lightClient/spec/processLightClientUpdate.d.ts.map +1 -0
- package/lib/lightClient/spec/processLightClientUpdate.js +80 -0
- package/lib/lightClient/spec/processLightClientUpdate.js.map +1 -0
- package/lib/lightClient/spec/store.d.ts +45 -0
- package/lib/lightClient/spec/store.d.ts.map +1 -0
- package/lib/lightClient/spec/store.js +56 -0
- package/lib/lightClient/spec/store.js.map +1 -0
- package/lib/lightClient/spec/utils.d.ts +47 -0
- package/lib/lightClient/spec/utils.d.ts.map +1 -0
- package/lib/lightClient/spec/utils.js +197 -0
- package/lib/lightClient/spec/utils.js.map +1 -0
- package/lib/lightClient/spec/validateLightClientBootstrap.d.ts +4 -0
- package/lib/lightClient/spec/validateLightClientBootstrap.d.ts.map +1 -0
- package/lib/lightClient/spec/validateLightClientBootstrap.js +22 -0
- package/lib/lightClient/spec/validateLightClientBootstrap.js.map +1 -0
- package/lib/lightClient/spec/validateLightClientUpdate.d.ts +5 -0
- package/lib/lightClient/spec/validateLightClientUpdate.d.ts.map +1 -0
- package/lib/lightClient/spec/validateLightClientUpdate.js +88 -0
- package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -0
- package/lib/signatureSets/executionPayloadEnvelope.js +1 -1
- package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
- package/lib/signatureSets/index.d.ts +1 -0
- package/lib/signatureSets/index.d.ts.map +1 -1
- package/lib/signatureSets/index.js +1 -0
- package/lib/signatureSets/index.js.map +1 -1
- package/lib/signatureSets/proposerPreferences.d.ts +4 -0
- package/lib/signatureSets/proposerPreferences.d.ts.map +1 -0
- package/lib/signatureSets/proposerPreferences.js +8 -0
- package/lib/signatureSets/proposerPreferences.js.map +1 -0
- package/lib/slot/upgradeStateToElectra.d.ts.map +1 -1
- package/lib/slot/upgradeStateToElectra.js +2 -2
- package/lib/slot/upgradeStateToElectra.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +34 -28
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +20 -7
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +52 -16
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +14 -4
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/util/computeAnchorCheckpoint.d.ts +1 -1
- package/lib/util/computeAnchorCheckpoint.d.ts.map +1 -1
- package/lib/util/computeAnchorCheckpoint.js +6 -19
- package/lib/util/computeAnchorCheckpoint.js.map +1 -1
- package/lib/util/epoch.d.ts.map +1 -1
- package/lib/util/epoch.js +6 -4
- package/lib/util/epoch.js.map +1 -1
- package/lib/util/gloas.d.ts +0 -1
- package/lib/util/gloas.d.ts.map +1 -1
- package/lib/util/gloas.js +0 -3
- package/lib/util/gloas.js.map +1 -1
- package/lib/util/index.d.ts +1 -0
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +1 -0
- package/lib/util/index.js.map +1 -1
- package/lib/util/loadState/loadState.js +4 -4
- package/lib/util/loadState/loadState.js.map +1 -1
- package/lib/util/pendingDepositsLookup.d.ts +40 -0
- package/lib/util/pendingDepositsLookup.d.ts.map +1 -0
- package/lib/util/pendingDepositsLookup.js +84 -0
- package/lib/util/pendingDepositsLookup.js.map +1 -0
- package/lib/util/shuffling.d.ts +6 -5
- package/lib/util/shuffling.d.ts.map +1 -1
- package/lib/util/shuffling.js +13 -15
- package/lib/util/shuffling.js.map +1 -1
- package/lib/util/validator.d.ts +14 -2
- package/lib/util/validator.d.ts.map +1 -1
- package/lib/util/validator.js +24 -2
- package/lib/util/validator.js.map +1 -1
- package/package.json +13 -8
- package/src/block/index.ts +12 -4
- package/src/block/processConsolidationRequest.ts +2 -1
- package/src/block/processDepositRequest.ts +29 -47
- package/src/block/processParentExecutionPayload.ts +117 -0
- package/src/block/processWithdrawals.ts +12 -4
- package/src/cache/epochCache.ts +3 -3
- package/src/epoch/processPendingDeposits.ts +5 -2
- package/src/lightClient/spec/index.ts +101 -0
- package/src/lightClient/spec/isBetterUpdate.ts +94 -0
- package/src/lightClient/spec/processLightClientUpdate.ts +119 -0
- package/src/lightClient/spec/store.ts +106 -0
- package/src/lightClient/spec/utils.ts +317 -0
- package/src/lightClient/spec/validateLightClientBootstrap.ts +39 -0
- package/src/lightClient/spec/validateLightClientUpdate.ts +145 -0
- package/src/signatureSets/executionPayloadEnvelope.ts +1 -1
- package/src/signatureSets/index.ts +1 -0
- package/src/signatureSets/proposerPreferences.ts +12 -0
- package/src/slot/upgradeStateToElectra.ts +4 -2
- package/src/slot/upgradeStateToGloas.ts +44 -44
- package/src/stateView/beaconStateView.ts +60 -25
- package/src/stateView/interface.ts +16 -7
- package/src/util/computeAnchorCheckpoint.ts +6 -19
- package/src/util/epoch.ts +13 -4
- package/src/util/gloas.ts +0 -4
- package/src/util/index.ts +1 -0
- package/src/util/loadState/loadState.ts +4 -4
- package/src/util/pendingDepositsLookup.ts +105 -0
- package/src/util/shuffling.ts +17 -15
- package/src/util/validator.ts +42 -2
- package/lib/block/processExecutionPayloadEnvelope.d.ts +0 -9
- package/lib/block/processExecutionPayloadEnvelope.d.ts.map +0 -1
- package/lib/block/processExecutionPayloadEnvelope.js +0 -106
- package/lib/block/processExecutionPayloadEnvelope.js.map +0 -1
- package/src/block/processExecutionPayloadEnvelope.ts +0 -175
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {PublicKey, Signature, fastAggregateVerify} from "@chainsafe/blst";
|
|
2
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
+
import {
|
|
4
|
+
DOMAIN_SYNC_COMMITTEE,
|
|
5
|
+
FINALIZED_ROOT_DEPTH,
|
|
6
|
+
FINALIZED_ROOT_DEPTH_ELECTRA,
|
|
7
|
+
FINALIZED_ROOT_INDEX,
|
|
8
|
+
FINALIZED_ROOT_INDEX_ELECTRA,
|
|
9
|
+
GENESIS_SLOT,
|
|
10
|
+
MIN_SYNC_COMMITTEE_PARTICIPANTS,
|
|
11
|
+
NEXT_SYNC_COMMITTEE_DEPTH,
|
|
12
|
+
NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA,
|
|
13
|
+
NEXT_SYNC_COMMITTEE_INDEX,
|
|
14
|
+
NEXT_SYNC_COMMITTEE_INDEX_ELECTRA,
|
|
15
|
+
} from "@lodestar/params";
|
|
16
|
+
import {LightClientUpdate, Root, isElectraLightClientUpdate, ssz} from "@lodestar/types";
|
|
17
|
+
import type {ILightClientStore, SyncCommitteeFast} from "./store.js";
|
|
18
|
+
import {
|
|
19
|
+
ZERO_HASH,
|
|
20
|
+
getParticipantPubkeys,
|
|
21
|
+
isFinalityUpdate,
|
|
22
|
+
isSyncCommitteeUpdate,
|
|
23
|
+
isValidLightClientHeader,
|
|
24
|
+
isValidMerkleBranch,
|
|
25
|
+
isZeroedHeader,
|
|
26
|
+
isZeroedSyncCommittee,
|
|
27
|
+
sumBits,
|
|
28
|
+
} from "./utils.js";
|
|
29
|
+
|
|
30
|
+
export function validateLightClientUpdate(
|
|
31
|
+
config: ChainForkConfig,
|
|
32
|
+
store: ILightClientStore,
|
|
33
|
+
update: LightClientUpdate,
|
|
34
|
+
syncCommittee: SyncCommitteeFast
|
|
35
|
+
): void {
|
|
36
|
+
// Verify sync committee has sufficient participants
|
|
37
|
+
if (sumBits(update.syncAggregate.syncCommitteeBits) < MIN_SYNC_COMMITTEE_PARTICIPANTS) {
|
|
38
|
+
throw Error("Sync committee has not sufficient participants");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!isValidLightClientHeader(config, update.attestedHeader)) {
|
|
42
|
+
throw Error("Attested Header is not Valid Light Client Header");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Sanity check that slots are in correct order
|
|
46
|
+
if (update.signatureSlot <= update.attestedHeader.beacon.slot) {
|
|
47
|
+
throw Error(
|
|
48
|
+
`signature slot ${update.signatureSlot} must be after attested header slot ${update.attestedHeader.beacon.slot}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
if (update.attestedHeader.beacon.slot < update.finalizedHeader.beacon.slot) {
|
|
52
|
+
throw Error(
|
|
53
|
+
`attested header slot ${update.signatureSlot} must be after finalized header slot ${update.finalizedHeader.beacon.slot}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Verify that the `finality_branch`, if present, confirms `finalized_header`
|
|
58
|
+
// to match the finalized checkpoint root saved in the state of `attested_header`.
|
|
59
|
+
// Note that the genesis finalized checkpoint root is represented as a zero hash.
|
|
60
|
+
if (!isFinalityUpdate(update)) {
|
|
61
|
+
if (!isZeroedHeader(update.finalizedHeader.beacon)) {
|
|
62
|
+
throw Error("finalizedHeader must be zero for non-finality update");
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
let finalizedRoot: Root;
|
|
66
|
+
|
|
67
|
+
if (update.finalizedHeader.beacon.slot === GENESIS_SLOT) {
|
|
68
|
+
if (!isZeroedHeader(update.finalizedHeader.beacon)) {
|
|
69
|
+
throw Error("finalizedHeader must be zero for not finality update");
|
|
70
|
+
}
|
|
71
|
+
finalizedRoot = ZERO_HASH;
|
|
72
|
+
} else {
|
|
73
|
+
if (!isValidLightClientHeader(config, update.finalizedHeader)) {
|
|
74
|
+
throw Error("Finalized Header is not valid Light Client Header");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
finalizedRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(update.finalizedHeader.beacon);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (
|
|
81
|
+
!isValidMerkleBranch(
|
|
82
|
+
finalizedRoot,
|
|
83
|
+
update.finalityBranch,
|
|
84
|
+
isElectraLightClientUpdate(update) ? FINALIZED_ROOT_DEPTH_ELECTRA : FINALIZED_ROOT_DEPTH,
|
|
85
|
+
isElectraLightClientUpdate(update) ? FINALIZED_ROOT_INDEX_ELECTRA : FINALIZED_ROOT_INDEX,
|
|
86
|
+
update.attestedHeader.beacon.stateRoot
|
|
87
|
+
)
|
|
88
|
+
) {
|
|
89
|
+
throw Error("Invalid finality header merkle branch");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Verify that the `next_sync_committee`, if present, actually is the next sync committee saved in the
|
|
94
|
+
// state of the `attested_header`
|
|
95
|
+
if (!isSyncCommitteeUpdate(update)) {
|
|
96
|
+
if (!isZeroedSyncCommittee(update.nextSyncCommittee)) {
|
|
97
|
+
throw Error("nextSyncCommittee must be zero for non sync committee update");
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
if (
|
|
101
|
+
!isValidMerkleBranch(
|
|
102
|
+
ssz.altair.SyncCommittee.hashTreeRoot(update.nextSyncCommittee),
|
|
103
|
+
update.nextSyncCommitteeBranch,
|
|
104
|
+
isElectraLightClientUpdate(update) ? NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA : NEXT_SYNC_COMMITTEE_DEPTH,
|
|
105
|
+
isElectraLightClientUpdate(update) ? NEXT_SYNC_COMMITTEE_INDEX_ELECTRA : NEXT_SYNC_COMMITTEE_INDEX,
|
|
106
|
+
update.attestedHeader.beacon.stateRoot
|
|
107
|
+
)
|
|
108
|
+
) {
|
|
109
|
+
throw Error("Invalid next sync committee merkle branch");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Verify sync committee aggregate signature
|
|
114
|
+
|
|
115
|
+
const participantPubkeys = getParticipantPubkeys(syncCommittee.pubkeys, update.syncAggregate.syncCommitteeBits);
|
|
116
|
+
|
|
117
|
+
const signingRoot = ssz.phase0.SigningData.hashTreeRoot({
|
|
118
|
+
objectRoot: ssz.phase0.BeaconBlockHeader.hashTreeRoot(update.attestedHeader.beacon),
|
|
119
|
+
domain: store.config.getDomain(update.signatureSlot - 1, DOMAIN_SYNC_COMMITTEE),
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
if (!isValidBlsAggregate(participantPubkeys, signingRoot, update.syncAggregate.syncCommitteeSignature)) {
|
|
123
|
+
throw Error("Invalid aggregate signature");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Same as BLS.verifyAggregate but with detailed error messages
|
|
129
|
+
*/
|
|
130
|
+
function isValidBlsAggregate(publicKeys: PublicKey[], message: Uint8Array, signature: Uint8Array): boolean {
|
|
131
|
+
let sig: Signature;
|
|
132
|
+
try {
|
|
133
|
+
sig = Signature.fromBytes(signature, true);
|
|
134
|
+
} catch (e) {
|
|
135
|
+
(e as Error).message = `Error deserializing signature: ${(e as Error).message}`;
|
|
136
|
+
throw e;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
return fastAggregateVerify(message, publicKeys, sig);
|
|
141
|
+
} catch (e) {
|
|
142
|
+
(e as Error).message = `Error verifying signature: ${(e as Error).message}`;
|
|
143
|
+
throw e;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -11,7 +11,7 @@ export function getExecutionPayloadEnvelopeSigningRoot(
|
|
|
11
11
|
config: BeaconConfig,
|
|
12
12
|
envelope: gloas.ExecutionPayloadEnvelope
|
|
13
13
|
): Uint8Array {
|
|
14
|
-
const domain = config.getDomain(envelope.
|
|
14
|
+
const domain = config.getDomain(envelope.payload.slotNumber, DOMAIN_BEACON_BUILDER);
|
|
15
15
|
|
|
16
16
|
return computeSigningRoot(ssz.gloas.ExecutionPayloadEnvelope, envelope, domain);
|
|
17
17
|
}
|
|
@@ -20,6 +20,7 @@ export * from "./executionPayloadEnvelope.js";
|
|
|
20
20
|
export * from "./indexedAttestation.js";
|
|
21
21
|
export * from "./indexedPayloadAttestation.js";
|
|
22
22
|
export * from "./proposer.js";
|
|
23
|
+
export * from "./proposerPreferences.js";
|
|
23
24
|
export * from "./proposerSlashings.js";
|
|
24
25
|
export * from "./randao.js";
|
|
25
26
|
export * from "./voluntaryExits.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
+
import {DOMAIN_PROPOSER_PREFERENCES} from "@lodestar/params";
|
|
3
|
+
import {gloas, ssz} from "@lodestar/types";
|
|
4
|
+
import {computeSigningRoot} from "../util/index.js";
|
|
5
|
+
|
|
6
|
+
export function getProposerPreferencesSigningRoot(
|
|
7
|
+
config: BeaconConfig,
|
|
8
|
+
preferences: gloas.ProposerPreferences
|
|
9
|
+
): Uint8Array {
|
|
10
|
+
const domain = config.getDomain(preferences.proposalSlot, DOMAIN_PROPOSER_PREFERENCES);
|
|
11
|
+
return computeSigningRoot(ssz.gloas.ProposerPreferences, preferences, domain);
|
|
12
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {FAR_FUTURE_EPOCH, GENESIS_SLOT, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params";
|
|
1
|
+
import {FAR_FUTURE_EPOCH, ForkSeq, GENESIS_SLOT, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params";
|
|
2
2
|
import {ValidatorIndex, ssz} from "@lodestar/types";
|
|
3
3
|
import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js";
|
|
4
4
|
import {G2_POINT_AT_INFINITY} from "../constants/constants.js";
|
|
@@ -78,7 +78,9 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache
|
|
|
78
78
|
stateElectraView.commit();
|
|
79
79
|
const tmpElectraState = getCachedBeaconState(stateElectraView, stateDeneb);
|
|
80
80
|
stateElectraView.exitBalanceToConsume = BigInt(getActivationExitChurnLimit(tmpElectraState.epochCtx));
|
|
81
|
-
stateElectraView.consolidationBalanceToConsume = BigInt(
|
|
81
|
+
stateElectraView.consolidationBalanceToConsume = BigInt(
|
|
82
|
+
getConsolidationChurnLimit(ForkSeq.electra, tmpElectraState.epochCtx)
|
|
83
|
+
);
|
|
82
84
|
|
|
83
85
|
preActivation.sort((i0, i1) => {
|
|
84
86
|
const res = validatorsArr[i0].activationEligibilityEpoch - validatorsArr[i1].activationEligibilityEpoch;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
2
2
|
import {ssz} from "@lodestar/types";
|
|
3
|
-
import {
|
|
4
|
-
import {isValidDepositSignature} from "../block/processDeposit.js";
|
|
3
|
+
import {toPubkeyHex} from "@lodestar/utils";
|
|
5
4
|
import {applyDepositForBuilder} from "../block/processDepositRequest.js";
|
|
6
5
|
import {getCachedBeaconState} from "../cache/stateCache.js";
|
|
7
6
|
import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
|
|
8
7
|
import {initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
|
|
9
8
|
import {isValidatorKnown} from "../util/index.js";
|
|
9
|
+
import {PendingDepositsLookup} from "../util/pendingDepositsLookup.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Upgrade a state from Fulu to Gloas.
|
|
@@ -48,6 +48,9 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
48
48
|
stateGloasView.currentSyncCommittee = stateGloasCloned.currentSyncCommittee;
|
|
49
49
|
stateGloasView.nextSyncCommittee = stateGloasCloned.nextSyncCommittee;
|
|
50
50
|
stateGloasView.latestExecutionPayloadBid.blockHash = stateFulu.latestExecutionPayloadHeader.blockHash;
|
|
51
|
+
stateGloasView.latestExecutionPayloadBid.executionRequestsRoot = ssz.electra.ExecutionRequests.hashTreeRoot(
|
|
52
|
+
ssz.electra.ExecutionRequests.defaultValue()
|
|
53
|
+
);
|
|
51
54
|
stateGloasView.nextWithdrawalIndex = stateGloasCloned.nextWithdrawalIndex;
|
|
52
55
|
stateGloasView.nextWithdrawalValidatorIndex = stateGloasCloned.nextWithdrawalValidatorIndex;
|
|
53
56
|
stateGloasView.historicalSummaries = stateGloasCloned.historicalSummaries;
|
|
@@ -86,63 +89,60 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
86
89
|
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.2/specs/gloas/fork.md#new-onboard_builders_from_pending_deposits
|
|
87
90
|
*/
|
|
88
91
|
function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void {
|
|
89
|
-
// Track pubkeys of new validators to keep their deposits pending
|
|
90
|
-
const validatorPubkeys = new Set<string>();
|
|
91
|
-
|
|
92
92
|
// Track pubkeys of new builders added when applying deposits
|
|
93
93
|
const builderPubkeys = new Set<string>();
|
|
94
94
|
|
|
95
|
-
const
|
|
95
|
+
const pendingDeposits = ssz.electra.PendingDeposits.defaultViewDU();
|
|
96
|
+
const pendingDepositsLookup = PendingDepositsLookup.buildEmpty();
|
|
97
|
+
|
|
96
98
|
for (let i = 0; i < state.pendingDeposits.length; i++) {
|
|
97
99
|
const deposit = state.pendingDeposits.getReadonly(i);
|
|
98
100
|
|
|
99
101
|
const validatorIndex = state.epochCtx.getValidatorIndex(deposit.pubkey);
|
|
100
|
-
const pubkeyHex =
|
|
102
|
+
const pubkeyHex = toPubkeyHex(deposit.pubkey);
|
|
101
103
|
|
|
102
|
-
// Deposits for existing validators stay in pending queue
|
|
103
|
-
if (isValidatorKnown(state, validatorIndex)
|
|
104
|
-
|
|
104
|
+
// Deposits for existing validators stay in the pending queue
|
|
105
|
+
if (isValidatorKnown(state, validatorIndex)) {
|
|
106
|
+
pendingDeposits.push(deposit);
|
|
107
|
+
pendingDepositsLookup.add(deposit, pubkeyHex);
|
|
105
108
|
continue;
|
|
106
109
|
}
|
|
107
110
|
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
deposit
|
|
118
|
-
deposit
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
111
|
+
// `applyDepositForBuilder` can mutate the state and add a builder to the registry, so
|
|
112
|
+
// the set of builder pubkeys must be recomputed each iteration. `builderPubkeys` stands
|
|
113
|
+
// in for the spec's `[b.pubkey for b in state.builders]`: `state.builders` starts empty
|
|
114
|
+
// at the fork, so every builder is one added in a previous iteration of this loop.
|
|
115
|
+
if (!builderPubkeys.has(pubkeyHex)) {
|
|
116
|
+
// Deposits for non-builders stay in the pending queue. If there is a valid pending
|
|
117
|
+
// deposit for a new validator with this pubkey, keep this deposit in the pending
|
|
118
|
+
// queue to be applied to that validator later.
|
|
119
|
+
if (!isBuilderWithdrawalCredential(deposit.withdrawalCredentials)) {
|
|
120
|
+
pendingDeposits.push(deposit);
|
|
121
|
+
pendingDepositsLookup.add(deposit, pubkeyHex);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (pendingDepositsLookup.hasPendingValidator(state.config, pubkeyHex)) {
|
|
125
|
+
pendingDeposits.push(deposit);
|
|
126
|
+
pendingDepositsLookup.add(deposit, pubkeyHex);
|
|
127
|
+
continue;
|
|
125
128
|
}
|
|
126
|
-
continue;
|
|
127
129
|
}
|
|
128
130
|
|
|
129
|
-
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
validatorPubkeys.add(pubkeyHex);
|
|
143
|
-
remainingPendingDeposits.push(deposit);
|
|
131
|
+
const buildersLenBefore = state.builders.length;
|
|
132
|
+
// TODO GLOAS: handle 20k 1ETH deposits on time
|
|
133
|
+
// there is a note in the spec https://github.com/ethereum/consensus-specs/pull/5227
|
|
134
|
+
applyDepositForBuilder(
|
|
135
|
+
state,
|
|
136
|
+
deposit.pubkey,
|
|
137
|
+
deposit.withdrawalCredentials,
|
|
138
|
+
deposit.amount,
|
|
139
|
+
deposit.signature,
|
|
140
|
+
deposit.slot
|
|
141
|
+
);
|
|
142
|
+
if (state.builders.length > buildersLenBefore) {
|
|
143
|
+
builderPubkeys.add(pubkeyHex);
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
state.pendingDeposits =
|
|
147
|
+
state.pendingDeposits = pendingDeposits;
|
|
148
148
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {CompactMultiProof, ProofType, Tree, createProof} from "@chainsafe/persistent-merkle-tree";
|
|
2
2
|
import {BitArray, ByteViews} from "@chainsafe/ssz";
|
|
3
3
|
import {BeaconConfig} from "@lodestar/config";
|
|
4
|
-
import {ForkName, ForkSeq, SLOTS_PER_HISTORICAL_ROOT
|
|
4
|
+
import {ForkName, ForkSeq, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
5
5
|
import {
|
|
6
6
|
BeaconBlock,
|
|
7
7
|
BeaconState,
|
|
@@ -28,8 +28,7 @@ import {
|
|
|
28
28
|
rewards,
|
|
29
29
|
} from "@lodestar/types";
|
|
30
30
|
import {Checkpoint, Fork} from "@lodestar/types/phase0";
|
|
31
|
-
import {
|
|
32
|
-
import {ProcessExecutionPayloadEnvelopeOpts} from "../block/processExecutionPayloadEnvelope.js";
|
|
31
|
+
import {applyParentExecutionPayload} from "../block/processParentExecutionPayload.js";
|
|
33
32
|
import {VoluntaryExitValidity, getVoluntaryExitValidity} from "../block/processVoluntaryExit.js";
|
|
34
33
|
import {getExpectedWithdrawals} from "../block/processWithdrawals.js";
|
|
35
34
|
import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
|
|
@@ -69,7 +68,7 @@ import {canBuilderCoverBid} from "../util/gloas.js";
|
|
|
69
68
|
import {loadState} from "../util/loadState/loadState.js";
|
|
70
69
|
import {getRandaoMix} from "../util/seed.js";
|
|
71
70
|
import {getLatestWeakSubjectivityCheckpointEpoch} from "../util/weakSubjectivity.js";
|
|
72
|
-
import {IBeaconStateView, IBeaconStateViewLatestFork} from "./interface.js";
|
|
71
|
+
import {IBeaconStateView, IBeaconStateViewGloas, IBeaconStateViewLatestFork, isStatePostGloas} from "./interface.js";
|
|
73
72
|
|
|
74
73
|
export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
75
74
|
private readonly config: BeaconConfig;
|
|
@@ -407,16 +406,44 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
407
406
|
}
|
|
408
407
|
|
|
409
408
|
/**
|
|
410
|
-
* Return the
|
|
411
|
-
* return -1 if validator is not in the PTC committee for the given slot.
|
|
409
|
+
* Return the PTCs for an epoch
|
|
412
410
|
*/
|
|
413
|
-
|
|
411
|
+
getEpochPTCs(epoch: Epoch): Uint32Array[] {
|
|
412
|
+
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
413
|
+
throw new Error("PTC committees are not supported before Gloas");
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const epochCtx = (this.cachedState as CachedBeaconStateGloas).epochCtx;
|
|
417
|
+
if (epoch === epochCtx.epoch) {
|
|
418
|
+
return epochCtx.payloadTimelinessCommittees;
|
|
419
|
+
}
|
|
420
|
+
if (epoch === epochCtx.nextEpoch) {
|
|
421
|
+
return epochCtx.nextPayloadTimelinessCommittees;
|
|
422
|
+
}
|
|
423
|
+
throw new Error(`PTC committees are not available for epoch=${epoch}`);
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Return all positions of the validator in the PTC committee for the given slot.
|
|
427
|
+
*
|
|
428
|
+
* `compute_ptc` samples by effective balance and may place the same validator at multiple
|
|
429
|
+
* positions, so a validator can have more than one index. Returns an empty array if the
|
|
430
|
+
* validator is not in the PTC for the given slot.
|
|
431
|
+
*
|
|
432
|
+
* Spec: gloas/fork-choice.md#new-on_payload_attestation_message
|
|
433
|
+
*/
|
|
434
|
+
getIndicesInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number[] {
|
|
414
435
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
415
436
|
throw new Error("PTC committees are not supported before Gloas");
|
|
416
437
|
}
|
|
417
438
|
|
|
418
439
|
const ptcCommittee = (this.cachedState as CachedBeaconStateGloas).epochCtx.getPayloadTimelinessCommittee(slot);
|
|
419
|
-
|
|
440
|
+
const indices: number[] = [];
|
|
441
|
+
for (let i = 0; i < ptcCommittee.length; i++) {
|
|
442
|
+
if (ptcCommittee[i] === validatorIndex) {
|
|
443
|
+
indices.push(i);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return indices;
|
|
420
447
|
}
|
|
421
448
|
|
|
422
449
|
// Shuffling and committees
|
|
@@ -704,7 +731,11 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
704
731
|
|
|
705
732
|
// Serialization
|
|
706
733
|
|
|
707
|
-
loadOtherState(
|
|
734
|
+
loadOtherState(
|
|
735
|
+
stateBytes: Uint8Array,
|
|
736
|
+
seedValidatorsBytes?: Uint8Array,
|
|
737
|
+
opts?: {preloadValidatorsAndBalances?: boolean}
|
|
738
|
+
): IBeaconStateView {
|
|
708
739
|
const {state} = loadState(this.config, this.cachedState, stateBytes, seedValidatorsBytes);
|
|
709
740
|
|
|
710
741
|
const cachedState = createCachedBeaconState(
|
|
@@ -719,9 +750,10 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
719
750
|
}
|
|
720
751
|
);
|
|
721
752
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
753
|
+
if (opts?.preloadValidatorsAndBalances) {
|
|
754
|
+
cachedState.validators.getAllReadonlyValues();
|
|
755
|
+
cachedState.balances.getAll();
|
|
756
|
+
}
|
|
725
757
|
|
|
726
758
|
return new BeaconStateView(cachedState);
|
|
727
759
|
}
|
|
@@ -779,19 +811,22 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
779
811
|
return new BeaconStateView(newState);
|
|
780
812
|
}
|
|
781
813
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
):
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
throw Error(`processExecutionPayloadEnvelope is only available for gloas+ forks, got fork=${fork}`);
|
|
814
|
+
/**
|
|
815
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.5/specs/gloas/validator.md#executionpayload
|
|
816
|
+
*/
|
|
817
|
+
withParentPayloadApplied(executionRequests: electra.ExecutionRequests): IBeaconStateViewGloas {
|
|
818
|
+
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
819
|
+
throw new Error("withParentPayloadApplied is not available before Gloas");
|
|
789
820
|
}
|
|
790
|
-
const
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
);
|
|
795
|
-
|
|
821
|
+
const stateCopy = this.cachedState.clone(true) as CachedBeaconStateGloas;
|
|
822
|
+
|
|
823
|
+
applyParentExecutionPayload(stateCopy, executionRequests);
|
|
824
|
+
|
|
825
|
+
const stateView = new BeaconStateView(stateCopy);
|
|
826
|
+
if (!isStatePostGloas(stateView)) {
|
|
827
|
+
throw new Error("Expected gloas state after clone");
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
return stateView;
|
|
796
831
|
}
|
|
797
832
|
}
|
|
@@ -41,7 +41,6 @@ import {
|
|
|
41
41
|
rewards,
|
|
42
42
|
} from "@lodestar/types";
|
|
43
43
|
import {Checkpoint, Fork} from "@lodestar/types/phase0";
|
|
44
|
-
import {ProcessExecutionPayloadEnvelopeOpts} from "../block/processExecutionPayloadEnvelope.js";
|
|
45
44
|
import {VoluntaryExitValidity} from "../block/processVoluntaryExit.js";
|
|
46
45
|
import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
|
|
47
46
|
import {EpochTransitionCacheOpts} from "../cache/epochTransitionCache.js";
|
|
@@ -138,7 +137,13 @@ export interface IBeaconStateView {
|
|
|
138
137
|
isStateValidatorsNodesPopulated(): boolean;
|
|
139
138
|
|
|
140
139
|
// Serialization
|
|
141
|
-
|
|
140
|
+
/** Set `preloadValidatorsAndBalances` only when the whole state will be consumed
|
|
141
|
+
* immediately (e.g. CP reload before block replay). */
|
|
142
|
+
loadOtherState(
|
|
143
|
+
stateBytes: Uint8Array,
|
|
144
|
+
seedValidatorsBytes?: Uint8Array,
|
|
145
|
+
opts?: {preloadValidatorsAndBalances?: boolean}
|
|
146
|
+
): IBeaconStateView;
|
|
142
147
|
toValue(): BeaconState;
|
|
143
148
|
serialize(): Uint8Array;
|
|
144
149
|
serializedSize(): number;
|
|
@@ -247,11 +252,15 @@ export interface IBeaconStateViewGloas extends IBeaconStateViewFulu {
|
|
|
247
252
|
payloadExpectedWithdrawals: capella.Withdrawal[];
|
|
248
253
|
getBuilder(index: BuilderIndex): gloas.Builder;
|
|
249
254
|
canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean;
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
+
getEpochPTCs(epoch: Epoch): Uint32Array[];
|
|
256
|
+
getIndicesInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number[];
|
|
257
|
+
/**
|
|
258
|
+
* Clone the state and apply parent execution payload effects.
|
|
259
|
+
* Used during block production and prepareNextSlot so that withdrawals and
|
|
260
|
+
* operation selection (e.g. voluntary exits) see the same post-apply state that the block
|
|
261
|
+
* processor will see at import.
|
|
262
|
+
*/
|
|
263
|
+
withParentPayloadApplied(executionRequests: electra.ExecutionRequests): IBeaconStateViewGloas;
|
|
255
264
|
}
|
|
256
265
|
|
|
257
266
|
/**
|
|
@@ -1,34 +1,21 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {
|
|
2
|
+
import {ZERO_HASH} from "@lodestar/params";
|
|
3
3
|
import {phase0, ssz} from "@lodestar/types";
|
|
4
4
|
import {BeaconStateAllForks} from "../types.js";
|
|
5
|
-
import {blockToHeader} from "./blockRoot.js";
|
|
6
5
|
import {computeCheckpointEpochAtStateSlot} from "./epoch.js";
|
|
7
6
|
|
|
8
7
|
export function computeAnchorCheckpoint(
|
|
9
|
-
|
|
8
|
+
_config: ChainForkConfig,
|
|
10
9
|
anchorState: BeaconStateAllForks
|
|
11
10
|
): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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);
|
|
11
|
+
const blockHeader = ssz.phase0.BeaconBlockHeader.clone(anchorState.latestBlockHeader);
|
|
12
|
+
if (ssz.Root.equals(blockHeader.stateRoot, ZERO_HASH)) {
|
|
13
|
+
blockHeader.stateRoot = anchorState.hashTreeRoot();
|
|
27
14
|
}
|
|
28
15
|
|
|
29
16
|
return {
|
|
30
17
|
checkpoint: {
|
|
31
|
-
root,
|
|
18
|
+
root: ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader),
|
|
32
19
|
// the checkpoint epoch = computeEpochAtSlot(anchorState.slot) + 1 if slot is not at epoch boundary
|
|
33
20
|
// this is similar to a process_slots() call
|
|
34
21
|
epoch: computeCheckpointEpochAtStateSlot(anchorState.slot),
|
package/src/util/epoch.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
EPOCHS_PER_SYNC_COMMITTEE_PERIOD,
|
|
3
|
+
ForkSeq,
|
|
4
|
+
GENESIS_EPOCH,
|
|
5
|
+
MAX_SEED_LOOKAHEAD,
|
|
6
|
+
SLOTS_PER_EPOCH,
|
|
7
|
+
} from "@lodestar/params";
|
|
2
8
|
import {BeaconState, Epoch, Gwei, Slot, SyncPeriod} from "@lodestar/types";
|
|
3
9
|
import {CachedBeaconStateElectra, CachedBeaconStateGloas} from "../types.js";
|
|
4
|
-
import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "./validator.js";
|
|
10
|
+
import {getActivationExitChurnLimit, getConsolidationChurnLimit, getExitChurnLimit} from "./validator.js";
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
13
|
* Return the epoch number at the given slot.
|
|
@@ -45,8 +51,10 @@ export function computeExitEpochAndUpdateChurn(
|
|
|
45
51
|
state: CachedBeaconStateElectra | CachedBeaconStateGloas,
|
|
46
52
|
exitBalance: Gwei
|
|
47
53
|
): number {
|
|
54
|
+
const fork = state.config.getForkSeq(state.slot);
|
|
48
55
|
let earliestExitEpoch = Math.max(state.earliestExitEpoch, computeActivationExitEpoch(state.epochCtx.epoch));
|
|
49
|
-
const perEpochChurn =
|
|
56
|
+
const perEpochChurn =
|
|
57
|
+
fork >= ForkSeq.gloas ? getExitChurnLimit(state.epochCtx) : getActivationExitChurnLimit(state.epochCtx);
|
|
50
58
|
|
|
51
59
|
// New epoch for exits.
|
|
52
60
|
let exitBalanceToConsume =
|
|
@@ -71,11 +79,12 @@ export function computeConsolidationEpochAndUpdateChurn(
|
|
|
71
79
|
state: CachedBeaconStateElectra | CachedBeaconStateGloas,
|
|
72
80
|
consolidationBalance: Gwei
|
|
73
81
|
): number {
|
|
82
|
+
const fork = state.config.getForkSeq(state.slot);
|
|
74
83
|
let earliestConsolidationEpoch = Math.max(
|
|
75
84
|
state.earliestConsolidationEpoch,
|
|
76
85
|
computeActivationExitEpoch(state.epochCtx.epoch)
|
|
77
86
|
);
|
|
78
|
-
const perEpochConsolidationChurn = getConsolidationChurnLimit(state.epochCtx);
|
|
87
|
+
const perEpochConsolidationChurn = getConsolidationChurnLimit(fork, state.epochCtx);
|
|
79
88
|
|
|
80
89
|
// New epoch for consolidations
|
|
81
90
|
let consolidationBalanceToConsume =
|
package/src/util/gloas.ts
CHANGED
|
@@ -172,10 +172,6 @@ export function isAttestationSameSlotRootCache(rootCache: RootCache, data: Attes
|
|
|
172
172
|
return isMatchingBlockRoot && isCurrentBlockRoot;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
export function isParentBlockFull(state: CachedBeaconStateGloas): boolean {
|
|
176
|
-
return byteArrayEquals(state.latestExecutionPayloadBid.blockHash, state.latestBlockHash);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
175
|
export function initializePtcWindow(state: CachedBeaconStateFulu): Uint32Array[] {
|
|
180
176
|
const ptcWindow: Uint32Array[] = Array.from({length: SLOTS_PER_EPOCH}, () => new Uint32Array(PTC_SIZE));
|
|
181
177
|
const currentEpoch = state.epochCtx.epoch;
|
package/src/util/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from "./genesis.js";
|
|
|
18
18
|
export * from "./gloas.js";
|
|
19
19
|
export * from "./interop.js";
|
|
20
20
|
export * from "./loadState/index.js";
|
|
21
|
+
export * from "./pendingDepositsLookup.js";
|
|
21
22
|
export * from "./rootCache.js";
|
|
22
23
|
export * from "./seed.js";
|
|
23
24
|
export * from "./shuffling.js";
|
|
@@ -110,8 +110,8 @@ function loadInactivityScores(
|
|
|
110
110
|
seedState: BeaconStateAltair,
|
|
111
111
|
inactivityScoresBytes: Uint8Array
|
|
112
112
|
): void {
|
|
113
|
-
//
|
|
114
|
-
migratedState.inactivityScores = seedState.inactivityScores.clone();
|
|
113
|
+
// true = do not transfer cache
|
|
114
|
+
migratedState.inactivityScores = seedState.inactivityScores.clone(true);
|
|
115
115
|
const oldValidator = migratedState.inactivityScores.length;
|
|
116
116
|
// UintNum64 = 8 bytes
|
|
117
117
|
const newValidator = inactivityScoresBytes.length / 8;
|
|
@@ -187,8 +187,8 @@ function loadValidators(
|
|
|
187
187
|
const newValidatorCount = Math.floor(newValidatorsBytes.length / VALIDATOR_BYTES_SIZE);
|
|
188
188
|
const isMoreValidator = newValidatorCount >= seedValidatorCount;
|
|
189
189
|
const minValidatorCount = Math.min(seedValidatorCount, newValidatorCount);
|
|
190
|
-
//
|
|
191
|
-
migratedState.validators = seedState.validators.clone();
|
|
190
|
+
// true = do not transfer cache
|
|
191
|
+
migratedState.validators = seedState.validators.clone(true);
|
|
192
192
|
// 80% of validators serialization time comes from memory allocation
|
|
193
193
|
// seedStateValidatorsBytes is an optimization at beacon-node side to avoid memory allocation here
|
|
194
194
|
const seedValidatorsBytes = seedStateValidatorsBytes ?? seedState.validators.serialize();
|