@lodestar/state-transition 1.47.0 → 1.48.0-dev.0dbea0de1b
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/processWithdrawals.d.ts.map +1 -1
- package/lib/block/processWithdrawals.js +8 -2
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/lightClient/spec/index.d.ts +1 -1
- package/lib/lightClient/spec/index.d.ts.map +1 -1
- package/lib/lightClient/spec/index.js +1 -1
- package/lib/lightClient/spec/index.js.map +1 -1
- package/lib/lightClient/spec/utils.d.ts +13 -3
- package/lib/lightClient/spec/utils.d.ts.map +1 -1
- package/lib/lightClient/spec/utils.js +108 -34
- package/lib/lightClient/spec/utils.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +2 -1
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +6 -1
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/computeNewStateRoot.d.ts +6 -0
- package/lib/stateView/computeNewStateRoot.d.ts.map +1 -0
- package/lib/stateView/computeNewStateRoot.js +28 -0
- package/lib/stateView/computeNewStateRoot.js.map +1 -0
- package/lib/stateView/interface.d.ts +17 -2
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/interface.js.map +1 -1
- package/lib/stateView/nativeBeaconStateView.d.ts +2 -1
- package/lib/stateView/nativeBeaconStateView.d.ts.map +1 -1
- package/lib/stateView/nativeBeaconStateView.js +5 -0
- package/lib/stateView/nativeBeaconStateView.js.map +1 -1
- package/package.json +7 -7
- package/src/block/processWithdrawals.ts +12 -2
- package/src/index.ts +2 -0
- package/src/lightClient/spec/index.ts +2 -0
- package/src/lightClient/spec/utils.ts +142 -48
- package/src/stateView/beaconStateView.ts +16 -1
- package/src/stateView/computeNewStateRoot.ts +35 -0
- package/src/stateView/interface.ts +24 -1
- package/src/stateView/nativeBeaconStateView.ts +10 -0
|
@@ -23,18 +23,18 @@ import {
|
|
|
23
23
|
} from "@lodestar/params";
|
|
24
24
|
import {
|
|
25
25
|
BeaconBlockHeader,
|
|
26
|
+
LightClientBootstrap,
|
|
26
27
|
LightClientFinalityUpdate,
|
|
27
28
|
LightClientHeader,
|
|
28
29
|
LightClientOptimisticUpdate,
|
|
29
30
|
LightClientUpdate,
|
|
30
|
-
Slot,
|
|
31
31
|
SyncCommittee,
|
|
32
32
|
isElectraLightClientUpdate,
|
|
33
33
|
ssz,
|
|
34
34
|
} from "@lodestar/types";
|
|
35
|
-
import {byteArrayEquals, verifyMerkleBranch} from "@lodestar/utils";
|
|
36
|
-
import {computeEpochAtSlot
|
|
37
|
-
import type {
|
|
35
|
+
import {byteArrayEquals, hash, verifyMerkleBranch} from "@lodestar/utils";
|
|
36
|
+
import {computeEpochAtSlot} from "../../util/epoch.js";
|
|
37
|
+
import type {ILightClientStore, SyncCommitteeFast} from "./store.js";
|
|
38
38
|
|
|
39
39
|
export const GENESIS_SLOT = 0;
|
|
40
40
|
export const ZERO_HASH = new Uint8Array(32);
|
|
@@ -201,6 +201,76 @@ function getGindexIndex(gindex: number): number {
|
|
|
201
201
|
return gindex - 2 ** getGindexDepth(gindex);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Returns the execution root represented by a light-client header.
|
|
206
|
+
*
|
|
207
|
+
* Gloas headers removed `execution` so Pre-Gloas headers upgraded to the Gloas format
|
|
208
|
+
* require reconstruction of the original execution payload header root.
|
|
209
|
+
*
|
|
210
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/e762dd6e2c45ee05648b5787e7d261279aec226a/specs/gloas/light-client/sync-protocol.md#modified-get_lc_execution_root
|
|
211
|
+
*/
|
|
212
|
+
export function getLcExecutionRoot(config: ChainForkConfig, header: LightClientHeader): Uint8Array {
|
|
213
|
+
const epoch = computeEpochAtSlot(header.beacon.slot);
|
|
214
|
+
|
|
215
|
+
if (!isGloasLightClientHeader(header)) {
|
|
216
|
+
if (epoch < config.CAPELLA_FORK_EPOCH) {
|
|
217
|
+
return ZERO_HASH;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return config
|
|
221
|
+
.getPostBellatrixForkTypes(header.beacon.slot)
|
|
222
|
+
.ExecutionPayloadHeader.hashTreeRoot((header as LightClientHeader<ForkName.capella>).execution);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (epoch >= config.GLOAS_FORK_EPOCH) {
|
|
226
|
+
return header.executionBlockHash;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Reconstruct the pre-Gloas execution payload root for a header upgraded to the Gloas format
|
|
230
|
+
// because the structure is different, `execution` is removed
|
|
231
|
+
const executionPayloadDepth = getGindexDepth(BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX);
|
|
232
|
+
const innerBranch = header.executionBranch.slice(0, -executionPayloadDepth);
|
|
233
|
+
|
|
234
|
+
if (epoch >= config.DENEB_FORK_EPOCH) {
|
|
235
|
+
if (header.beacon.slot === GENESIS_SLOT) {
|
|
236
|
+
return ssz.deneb.ExecutionPayloadHeader.hashTreeRoot(ssz.deneb.ExecutionPayloadHeader.defaultValue());
|
|
237
|
+
}
|
|
238
|
+
return computeBranchRoot(
|
|
239
|
+
header.executionBlockHash,
|
|
240
|
+
innerBranch,
|
|
241
|
+
ssz.deneb.ExecutionPayloadHeader.getPathInfo(["blockHash"]).gindex
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (epoch >= config.CAPELLA_FORK_EPOCH) {
|
|
246
|
+
if (header.beacon.slot === GENESIS_SLOT) {
|
|
247
|
+
return ssz.capella.ExecutionPayloadHeader.hashTreeRoot(ssz.capella.ExecutionPayloadHeader.defaultValue());
|
|
248
|
+
}
|
|
249
|
+
return computeBranchRoot(
|
|
250
|
+
header.executionBlockHash,
|
|
251
|
+
innerBranch,
|
|
252
|
+
ssz.capella.ExecutionPayloadHeader.getPathInfo(["blockHash"]).gindex
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return ZERO_HASH;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function upgradeLightClientBootstrap(
|
|
260
|
+
config: ChainForkConfig,
|
|
261
|
+
targetFork: ForkName,
|
|
262
|
+
bootstrap: LightClientBootstrap
|
|
263
|
+
): LightClientBootstrap {
|
|
264
|
+
return {
|
|
265
|
+
...bootstrap,
|
|
266
|
+
header: upgradeLightClientHeader(config, targetFork, bootstrap.header),
|
|
267
|
+
currentSyncCommitteeBranch: normalizeMerkleBranch(
|
|
268
|
+
bootstrap.currentSyncCommitteeBranch,
|
|
269
|
+
currentSyncCommitteeGindexAtFork(targetFork)
|
|
270
|
+
),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
204
274
|
export function upgradeLightClientHeader(
|
|
205
275
|
config: ChainForkConfig,
|
|
206
276
|
targetFork: ForkName,
|
|
@@ -211,9 +281,7 @@ export function upgradeLightClientHeader(
|
|
|
211
281
|
throw Error(`Invalid upgrade request from headerFork=${headerFork} to targetFork=${targetFork}`);
|
|
212
282
|
}
|
|
213
283
|
|
|
214
|
-
|
|
215
|
-
// not required as of now
|
|
216
|
-
let upgradedHeader = header;
|
|
284
|
+
let upgradedHeader = {...header} as LightClientHeader;
|
|
217
285
|
const startUpgradeFromFork = Object.values(ForkName)[ForkSeq[headerFork] + 1];
|
|
218
286
|
|
|
219
287
|
switch (startUpgradeFromFork) {
|
|
@@ -231,23 +299,30 @@ export function upgradeLightClientHeader(
|
|
|
231
299
|
|
|
232
300
|
// biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here
|
|
233
301
|
case ForkName.capella:
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
ssz.capella.LightClientHeader.fields.executionBranch.defaultValue()
|
|
302
|
+
upgradedHeader = {
|
|
303
|
+
...upgradedHeader,
|
|
304
|
+
execution: ssz.capella.LightClientHeader.fields.execution.defaultValue(),
|
|
305
|
+
executionBranch: ssz.capella.LightClientHeader.fields.executionBranch.defaultValue(),
|
|
306
|
+
} as LightClientHeader<ForkName.capella>;
|
|
238
307
|
|
|
239
308
|
// Break if no further upgradation is required else fall through
|
|
240
309
|
if (ForkSeq[targetFork] <= ForkSeq.capella) break;
|
|
241
310
|
|
|
242
311
|
// biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here
|
|
243
|
-
case ForkName.deneb:
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
312
|
+
case ForkName.deneb: {
|
|
313
|
+
const capellaHeader = upgradedHeader as LightClientHeader<ForkName.capella>;
|
|
314
|
+
upgradedHeader = {
|
|
315
|
+
...capellaHeader,
|
|
316
|
+
execution: {
|
|
317
|
+
...capellaHeader.execution,
|
|
318
|
+
blobGasUsed: ssz.deneb.LightClientHeader.fields.execution.fields.blobGasUsed.defaultValue(),
|
|
319
|
+
excessBlobGas: ssz.deneb.LightClientHeader.fields.execution.fields.excessBlobGas.defaultValue(),
|
|
320
|
+
},
|
|
321
|
+
} as LightClientHeader<ForkName.deneb>;
|
|
248
322
|
|
|
249
323
|
// Break if no further upgradation is required else fall through
|
|
250
324
|
if (ForkSeq[targetFork] <= ForkSeq.deneb) break;
|
|
325
|
+
}
|
|
251
326
|
|
|
252
327
|
// biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here
|
|
253
328
|
case ForkName.electra:
|
|
@@ -361,15 +436,16 @@ export function upgradeLightClientUpdate(
|
|
|
361
436
|
targetFork: ForkName,
|
|
362
437
|
update: LightClientUpdate
|
|
363
438
|
): LightClientUpdate {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
update.
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
439
|
+
return {
|
|
440
|
+
...update,
|
|
441
|
+
attestedHeader: upgradeLightClientHeader(config, targetFork, update.attestedHeader),
|
|
442
|
+
finalizedHeader: upgradeLightClientHeader(config, targetFork, update.finalizedHeader),
|
|
443
|
+
nextSyncCommitteeBranch: normalizeMerkleBranch(
|
|
444
|
+
update.nextSyncCommitteeBranch,
|
|
445
|
+
nextSyncCommitteeGindexAtFork(targetFork)
|
|
446
|
+
),
|
|
447
|
+
finalityBranch: normalizeMerkleBranch(update.finalityBranch, finalizedRootGindexAtFork(targetFork)),
|
|
448
|
+
};
|
|
373
449
|
}
|
|
374
450
|
|
|
375
451
|
export function upgradeLightClientFinalityUpdate(
|
|
@@ -377,14 +453,12 @@ export function upgradeLightClientFinalityUpdate(
|
|
|
377
453
|
targetFork: ForkName,
|
|
378
454
|
finalityUpdate: LightClientFinalityUpdate
|
|
379
455
|
): LightClientFinalityUpdate {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
finalityUpdate.
|
|
384
|
-
finalizedRootGindexAtFork(targetFork)
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
return finalityUpdate;
|
|
456
|
+
return {
|
|
457
|
+
...finalityUpdate,
|
|
458
|
+
attestedHeader: upgradeLightClientHeader(config, targetFork, finalityUpdate.attestedHeader),
|
|
459
|
+
finalizedHeader: upgradeLightClientHeader(config, targetFork, finalityUpdate.finalizedHeader),
|
|
460
|
+
finalityBranch: normalizeMerkleBranch(finalityUpdate.finalityBranch, finalizedRootGindexAtFork(targetFork)),
|
|
461
|
+
};
|
|
388
462
|
}
|
|
389
463
|
|
|
390
464
|
export function upgradeLightClientOptimisticUpdate(
|
|
@@ -392,9 +466,10 @@ export function upgradeLightClientOptimisticUpdate(
|
|
|
392
466
|
targetFork: ForkName,
|
|
393
467
|
optimisticUpdate: LightClientOptimisticUpdate
|
|
394
468
|
): LightClientOptimisticUpdate {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
469
|
+
return {
|
|
470
|
+
...optimisticUpdate,
|
|
471
|
+
attestedHeader: upgradeLightClientHeader(config, targetFork, optimisticUpdate.attestedHeader),
|
|
472
|
+
};
|
|
398
473
|
}
|
|
399
474
|
|
|
400
475
|
/**
|
|
@@ -405,25 +480,44 @@ export function upgradeLightClientOptimisticUpdate(
|
|
|
405
480
|
export function upgradeLightClientStore(
|
|
406
481
|
config: ChainForkConfig,
|
|
407
482
|
targetFork: ForkName,
|
|
408
|
-
store:
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
update: upgradeLightClientUpdate(config, targetFork, bestValidUpdate.update),
|
|
417
|
-
summary: bestValidUpdate.summary,
|
|
483
|
+
store: ILightClientStore
|
|
484
|
+
): ILightClientStore {
|
|
485
|
+
const bestValidUpdates = new Map();
|
|
486
|
+
|
|
487
|
+
for (const [period, entry] of store.bestValidUpdates) {
|
|
488
|
+
bestValidUpdates.set(period, {
|
|
489
|
+
...entry,
|
|
490
|
+
update: upgradeLightClientUpdate(config, targetFork, entry.update),
|
|
418
491
|
});
|
|
419
492
|
}
|
|
493
|
+
const finalizedHeader = upgradeLightClientHeader(config, targetFork, store.finalizedHeader);
|
|
494
|
+
const optimisticHeader = upgradeLightClientHeader(config, targetFork, store.optimisticHeader);
|
|
420
495
|
|
|
421
|
-
|
|
422
|
-
|
|
496
|
+
for (const [period, bestValidUpdate] of bestValidUpdates) {
|
|
497
|
+
store.bestValidUpdates.set(period, bestValidUpdate);
|
|
498
|
+
}
|
|
499
|
+
store.finalizedHeader = finalizedHeader;
|
|
500
|
+
store.optimisticHeader = optimisticHeader;
|
|
423
501
|
|
|
424
502
|
return store;
|
|
425
503
|
}
|
|
426
504
|
|
|
505
|
+
function computeBranchRoot(leaf: Uint8Array, branch: Uint8Array[], gindex: bigint): Uint8Array {
|
|
506
|
+
const depth = getGindexDepth(Number(gindex));
|
|
507
|
+
if (branch.length < depth) {
|
|
508
|
+
throw Error(`Invalid Merkle branch length ${branch.length}, expected at least ${depth}`);
|
|
509
|
+
}
|
|
510
|
+
const proof = branch.slice(-depth);
|
|
511
|
+
const index = getGindexIndex(Number(gindex));
|
|
512
|
+
let root = leaf;
|
|
513
|
+
|
|
514
|
+
for (let i = 0; i < depth; i++) {
|
|
515
|
+
root = Math.floor(index / 2 ** i) % 2 === 1 ? hash(proof[i], root) : hash(root, proof[i]);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return root;
|
|
519
|
+
}
|
|
520
|
+
|
|
427
521
|
function isGloasLightClientHeader(header: LightClientHeader): header is LightClientHeader<ForkName.gloas> {
|
|
428
522
|
return (header as LightClientHeader<ForkName.gloas>).executionBlockHash !== undefined;
|
|
429
523
|
}
|
|
@@ -70,7 +70,15 @@ import {loadState} from "../util/loadState/loadState.js";
|
|
|
70
70
|
import {PreVerifyBuilderDepositsResult, preVerifyBuilderDepositsPreGloas} from "../util/preVerifyBuilderDeposits.js";
|
|
71
71
|
import {getRandaoMix} from "../util/seed.js";
|
|
72
72
|
import {getLatestWeakSubjectivityCheckpointEpoch} from "../util/weakSubjectivity.js";
|
|
73
|
-
import {
|
|
73
|
+
import {computeNewStateRootStateTransitionOpts, getComputeNewStateRootResult} from "./computeNewStateRoot.js";
|
|
74
|
+
import {
|
|
75
|
+
ComputeNewStateRootInput,
|
|
76
|
+
ComputeNewStateRootResult,
|
|
77
|
+
IBeaconStateView,
|
|
78
|
+
IBeaconStateViewGloas,
|
|
79
|
+
IBeaconStateViewLatestFork,
|
|
80
|
+
isStatePostGloas,
|
|
81
|
+
} from "./interface.js";
|
|
74
82
|
|
|
75
83
|
export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
76
84
|
private readonly config: BeaconConfig;
|
|
@@ -823,6 +831,13 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
823
831
|
|
|
824
832
|
// State transition
|
|
825
833
|
|
|
834
|
+
computeNewStateRoot({block}: ComputeNewStateRootInput, modules: StateTransitionModules): ComputeNewStateRootResult {
|
|
835
|
+
const postState = new BeaconStateView(
|
|
836
|
+
stateTransition(this.cachedState, block, computeNewStateRootStateTransitionOpts, modules)
|
|
837
|
+
);
|
|
838
|
+
return getComputeNewStateRootResult(postState, modules);
|
|
839
|
+
}
|
|
840
|
+
|
|
826
841
|
stateTransition(
|
|
827
842
|
signedBlock: SignedBeaconBlock | SignedBlindedBeaconBlock,
|
|
828
843
|
options: StateTransitionOpts,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {DataAvailabilityStatus, ExecutionPayloadStatus} from "../block/externalData.js";
|
|
2
|
+
import {StateHashTreeRootSource, StateTransitionModules, StateTransitionOpts} from "../stateTransition.js";
|
|
3
|
+
import {ComputeNewStateRootResult, IBeaconStateView} from "./interface.js";
|
|
4
|
+
|
|
5
|
+
/** State transition options for computing the state root of a locally produced block. */
|
|
6
|
+
export const computeNewStateRootStateTransitionOpts: StateTransitionOpts = {
|
|
7
|
+
// ExecutionPayloadStatus.valid: Assume payload valid, it has been produced by a trusted EL
|
|
8
|
+
executionPayloadStatus: ExecutionPayloadStatus.valid,
|
|
9
|
+
// DataAvailabilityStatus.available: Assume the blobs to be available, have just been produced by trusted EL
|
|
10
|
+
dataAvailabilityStatus: DataAvailabilityStatus.Available,
|
|
11
|
+
// verifyStateRoot: false | the root in the block is zero-ed, it's being computed here
|
|
12
|
+
verifyStateRoot: false,
|
|
13
|
+
// verifyProposer: false | as the block signature is zero-ed
|
|
14
|
+
verifyProposer: false,
|
|
15
|
+
// verifySignatures: false | since the data to assemble the block is trusted
|
|
16
|
+
verifySignatures: false,
|
|
17
|
+
// Preserve cache in source state, since the resulting state is not added to the state cache
|
|
18
|
+
dontTransferCache: true,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function getComputeNewStateRootResult(
|
|
22
|
+
postState: IBeaconStateView,
|
|
23
|
+
{metrics}: StateTransitionModules
|
|
24
|
+
): ComputeNewStateRootResult {
|
|
25
|
+
const {attestations, syncAggregate, slashing} = postState.proposerRewards;
|
|
26
|
+
const proposerReward = BigInt(attestations + syncAggregate + slashing);
|
|
27
|
+
|
|
28
|
+
const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer({
|
|
29
|
+
source: StateHashTreeRootSource.computeNewStateRoot,
|
|
30
|
+
});
|
|
31
|
+
const newStateRoot = postState.hashTreeRoot();
|
|
32
|
+
hashTreeRootTimer?.();
|
|
33
|
+
|
|
34
|
+
return {newStateRoot, proposerReward, postState};
|
|
35
|
+
}
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
Epoch,
|
|
30
30
|
ExecutionPayloadBid,
|
|
31
31
|
ExecutionPayloadHeader,
|
|
32
|
+
Gwei,
|
|
32
33
|
Root,
|
|
33
34
|
RootHex,
|
|
34
35
|
SignedBeaconBlock,
|
|
@@ -54,6 +55,20 @@ import {StateTransitionModules, StateTransitionOpts} from "../stateTransition.js
|
|
|
54
55
|
import {EpochShuffling} from "../util/epochShuffling.js";
|
|
55
56
|
import {PreVerifyBuilderDepositsResult} from "../util/preVerifyBuilderDeposits.js";
|
|
56
57
|
|
|
58
|
+
/** Inputs for computing the state root of a locally produced block. */
|
|
59
|
+
export type ComputeNewStateRootInput = {
|
|
60
|
+
block: SignedBeaconBlock | SignedBlindedBeaconBlock;
|
|
61
|
+
/** Pre-serialized block bytes for native implementations. */
|
|
62
|
+
ssz?: Uint8Array;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** State root computation result. Includes data derived from the post-state. */
|
|
66
|
+
export type ComputeNewStateRootResult = {
|
|
67
|
+
newStateRoot: Root;
|
|
68
|
+
proposerReward: Gwei;
|
|
69
|
+
postState: IBeaconStateView;
|
|
70
|
+
};
|
|
71
|
+
|
|
57
72
|
/**
|
|
58
73
|
* A read-only view of the BeaconState.
|
|
59
74
|
*/
|
|
@@ -161,6 +176,7 @@ export interface IBeaconStateView {
|
|
|
161
176
|
hashTreeRoot(): Uint8Array;
|
|
162
177
|
|
|
163
178
|
// State transition
|
|
179
|
+
computeNewStateRoot(input: ComputeNewStateRootInput, modules: StateTransitionModules): ComputeNewStateRootResult;
|
|
164
180
|
stateTransition(
|
|
165
181
|
signedBlock: SignedBeaconBlock | SignedBlindedBeaconBlock,
|
|
166
182
|
options: StateTransitionOpts,
|
|
@@ -308,13 +324,20 @@ export type IBeaconStateViewLatestFork = Omit<
|
|
|
308
324
|
* `loadOtherState`, `withParentPayloadApplied`) return `IBeaconStateViewNative`
|
|
309
325
|
* so callers can re-wrap without an `as unknown` cast. Param lists are reused
|
|
310
326
|
* via `Parameters<...>` to avoid duplicating signatures.
|
|
327
|
+
* - `computeNewStateRoot` is implemented by the wrapper because its inputs differ
|
|
328
|
+
* between the TypeScript and Zig implementations.
|
|
311
329
|
*
|
|
312
330
|
* The TS-side `BeaconStateView` also structurally satisfies this contract since
|
|
313
331
|
* `BitArray` exposes `uint8Array` and `bitLen`.
|
|
314
332
|
*/
|
|
315
333
|
export type IBeaconStateViewNative = Omit<
|
|
316
334
|
IBeaconStateViewLatestFork,
|
|
317
|
-
|
|
335
|
+
| "computeNewStateRoot"
|
|
336
|
+
| "executionPayloadAvailability"
|
|
337
|
+
| "loadOtherState"
|
|
338
|
+
| "stateTransition"
|
|
339
|
+
| "processSlots"
|
|
340
|
+
| "withParentPayloadApplied"
|
|
318
341
|
> & {
|
|
319
342
|
executionPayloadAvailability: {uint8Array: Uint8Array; bitLen: number};
|
|
320
343
|
loadOtherState(...args: Parameters<IBeaconStateViewLatestFork["loadOtherState"]>): IBeaconStateViewNative;
|
|
@@ -36,7 +36,10 @@ import {SyncCommitteeWitness} from "../lightClient/types.js";
|
|
|
36
36
|
import {StateTransitionModules, StateTransitionOpts} from "../stateTransition.js";
|
|
37
37
|
import {EpochShuffling} from "../util/epochShuffling.js";
|
|
38
38
|
import {PreVerifyBuilderDepositsResult} from "../util/preVerifyBuilderDeposits.js";
|
|
39
|
+
import {computeNewStateRootStateTransitionOpts, getComputeNewStateRootResult} from "./computeNewStateRoot.js";
|
|
39
40
|
import {
|
|
41
|
+
ComputeNewStateRootInput,
|
|
42
|
+
ComputeNewStateRootResult,
|
|
40
43
|
IBeaconStateView,
|
|
41
44
|
IBeaconStateViewGloas,
|
|
42
45
|
IBeaconStateViewLatestFork,
|
|
@@ -637,6 +640,13 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
637
640
|
|
|
638
641
|
// State transition
|
|
639
642
|
|
|
643
|
+
computeNewStateRoot(input: ComputeNewStateRootInput, modules: StateTransitionModules): ComputeNewStateRootResult {
|
|
644
|
+
const postState = new NativeBeaconStateView(
|
|
645
|
+
this.binding.stateTransition(input.block, computeNewStateRootStateTransitionOpts, modules)
|
|
646
|
+
);
|
|
647
|
+
return getComputeNewStateRootResult(postState, modules);
|
|
648
|
+
}
|
|
649
|
+
|
|
640
650
|
stateTransition(
|
|
641
651
|
signedBlock: SignedBeaconBlock | SignedBlindedBeaconBlock,
|
|
642
652
|
options: StateTransitionOpts,
|