@lodestar/state-transition 1.45.0-dev.b620872107 → 1.45.0-dev.b98df0df3d
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/processAttestationsAltair.d.ts +4 -1
- package/lib/block/processAttestationsAltair.d.ts.map +1 -1
- package/lib/block/processAttestationsAltair.js +7 -5
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processBuilderDepositRequest.d.ts.map +1 -1
- package/lib/block/processBuilderDepositRequest.js +13 -7
- package/lib/block/processBuilderDepositRequest.js.map +1 -1
- package/lib/block/processOperations.d.ts.map +1 -1
- package/lib/block/processOperations.js +17 -1
- package/lib/block/processOperations.js.map +1 -1
- package/lib/block/processParentExecutionPayload.d.ts.map +1 -1
- package/lib/block/processParentExecutionPayload.js +15 -1
- package/lib/block/processParentExecutionPayload.js.map +1 -1
- package/lib/block/processWithdrawals.js +1 -1
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/cache/stateCache.d.ts.map +1 -1
- package/lib/cache/stateCache.js +2 -4
- package/lib/cache/stateCache.js.map +1 -1
- package/lib/epoch/processParticipationFlagUpdates.d.ts +2 -2
- package/lib/epoch/processParticipationFlagUpdates.d.ts.map +1 -1
- package/lib/epoch/processParticipationFlagUpdates.js +13 -0
- package/lib/epoch/processParticipationFlagUpdates.js.map +1 -1
- package/lib/epoch/processRewardsAndPenalties.d.ts.map +1 -1
- package/lib/epoch/processRewardsAndPenalties.js +1 -2
- package/lib/epoch/processRewardsAndPenalties.js.map +1 -1
- package/lib/lightClient/proofs.d.ts.map +1 -1
- package/lib/lightClient/proofs.js +28 -2
- package/lib/lightClient/proofs.js.map +1 -1
- package/lib/lightClient/spec/index.d.ts.map +1 -1
- package/lib/lightClient/spec/index.js +7 -4
- package/lib/lightClient/spec/index.js.map +1 -1
- package/lib/lightClient/spec/utils.d.ts +7 -1
- package/lib/lightClient/spec/utils.d.ts.map +1 -1
- package/lib/lightClient/spec/utils.js +123 -14
- package/lib/lightClient/spec/utils.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientBootstrap.d.ts.map +1 -1
- package/lib/lightClient/spec/validateLightClientBootstrap.js +2 -7
- package/lib/lightClient/spec/validateLightClientBootstrap.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientUpdate.d.ts.map +1 -1
- package/lib/lightClient/spec/validateLightClientUpdate.js +6 -5
- package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -1
- package/lib/lightClient/types.d.ts +3 -1
- package/lib/lightClient/types.d.ts.map +1 -1
- package/lib/metrics.js +2 -4
- package/lib/metrics.js.map +1 -1
- package/lib/slot/upgradeStateToAltair.js +1 -1
- package/lib/slot/upgradeStateToAltair.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +48 -9
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +0 -1
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +0 -8
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +0 -1
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/stateView/nativeBeaconStateView.d.ts +0 -2
- package/lib/stateView/nativeBeaconStateView.d.ts.map +1 -1
- package/lib/stateView/nativeBeaconStateView.js +0 -9
- package/lib/stateView/nativeBeaconStateView.js.map +1 -1
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +7 -2
- package/lib/util/execution.js.map +1 -1
- package/lib/util/gloas.d.ts +3 -1
- package/lib/util/gloas.d.ts.map +1 -1
- package/lib/util/gloas.js +8 -11
- 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/ssz.d.ts +9 -0
- package/lib/util/ssz.d.ts.map +1 -0
- package/lib/util/ssz.js +39 -0
- package/lib/util/ssz.js.map +1 -0
- package/package.json +11 -11
- package/src/block/processAttestationsAltair.ts +9 -6
- package/src/block/processBuilderDepositRequest.ts +21 -8
- package/src/block/processOperations.ts +28 -1
- package/src/block/processParentExecutionPayload.ts +26 -1
- package/src/block/processWithdrawals.ts +1 -1
- package/src/cache/stateCache.ts +2 -4
- package/src/epoch/processParticipationFlagUpdates.ts +20 -2
- package/src/epoch/processRewardsAndPenalties.ts +1 -2
- package/src/lightClient/proofs.ts +36 -1
- package/src/lightClient/spec/index.ts +8 -4
- package/src/lightClient/spec/utils.ts +193 -25
- package/src/lightClient/spec/validateLightClientBootstrap.ts +3 -10
- package/src/lightClient/spec/validateLightClientUpdate.ts +11 -21
- package/src/lightClient/types.ts +3 -1
- package/src/metrics.ts +2 -4
- package/src/slot/upgradeStateToAltair.ts +1 -1
- package/src/slot/upgradeStateToGloas.ts +84 -9
- package/src/stateView/beaconStateView.ts +0 -8
- package/src/stateView/interface.ts +0 -1
- package/src/stateView/nativeBeaconStateView.ts +0 -10
- package/src/util/execution.ts +9 -4
- package/src/util/gloas.ts +9 -14
- package/src/util/index.ts +1 -0
- package/src/util/ssz.ts +42 -0
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import {PublicKey} from "@chainsafe/blst";
|
|
2
|
+
import {Tree} from "@chainsafe/persistent-merkle-tree";
|
|
2
3
|
import {BitArray} from "@chainsafe/ssz";
|
|
3
4
|
import {ChainForkConfig} from "@lodestar/config";
|
|
4
5
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX,
|
|
7
|
+
CURRENT_SYNC_COMMITTEE_GINDEX,
|
|
8
|
+
CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA,
|
|
9
|
+
CURRENT_SYNC_COMMITTEE_GINDEX_GLOAS,
|
|
10
|
+
EXECUTION_BLOCK_HASH_GINDEX,
|
|
11
|
+
EXECUTION_BLOCK_HASH_GINDEX_DENEB,
|
|
12
|
+
EXECUTION_BLOCK_HASH_GINDEX_GLOAS,
|
|
13
|
+
FINALIZED_ROOT_GINDEX,
|
|
14
|
+
FINALIZED_ROOT_GINDEX_ELECTRA,
|
|
15
|
+
FINALIZED_ROOT_GINDEX_GLOAS,
|
|
9
16
|
ForkName,
|
|
10
17
|
ForkSeq,
|
|
11
|
-
|
|
12
|
-
|
|
18
|
+
NEXT_SYNC_COMMITTEE_GINDEX,
|
|
19
|
+
NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA,
|
|
20
|
+
NEXT_SYNC_COMMITTEE_GINDEX_GLOAS,
|
|
13
21
|
isForkPostElectra,
|
|
22
|
+
isForkPostGloas,
|
|
14
23
|
} from "@lodestar/params";
|
|
15
24
|
import {
|
|
16
25
|
BeaconBlockHeader,
|
|
@@ -74,17 +83,11 @@ export function getSafetyThreshold(maxActiveParticipants: number): number {
|
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
export function getZeroSyncCommitteeBranch(fork: ForkName): Uint8Array[] {
|
|
77
|
-
|
|
78
|
-
? NEXT_SYNC_COMMITTEE_DEPTH_ELECTRA
|
|
79
|
-
: NEXT_SYNC_COMMITTEE_DEPTH;
|
|
80
|
-
|
|
81
|
-
return Array.from({length: nextSyncCommitteeDepth}, () => ZERO_HASH);
|
|
86
|
+
return Array.from({length: getGindexDepth(nextSyncCommitteeGindexAtFork(fork))}, () => ZERO_HASH);
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
export function getZeroFinalityBranch(fork: ForkName): Uint8Array[] {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return Array.from({length: finalizedRootDepth}, () => ZERO_HASH);
|
|
90
|
+
return Array.from({length: getGindexDepth(finalizedRootGindexAtFork(fork))}, () => ZERO_HASH);
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
export function isSyncCommitteeUpdate(update: LightClientUpdate): boolean {
|
|
@@ -129,12 +132,73 @@ export function isValidMerkleBranch(
|
|
|
129
132
|
return verifyMerkleBranch(leaf, branch, depth, index, root);
|
|
130
133
|
}
|
|
131
134
|
|
|
132
|
-
export function
|
|
135
|
+
export function isValidNormalizedMerkleBranch(
|
|
136
|
+
leaf: Uint8Array,
|
|
137
|
+
branch: Uint8Array[],
|
|
138
|
+
gindex: number,
|
|
139
|
+
root: Uint8Array
|
|
140
|
+
): boolean {
|
|
141
|
+
const depth = getGindexDepth(gindex);
|
|
142
|
+
const index = getGindexIndex(gindex);
|
|
143
|
+
const numExtraDepth = branch.length - depth;
|
|
144
|
+
if (numExtraDepth < 0) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for (let i = 0; i < numExtraDepth; i++) {
|
|
149
|
+
if (!byteArrayEquals(branch[i], ZERO_HASH)) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return isValidMerkleBranch(leaf, branch.slice(numExtraDepth), depth, index, root);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function normalizeMerkleBranch(branch: Uint8Array[], gindex: number): Uint8Array[] {
|
|
158
|
+
const depth = getGindexDepth(gindex);
|
|
133
159
|
const numExtraDepth = depth - branch.length;
|
|
134
160
|
|
|
135
161
|
return [...Array.from({length: numExtraDepth}, () => ZERO_HASH), ...branch];
|
|
136
162
|
}
|
|
137
163
|
|
|
164
|
+
export function currentSyncCommitteeGindexAtFork(fork: ForkName): number {
|
|
165
|
+
if (isForkPostGloas(fork)) {
|
|
166
|
+
return CURRENT_SYNC_COMMITTEE_GINDEX_GLOAS;
|
|
167
|
+
}
|
|
168
|
+
if (isForkPostElectra(fork)) {
|
|
169
|
+
return CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA;
|
|
170
|
+
}
|
|
171
|
+
return CURRENT_SYNC_COMMITTEE_GINDEX;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function finalizedRootGindexAtFork(fork: ForkName): number {
|
|
175
|
+
if (isForkPostGloas(fork)) {
|
|
176
|
+
return FINALIZED_ROOT_GINDEX_GLOAS;
|
|
177
|
+
}
|
|
178
|
+
if (isForkPostElectra(fork)) {
|
|
179
|
+
return FINALIZED_ROOT_GINDEX_ELECTRA;
|
|
180
|
+
}
|
|
181
|
+
return FINALIZED_ROOT_GINDEX;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function nextSyncCommitteeGindexAtFork(fork: ForkName): number {
|
|
185
|
+
if (isForkPostGloas(fork)) {
|
|
186
|
+
return NEXT_SYNC_COMMITTEE_GINDEX_GLOAS;
|
|
187
|
+
}
|
|
188
|
+
if (isForkPostElectra(fork)) {
|
|
189
|
+
return NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA;
|
|
190
|
+
}
|
|
191
|
+
return NEXT_SYNC_COMMITTEE_GINDEX;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function getGindexDepth(gindex: number): number {
|
|
195
|
+
return Math.floor(Math.log2(gindex));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function getGindexIndex(gindex: number): number {
|
|
199
|
+
return gindex - 2 ** getGindexDepth(gindex);
|
|
200
|
+
}
|
|
201
|
+
|
|
138
202
|
export function upgradeLightClientHeader(
|
|
139
203
|
config: ChainForkConfig,
|
|
140
204
|
targetFork: ForkName,
|
|
@@ -147,7 +211,7 @@ export function upgradeLightClientHeader(
|
|
|
147
211
|
|
|
148
212
|
// We are modifying the same header object, may be we could create a copy, but its
|
|
149
213
|
// not required as of now
|
|
150
|
-
|
|
214
|
+
let upgradedHeader = header;
|
|
151
215
|
const startUpgradeFromFork = Object.values(ForkName)[ForkSeq[headerFork] + 1];
|
|
152
216
|
|
|
153
217
|
switch (startUpgradeFromFork) {
|
|
@@ -198,7 +262,11 @@ export function upgradeLightClientHeader(
|
|
|
198
262
|
if (ForkSeq[targetFork] <= ForkSeq.fulu) break;
|
|
199
263
|
|
|
200
264
|
case ForkName.gloas:
|
|
201
|
-
|
|
265
|
+
if (isGloasLightClientHeader(upgradedHeader)) {
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
upgradedHeader = upgradeLightClientHeaderToGloas(config, upgradedHeader as LightClientHeader<ForkName.electra>);
|
|
202
270
|
|
|
203
271
|
// Break if no further upgrades is required else fall through
|
|
204
272
|
if (ForkSeq[targetFork] <= ForkSeq.gloas) break;
|
|
@@ -209,6 +277,40 @@ export function upgradeLightClientHeader(
|
|
|
209
277
|
export function isValidLightClientHeader(config: ChainForkConfig, header: LightClientHeader): boolean {
|
|
210
278
|
const epoch = computeEpochAtSlot(header.beacon.slot);
|
|
211
279
|
|
|
280
|
+
if (isGloasLightClientHeader(header)) {
|
|
281
|
+
if (epoch >= config.GLOAS_FORK_EPOCH) {
|
|
282
|
+
return isValidNormalizedMerkleBranch(
|
|
283
|
+
header.executionBlockHash,
|
|
284
|
+
header.executionBranch,
|
|
285
|
+
EXECUTION_BLOCK_HASH_GINDEX_GLOAS,
|
|
286
|
+
header.beacon.bodyRoot
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (epoch >= config.DENEB_FORK_EPOCH) {
|
|
291
|
+
return isValidNormalizedMerkleBranch(
|
|
292
|
+
header.executionBlockHash,
|
|
293
|
+
header.executionBranch,
|
|
294
|
+
EXECUTION_BLOCK_HASH_GINDEX_DENEB,
|
|
295
|
+
header.beacon.bodyRoot
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (epoch >= config.CAPELLA_FORK_EPOCH) {
|
|
300
|
+
return isValidNormalizedMerkleBranch(
|
|
301
|
+
header.executionBlockHash,
|
|
302
|
+
header.executionBranch,
|
|
303
|
+
EXECUTION_BLOCK_HASH_GINDEX,
|
|
304
|
+
header.beacon.bodyRoot
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
byteArrayEquals(header.executionBlockHash, ZERO_HASH) &&
|
|
310
|
+
header.executionBranch.every((node) => byteArrayEquals(node, ZERO_HASH))
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
212
314
|
if (epoch < config.CAPELLA_FORK_EPOCH) {
|
|
213
315
|
return (
|
|
214
316
|
((header as LightClientHeader<ForkName.capella>).execution === undefined ||
|
|
@@ -239,8 +341,8 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC
|
|
|
239
341
|
.getPostBellatrixForkTypes(header.beacon.slot)
|
|
240
342
|
.ExecutionPayloadHeader.hashTreeRoot((header as LightClientHeader<ForkName.capella>).execution),
|
|
241
343
|
(header as LightClientHeader<ForkName.capella>).executionBranch,
|
|
242
|
-
|
|
243
|
-
|
|
344
|
+
getGindexDepth(BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX),
|
|
345
|
+
getGindexIndex(BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX),
|
|
244
346
|
header.beacon.bodyRoot
|
|
245
347
|
);
|
|
246
348
|
}
|
|
@@ -254,12 +356,9 @@ export function upgradeLightClientUpdate(
|
|
|
254
356
|
update.finalizedHeader = upgradeLightClientHeader(config, targetFork, update.finalizedHeader);
|
|
255
357
|
update.nextSyncCommitteeBranch = normalizeMerkleBranch(
|
|
256
358
|
update.nextSyncCommitteeBranch,
|
|
257
|
-
|
|
258
|
-
);
|
|
259
|
-
update.finalityBranch = normalizeMerkleBranch(
|
|
260
|
-
update.finalityBranch,
|
|
261
|
-
isForkPostElectra(targetFork) ? FINALIZED_ROOT_DEPTH_ELECTRA : FINALIZED_ROOT_DEPTH
|
|
359
|
+
nextSyncCommitteeGindexAtFork(targetFork)
|
|
262
360
|
);
|
|
361
|
+
update.finalityBranch = normalizeMerkleBranch(update.finalityBranch, finalizedRootGindexAtFork(targetFork));
|
|
263
362
|
|
|
264
363
|
return update;
|
|
265
364
|
}
|
|
@@ -273,7 +372,7 @@ export function upgradeLightClientFinalityUpdate(
|
|
|
273
372
|
finalityUpdate.finalizedHeader = upgradeLightClientHeader(config, targetFork, finalityUpdate.finalizedHeader);
|
|
274
373
|
finalityUpdate.finalityBranch = normalizeMerkleBranch(
|
|
275
374
|
finalityUpdate.finalityBranch,
|
|
276
|
-
|
|
375
|
+
finalizedRootGindexAtFork(targetFork)
|
|
277
376
|
);
|
|
278
377
|
|
|
279
378
|
return finalityUpdate;
|
|
@@ -315,3 +414,72 @@ export function upgradeLightClientStore(
|
|
|
315
414
|
|
|
316
415
|
return store;
|
|
317
416
|
}
|
|
417
|
+
|
|
418
|
+
function isGloasLightClientHeader(header: LightClientHeader): header is LightClientHeader<ForkName.gloas> {
|
|
419
|
+
return (header as LightClientHeader<ForkName.gloas>).executionBlockHash !== undefined;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function upgradeLightClientHeaderToGloas(
|
|
423
|
+
config: ChainForkConfig,
|
|
424
|
+
pre: LightClientHeader<ForkName.electra>
|
|
425
|
+
): LightClientHeader<ForkName.gloas> {
|
|
426
|
+
if (ssz.electra.LightClientHeader.equals(pre, ssz.electra.LightClientHeader.defaultValue())) {
|
|
427
|
+
return ssz.gloas.LightClientHeader.defaultValue();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const epoch = computeEpochAtSlot(pre.beacon.slot);
|
|
431
|
+
|
|
432
|
+
if (epoch >= config.DENEB_FORK_EPOCH) {
|
|
433
|
+
const blockHashGindex = ssz.deneb.ExecutionPayloadHeader.getPathInfo(["blockHash"]).gindex;
|
|
434
|
+
const executionBranch = new Tree(ssz.deneb.ExecutionPayloadHeader.toView(pre.execution).node).getSingleProof(
|
|
435
|
+
blockHashGindex
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
return {
|
|
439
|
+
beacon: pre.beacon,
|
|
440
|
+
executionBlockHash: pre.execution.blockHash,
|
|
441
|
+
executionBranch: normalizeMerkleBranch(
|
|
442
|
+
[...executionBranch, ...pre.executionBranch],
|
|
443
|
+
EXECUTION_BLOCK_HASH_GINDEX_GLOAS
|
|
444
|
+
),
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (epoch >= config.CAPELLA_FORK_EPOCH) {
|
|
449
|
+
const executionHeader = {
|
|
450
|
+
parentHash: pre.execution.parentHash,
|
|
451
|
+
feeRecipient: pre.execution.feeRecipient,
|
|
452
|
+
stateRoot: pre.execution.stateRoot,
|
|
453
|
+
receiptsRoot: pre.execution.receiptsRoot,
|
|
454
|
+
logsBloom: pre.execution.logsBloom,
|
|
455
|
+
prevRandao: pre.execution.prevRandao,
|
|
456
|
+
blockNumber: pre.execution.blockNumber,
|
|
457
|
+
gasLimit: pre.execution.gasLimit,
|
|
458
|
+
gasUsed: pre.execution.gasUsed,
|
|
459
|
+
timestamp: pre.execution.timestamp,
|
|
460
|
+
extraData: pre.execution.extraData,
|
|
461
|
+
baseFeePerGas: pre.execution.baseFeePerGas,
|
|
462
|
+
blockHash: pre.execution.blockHash,
|
|
463
|
+
transactionsRoot: pre.execution.transactionsRoot,
|
|
464
|
+
withdrawalsRoot: pre.execution.withdrawalsRoot,
|
|
465
|
+
};
|
|
466
|
+
const blockHashGindex = ssz.capella.ExecutionPayloadHeader.getPathInfo(["blockHash"]).gindex;
|
|
467
|
+
const executionBranch = new Tree(ssz.capella.ExecutionPayloadHeader.toView(executionHeader).node).getSingleProof(
|
|
468
|
+
blockHashGindex
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
beacon: pre.beacon,
|
|
473
|
+
executionBlockHash: executionHeader.blockHash,
|
|
474
|
+
executionBranch: normalizeMerkleBranch(
|
|
475
|
+
[...executionBranch, ...pre.executionBranch],
|
|
476
|
+
EXECUTION_BLOCK_HASH_GINDEX_GLOAS
|
|
477
|
+
),
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return {
|
|
482
|
+
...ssz.gloas.LightClientHeader.defaultValue(),
|
|
483
|
+
beacon: pre.beacon,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
|
-
import {isForkPostElectra} from "@lodestar/params";
|
|
3
2
|
import {LightClientBootstrap, Root, ssz} from "@lodestar/types";
|
|
4
3
|
import {byteArrayEquals, toHex} from "@lodestar/utils";
|
|
5
|
-
import {isValidLightClientHeader,
|
|
6
|
-
|
|
7
|
-
const CURRENT_SYNC_COMMITTEE_INDEX = 22;
|
|
8
|
-
const CURRENT_SYNC_COMMITTEE_DEPTH = 5;
|
|
9
|
-
const CURRENT_SYNC_COMMITTEE_INDEX_ELECTRA = 22;
|
|
10
|
-
const CURRENT_SYNC_COMMITTEE_DEPTH_ELECTRA = 6;
|
|
4
|
+
import {currentSyncCommitteeGindexAtFork, isValidLightClientHeader, isValidNormalizedMerkleBranch} from "./utils.js";
|
|
11
5
|
|
|
12
6
|
export function validateLightClientBootstrap(
|
|
13
7
|
config: ChainForkConfig,
|
|
@@ -26,11 +20,10 @@ export function validateLightClientBootstrap(
|
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
if (
|
|
29
|
-
!
|
|
23
|
+
!isValidNormalizedMerkleBranch(
|
|
30
24
|
ssz.altair.SyncCommittee.hashTreeRoot(bootstrap.currentSyncCommittee),
|
|
31
25
|
bootstrap.currentSyncCommitteeBranch,
|
|
32
|
-
|
|
33
|
-
isForkPostElectra(fork) ? CURRENT_SYNC_COMMITTEE_INDEX_ELECTRA : CURRENT_SYNC_COMMITTEE_INDEX,
|
|
26
|
+
currentSyncCommitteeGindexAtFork(fork),
|
|
34
27
|
bootstrap.header.beacon.stateRoot
|
|
35
28
|
)
|
|
36
29
|
) {
|
|
@@ -1,29 +1,19 @@
|
|
|
1
1
|
import {PublicKey, Signature, fastAggregateVerify} from "@chainsafe/blst";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
-
import {
|
|
4
|
-
|
|
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";
|
|
3
|
+
import {DOMAIN_SYNC_COMMITTEE, GENESIS_SLOT, MIN_SYNC_COMMITTEE_PARTICIPANTS} from "@lodestar/params";
|
|
4
|
+
import {LightClientUpdate, Root, ssz} from "@lodestar/types";
|
|
17
5
|
import type {ILightClientStore, SyncCommitteeFast} from "./store.js";
|
|
18
6
|
import {
|
|
19
7
|
ZERO_HASH,
|
|
8
|
+
finalizedRootGindexAtFork,
|
|
20
9
|
getParticipantPubkeys,
|
|
21
10
|
isFinalityUpdate,
|
|
22
11
|
isSyncCommitteeUpdate,
|
|
23
12
|
isValidLightClientHeader,
|
|
24
|
-
|
|
13
|
+
isValidNormalizedMerkleBranch,
|
|
25
14
|
isZeroedHeader,
|
|
26
15
|
isZeroedSyncCommittee,
|
|
16
|
+
nextSyncCommitteeGindexAtFork,
|
|
27
17
|
sumBits,
|
|
28
18
|
} from "./utils.js";
|
|
29
19
|
|
|
@@ -33,6 +23,8 @@ export function validateLightClientUpdate(
|
|
|
33
23
|
update: LightClientUpdate,
|
|
34
24
|
syncCommittee: SyncCommitteeFast
|
|
35
25
|
): void {
|
|
26
|
+
const attestedFork = config.getForkName(update.attestedHeader.beacon.slot);
|
|
27
|
+
|
|
36
28
|
// Verify sync committee has sufficient participants
|
|
37
29
|
if (sumBits(update.syncAggregate.syncCommitteeBits) < MIN_SYNC_COMMITTEE_PARTICIPANTS) {
|
|
38
30
|
throw Error("Sync committee has not sufficient participants");
|
|
@@ -78,11 +70,10 @@ export function validateLightClientUpdate(
|
|
|
78
70
|
}
|
|
79
71
|
|
|
80
72
|
if (
|
|
81
|
-
!
|
|
73
|
+
!isValidNormalizedMerkleBranch(
|
|
82
74
|
finalizedRoot,
|
|
83
75
|
update.finalityBranch,
|
|
84
|
-
|
|
85
|
-
isElectraLightClientUpdate(update) ? FINALIZED_ROOT_INDEX_ELECTRA : FINALIZED_ROOT_INDEX,
|
|
76
|
+
finalizedRootGindexAtFork(attestedFork),
|
|
86
77
|
update.attestedHeader.beacon.stateRoot
|
|
87
78
|
)
|
|
88
79
|
) {
|
|
@@ -98,11 +89,10 @@ export function validateLightClientUpdate(
|
|
|
98
89
|
}
|
|
99
90
|
} else {
|
|
100
91
|
if (
|
|
101
|
-
!
|
|
92
|
+
!isValidNormalizedMerkleBranch(
|
|
102
93
|
ssz.altair.SyncCommittee.hashTreeRoot(update.nextSyncCommittee),
|
|
103
94
|
update.nextSyncCommitteeBranch,
|
|
104
|
-
|
|
105
|
-
isElectraLightClientUpdate(update) ? NEXT_SYNC_COMMITTEE_INDEX_ELECTRA : NEXT_SYNC_COMMITTEE_INDEX,
|
|
95
|
+
nextSyncCommitteeGindexAtFork(attestedFork),
|
|
106
96
|
update.attestedHeader.beacon.stateRoot
|
|
107
97
|
)
|
|
108
98
|
) {
|
package/src/lightClient/types.ts
CHANGED
|
@@ -26,8 +26,10 @@
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
export type SyncCommitteeWitness = {
|
|
29
|
-
/**
|
|
29
|
+
/** Shared witness for pre-Gloas forks where current and next sync committees are siblings. */
|
|
30
30
|
witness: Uint8Array[];
|
|
31
31
|
currentSyncCommitteeRoot: Uint8Array;
|
|
32
32
|
nextSyncCommitteeRoot: Uint8Array;
|
|
33
|
+
currentSyncCommitteeBranch?: Uint8Array[];
|
|
34
|
+
nextSyncCommitteeBranch?: Uint8Array[];
|
|
33
35
|
};
|
package/src/metrics.ts
CHANGED
|
@@ -159,11 +159,9 @@ export function onPostStateMetrics(postState: CachedBeaconStateAllForks, metrics
|
|
|
159
159
|
// This cache is populated during epoch transition, and should be preserved for performance.
|
|
160
160
|
// If the cache is missing too often, means that our clone strategy is not working well.
|
|
161
161
|
function isValidatorsNodesPopulated(state: CachedBeaconStateAllForks): boolean {
|
|
162
|
-
|
|
163
|
-
return state.validators["nodesPopulated"] === true;
|
|
162
|
+
return (state.validators as unknown as {nodesPopulated?: boolean}).nodesPopulated === true;
|
|
164
163
|
}
|
|
165
164
|
|
|
166
165
|
function isBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean {
|
|
167
|
-
|
|
168
|
-
return state.balances["nodesPopulated"] === true;
|
|
166
|
+
return (state.balances as unknown as {nodesPopulated?: boolean}).nodesPopulated === true;
|
|
169
167
|
}
|
|
@@ -131,7 +131,7 @@ function translateParticipation(
|
|
|
131
131
|
|
|
132
132
|
for (const attestation of pendingAttesations.getAllReadonly()) {
|
|
133
133
|
const data = attestation.data;
|
|
134
|
-
const attestationFlags = getAttestationParticipationStatus(
|
|
134
|
+
const {flags: attestationFlags} = getAttestationParticipationStatus(
|
|
135
135
|
ForkSeq.altair,
|
|
136
136
|
data,
|
|
137
137
|
attestation.inclusionDelay,
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
import {getNodesAtDepth} from "@chainsafe/persistent-merkle-tree";
|
|
2
|
+
import {
|
|
3
|
+
BasicType,
|
|
4
|
+
CompositeType,
|
|
5
|
+
CompositeView,
|
|
6
|
+
CompositeViewDU,
|
|
7
|
+
ListBasicTreeViewDU,
|
|
8
|
+
ListCompositeTreeViewDU,
|
|
9
|
+
ProgressiveListBasicType,
|
|
10
|
+
ProgressiveListCompositeType,
|
|
11
|
+
ValueOf,
|
|
12
|
+
} from "@chainsafe/ssz";
|
|
1
13
|
import {PAYLOAD_BUILDER_VERSION, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
2
14
|
import {ssz} from "@lodestar/types";
|
|
3
15
|
import {toPubkeyHex} from "@lodestar/utils";
|
|
@@ -7,6 +19,7 @@ import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
|
|
|
7
19
|
import {addBuilderToRegistry, initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
|
|
8
20
|
import {isValidatorKnown} from "../util/index.js";
|
|
9
21
|
import {PendingDepositsLookup} from "../util/pendingDepositsLookup.js";
|
|
22
|
+
import {progressiveListRootNode} from "../util/ssz.js";
|
|
10
23
|
|
|
11
24
|
/**
|
|
12
25
|
* Upgrade a state from Fulu to Gloas.
|
|
@@ -34,17 +47,26 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
34
47
|
stateGloasView.eth1Data = stateGloasCloned.eth1Data;
|
|
35
48
|
stateGloasView.eth1DataVotes = stateGloasCloned.eth1DataVotes;
|
|
36
49
|
stateGloasView.eth1DepositIndex = stateGloasCloned.eth1DepositIndex;
|
|
37
|
-
stateGloasView.validators = stateGloasCloned.validators;
|
|
38
|
-
stateGloasView.balances = stateGloasCloned.balances;
|
|
50
|
+
stateGloasView.validators = migrateCompositeListToGloas(stateGloasCloned.validators, ssz.gloas.Validators);
|
|
51
|
+
stateGloasView.balances = migrateBasicListToGloas(stateGloasCloned.balances, ssz.gloas.Balances);
|
|
39
52
|
stateGloasView.randaoMixes = stateGloasCloned.randaoMixes;
|
|
40
53
|
stateGloasView.slashings = stateGloasCloned.slashings;
|
|
41
|
-
stateGloasView.previousEpochParticipation =
|
|
42
|
-
|
|
54
|
+
stateGloasView.previousEpochParticipation = migrateBasicListToGloas(
|
|
55
|
+
stateGloasCloned.previousEpochParticipation,
|
|
56
|
+
ssz.gloas.EpochParticipation
|
|
57
|
+
);
|
|
58
|
+
stateGloasView.currentEpochParticipation = migrateBasicListToGloas(
|
|
59
|
+
stateGloasCloned.currentEpochParticipation,
|
|
60
|
+
ssz.gloas.EpochParticipation
|
|
61
|
+
);
|
|
43
62
|
stateGloasView.justificationBits = stateGloasCloned.justificationBits;
|
|
44
63
|
stateGloasView.previousJustifiedCheckpoint = stateGloasCloned.previousJustifiedCheckpoint;
|
|
45
64
|
stateGloasView.currentJustifiedCheckpoint = stateGloasCloned.currentJustifiedCheckpoint;
|
|
46
65
|
stateGloasView.finalizedCheckpoint = stateGloasCloned.finalizedCheckpoint;
|
|
47
|
-
stateGloasView.inactivityScores =
|
|
66
|
+
stateGloasView.inactivityScores = migrateBasicListToGloas(
|
|
67
|
+
stateGloasCloned.inactivityScores,
|
|
68
|
+
ssz.gloas.InactivityScores
|
|
69
|
+
);
|
|
48
70
|
stateGloasView.currentSyncCommittee = stateGloasCloned.currentSyncCommittee;
|
|
49
71
|
stateGloasView.nextSyncCommittee = stateGloasCloned.nextSyncCommittee;
|
|
50
72
|
stateGloasView.latestExecutionPayloadBid.blockHash = stateFulu.latestExecutionPayloadHeader.blockHash;
|
|
@@ -61,9 +83,18 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
61
83
|
stateGloasView.earliestExitEpoch = stateGloasCloned.earliestExitEpoch;
|
|
62
84
|
stateGloasView.consolidationBalanceToConsume = stateGloasCloned.consolidationBalanceToConsume;
|
|
63
85
|
stateGloasView.earliestConsolidationEpoch = stateGloasCloned.earliestConsolidationEpoch;
|
|
64
|
-
stateGloasView.pendingDeposits =
|
|
65
|
-
|
|
66
|
-
|
|
86
|
+
stateGloasView.pendingDeposits = migrateCompositeListToGloas(
|
|
87
|
+
stateGloasCloned.pendingDeposits,
|
|
88
|
+
ssz.gloas.PendingDeposits
|
|
89
|
+
);
|
|
90
|
+
stateGloasView.pendingPartialWithdrawals = migrateCompositeListToGloas(
|
|
91
|
+
stateGloasCloned.pendingPartialWithdrawals,
|
|
92
|
+
ssz.gloas.PendingPartialWithdrawals
|
|
93
|
+
);
|
|
94
|
+
stateGloasView.pendingConsolidations = migrateCompositeListToGloas(
|
|
95
|
+
stateGloasCloned.pendingConsolidations,
|
|
96
|
+
ssz.gloas.PendingConsolidations
|
|
97
|
+
);
|
|
67
98
|
stateGloasView.proposerLookahead = stateGloasCloned.proposerLookahead;
|
|
68
99
|
stateGloasView.ptcWindow = ssz.gloas.PtcWindow.toViewDU(initializePtcWindow(stateFulu));
|
|
69
100
|
|
|
@@ -85,6 +116,50 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
85
116
|
return stateGloas;
|
|
86
117
|
}
|
|
87
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Migrate a composite list from fulu to its gloas progressive-list equivalent by reusing the fulu
|
|
121
|
+
* list's element nodes.
|
|
122
|
+
*
|
|
123
|
+
* Works whenever the element type is identical across the fork (e.g. validators use ValidatorNodeStruct,
|
|
124
|
+
* the pending* queues use the same electra element types). Each element's cached subtree root is then
|
|
125
|
+
* valid under gloas, so only the progressive list superstructure is rebuilt and a subsequent
|
|
126
|
+
* hashTreeRoot() skips re-hashing every element — the dominant cost for large lists like validators.
|
|
127
|
+
* Much cheaper than `gloasType.toViewDU(fuluList.getAllReadonlyValues())`, which decodes every element
|
|
128
|
+
* to a value and forces a full re-hash.
|
|
129
|
+
*
|
|
130
|
+
* The chunk nodes of a composite list ARE the element root nodes, so they are extracted directly
|
|
131
|
+
* with getNodesAtDepth instead of allocating a temporary ViewDU wrapper per element (getAllReadonly).
|
|
132
|
+
* Requires the fulu view to be committed (done at the top of upgradeStateToGloas).
|
|
133
|
+
*/
|
|
134
|
+
function migrateCompositeListToGloas<
|
|
135
|
+
ElementType extends CompositeType<ValueOf<ElementType>, CompositeView<ElementType>, CompositeViewDU<ElementType>>,
|
|
136
|
+
>(fuluList: ListCompositeTreeViewDU<ElementType>, gloasType: ProgressiveListCompositeType<ElementType>) {
|
|
137
|
+
const {length, type} = fuluList;
|
|
138
|
+
const elementNodes = getNodesAtDepth(fuluList.node.left, type.chunkDepth, 0, length);
|
|
139
|
+
return gloasType.getViewDU(progressiveListRootNode(elementNodes, length));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Migrate a basic list from fulu to its gloas progressive-list equivalent by reusing the fulu
|
|
144
|
+
* list's packed chunk leaf nodes.
|
|
145
|
+
*
|
|
146
|
+
* Packed leaf chunks are bit-identical between List[T, N] and ProgressiveList[T] (same 32-byte
|
|
147
|
+
* LE packing, zero-padded final chunk); only the superstructure above the leaves differs. Reusing
|
|
148
|
+
* the leaves avoids materializing the value array (getAll), re-serializing it, and allocating
|
|
149
|
+
* fresh LeafNodes — the gloas tree shares the leaf nodes with the fulu tree.
|
|
150
|
+
* Requires the fulu view to be committed (done at the top of upgradeStateToGloas).
|
|
151
|
+
*/
|
|
152
|
+
function migrateBasicListToGloas<ElementType extends BasicType<unknown>>(
|
|
153
|
+
fuluList: ListBasicTreeViewDU<ElementType>,
|
|
154
|
+
gloasType: ProgressiveListBasicType<ElementType>
|
|
155
|
+
) {
|
|
156
|
+
const {length, type} = fuluList;
|
|
157
|
+
const chunkCount = Math.ceil(length / type.itemsPerChunk);
|
|
158
|
+
// List root = BranchNode(chunksNode, lengthNode) → chunks tree is the left child
|
|
159
|
+
const chunkLeafNodes = getNodesAtDepth(fuluList.node.left, type.chunkDepth, 0, chunkCount);
|
|
160
|
+
return gloasType.getViewDU(progressiveListRootNode(chunkLeafNodes, length));
|
|
161
|
+
}
|
|
162
|
+
|
|
88
163
|
/**
|
|
89
164
|
* Applies any pending deposits for builders to onboard builders during the fork transition
|
|
90
165
|
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.8/specs/gloas/fork.md#new-onboard_builders_from_pending_deposits
|
|
@@ -94,7 +169,7 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
|
|
|
94
169
|
// at the fork, so every builder pubkey here is one added in an earlier iteration.
|
|
95
170
|
const builderPubkeys = new Set<string>();
|
|
96
171
|
|
|
97
|
-
const pendingDeposits = ssz.
|
|
172
|
+
const pendingDeposits = ssz.gloas.PendingDeposits.defaultViewDU();
|
|
98
173
|
const pendingDepositsLookup = PendingDepositsLookup.buildEmpty();
|
|
99
174
|
|
|
100
175
|
for (let i = 0; i < state.pendingDeposits.length; i++) {
|
|
@@ -515,14 +515,6 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
515
515
|
return this.cachedState.epochCtx.getBeaconProposer(slot);
|
|
516
516
|
}
|
|
517
517
|
|
|
518
|
-
getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null {
|
|
519
|
-
try {
|
|
520
|
-
return this.cachedState.epochCtx.getBeaconProposer(slot);
|
|
521
|
-
} catch {
|
|
522
|
-
return null;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
518
|
computeAnchorCheckpoint(): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} {
|
|
527
519
|
return computeAnchorCheckpoint(this.config, this.cachedState);
|
|
528
520
|
}
|
|
@@ -92,7 +92,6 @@ export interface IBeaconStateView {
|
|
|
92
92
|
currentProposers: ValidatorIndex[];
|
|
93
93
|
nextProposers: ValidatorIndex[];
|
|
94
94
|
getBeaconProposer(slot: Slot): ValidatorIndex;
|
|
95
|
-
getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null;
|
|
96
95
|
|
|
97
96
|
// Validators and balances
|
|
98
97
|
effectiveBalanceIncrements: EffectiveBalanceIncrements;
|
|
@@ -128,8 +128,6 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
128
128
|
private readonly _getBeaconCommitteeCountPerSlot = new Map<Epoch, number>();
|
|
129
129
|
private readonly _getShufflingDecisionRoot = new Map<Epoch, RootHex>();
|
|
130
130
|
private readonly _getBeaconProposer = new Map<Slot, ValidatorIndex>();
|
|
131
|
-
// getBeaconProposerOrNull can return null, so use .has() to distinguish "not cached" from "cached null"
|
|
132
|
-
private readonly _getBeaconProposerOrNull = new Map<Slot, ValidatorIndex | null>();
|
|
133
131
|
private readonly _getValidator = new Map<ValidatorIndex, phase0.Validator>();
|
|
134
132
|
private readonly _getBalance = new Map<number, number>();
|
|
135
133
|
private readonly _getIndexedSyncCommitteeAtEpoch = new Map<Epoch, SyncCommitteeCache>();
|
|
@@ -411,14 +409,6 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
411
409
|
return cached;
|
|
412
410
|
}
|
|
413
411
|
|
|
414
|
-
getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null {
|
|
415
|
-
if (!this._getBeaconProposerOrNull.has(slot)) {
|
|
416
|
-
this._getBeaconProposerOrNull.set(slot, this.binding.getBeaconProposerOrNull(slot));
|
|
417
|
-
}
|
|
418
|
-
// biome-ignore lint/style/noNonNullAssertion: has() check guarantees a value
|
|
419
|
-
return this._getBeaconProposerOrNull.get(slot)!;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
412
|
// Validators and balances
|
|
423
413
|
|
|
424
414
|
get effectiveBalanceIncrements(): EffectiveBalanceIncrements {
|
package/src/util/execution.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
bellatrix,
|
|
10
10
|
capella,
|
|
11
11
|
deneb,
|
|
12
|
+
gloas,
|
|
12
13
|
isBlindedBeaconBlockBody,
|
|
13
14
|
isExecutionPayload,
|
|
14
15
|
ssz,
|
|
@@ -127,7 +128,10 @@ export function isCapellaPayloadHeader(
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: ExecutionPayload): ExecutionPayloadHeader {
|
|
130
|
-
const transactionsRoot =
|
|
131
|
+
const transactionsRoot =
|
|
132
|
+
fork >= ForkSeq.gloas
|
|
133
|
+
? ssz.gloas.Transactions.hashTreeRoot((payload as gloas.ExecutionPayload).transactions)
|
|
134
|
+
: ssz.bellatrix.Transactions.hashTreeRoot(payload.transactions);
|
|
131
135
|
|
|
132
136
|
const bellatrixPayloadFields: ExecutionPayloadHeader = {
|
|
133
137
|
parentHash: payload.parentHash,
|
|
@@ -147,9 +151,10 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio
|
|
|
147
151
|
};
|
|
148
152
|
|
|
149
153
|
if (fork >= ForkSeq.capella) {
|
|
150
|
-
(bellatrixPayloadFields as capella.ExecutionPayloadHeader).withdrawalsRoot =
|
|
151
|
-
|
|
152
|
-
|
|
154
|
+
(bellatrixPayloadFields as capella.ExecutionPayloadHeader).withdrawalsRoot =
|
|
155
|
+
fork >= ForkSeq.gloas
|
|
156
|
+
? ssz.gloas.Withdrawals.hashTreeRoot((payload as gloas.ExecutionPayload).withdrawals)
|
|
157
|
+
: ssz.capella.Withdrawals.hashTreeRoot((payload as capella.ExecutionPayload).withdrawals);
|
|
153
158
|
}
|
|
154
159
|
|
|
155
160
|
if (fork >= ForkSeq.deneb) {
|