@lodestar/state-transition 1.44.0-dev.f715896231 → 1.44.0-dev.ff43f013ea

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.
@@ -0,0 +1,893 @@
1
+ import {CompactMultiProof} from "@chainsafe/persistent-merkle-tree";
2
+ import {BitArray, ByteViews} from "@chainsafe/ssz";
3
+ import {ForkName} from "@lodestar/params";
4
+ import {
5
+ BeaconBlock,
6
+ BeaconState,
7
+ BlindedBeaconBlock,
8
+ BuilderIndex,
9
+ Bytes32,
10
+ Epoch,
11
+ ExecutionPayloadBid,
12
+ ExecutionPayloadHeader,
13
+ Root,
14
+ RootHex,
15
+ SignedBeaconBlock,
16
+ SignedBlindedBeaconBlock,
17
+ Slot,
18
+ SyncCommittee,
19
+ ValidatorIndex,
20
+ altair,
21
+ capella,
22
+ electra,
23
+ fulu,
24
+ gloas,
25
+ phase0,
26
+ rewards,
27
+ } from "@lodestar/types";
28
+ import {Checkpoint, Fork} from "@lodestar/types/phase0";
29
+ import {VoluntaryExitValidity} from "../block/processVoluntaryExit.js";
30
+ import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
31
+ import {EpochTransitionCacheOpts} from "../cache/epochTransitionCache.js";
32
+ import {RewardCache} from "../cache/rewardCache.js";
33
+ import {SyncCommitteeCache} from "../cache/syncCommitteeCache.js";
34
+ import {SyncCommitteeWitness} from "../lightClient/types.js";
35
+ import {StateTransitionModules, StateTransitionOpts} from "../stateTransition.js";
36
+ import {EpochShuffling} from "../util/epochShuffling.js";
37
+ import {
38
+ IBeaconStateView,
39
+ IBeaconStateViewGloas,
40
+ IBeaconStateViewLatestFork,
41
+ IBeaconStateViewNative,
42
+ isStatePostGloas,
43
+ } from "./interface.js";
44
+
45
+ /**
46
+ * Wraps a native binding (the auto-generated JS interface produced by a `.node`
47
+ * file) and exposes it as a fully-conformant `IBeaconStateViewLatestFork`.
48
+ *
49
+ * The binding is typed `IBeaconStateViewNative` — identical to
50
+ * `IBeaconStateViewLatestFork` except `executionPayloadAvailability` is a raw
51
+ * `{uint8Array, bitLen}` POJO. The `executionPayloadAvailability` getter lifts
52
+ * that POJO back to a `BitArray` so beacon-node consumers see no difference from
53
+ * the TS-side `BeaconStateView`.
54
+ *
55
+ * Every getter that returns a value stable for the view's lifetime is cached so
56
+ * the binding is hit at most once per field per view. Only mutable counters
57
+ * (`proposerRewards`, `clonedCount`, `clonedCountWithTransferCache`) stay
58
+ * pass-through. Methods with arguments are pass-through too — caching them
59
+ * would need a per-arg map and isn't worth it without a hot-path signal.
60
+ */
61
+ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
62
+ // phase0
63
+ private _forkName: ForkName | null = null;
64
+ private _slot: Slot | null = null;
65
+ private _fork: Fork | null = null;
66
+ private _epoch: Epoch | null = null;
67
+ private _genesisTime: number | null = null;
68
+ private _genesisValidatorsRoot: Root | null = null;
69
+ private _eth1Data: phase0.Eth1Data | null = null;
70
+ private _latestBlockHeader: phase0.BeaconBlockHeader | null = null;
71
+ private _previousJustifiedCheckpoint: Checkpoint | null = null;
72
+ private _currentJustifiedCheckpoint: Checkpoint | null = null;
73
+ private _finalizedCheckpoint: Checkpoint | null = null;
74
+ // shuffling / decision roots / proposers
75
+ private _previousDecisionRoot: RootHex | null = null;
76
+ private _currentDecisionRoot: RootHex | null = null;
77
+ private _nextDecisionRoot: RootHex | null = null;
78
+ // previousProposers can be null, so use undefined as the "not loaded" sentinel
79
+ private _previousProposers: ValidatorIndex[] | null | undefined = undefined;
80
+ private _currentProposers: ValidatorIndex[] | null = null;
81
+ private _nextProposers: ValidatorIndex[] | null = null;
82
+ // validators / balances
83
+ private _effectiveBalanceIncrements: EffectiveBalanceIncrements | null = null;
84
+ private _validatorCount: number | null = null;
85
+ private _activeValidatorCount: number | null = null;
86
+ // backward compat
87
+ private _createdWithTransferCache: boolean | null = null;
88
+ // altair
89
+ private _currentSyncCommittee: SyncCommittee | null = null;
90
+ private _nextSyncCommittee: SyncCommittee | null = null;
91
+ private _previousEpochParticipation: Uint8Array | null = null;
92
+ private _currentEpochParticipation: Uint8Array | null = null;
93
+ private _currentSyncCommitteeIndexed: SyncCommitteeCache | null = null;
94
+ private _syncProposerReward: number | null = null;
95
+ // bellatrix
96
+ private _latestExecutionPayloadHeader: ExecutionPayloadHeader | null = null;
97
+ private _payloadBlockNumber: number | null = null;
98
+ private _isExecutionStateType: boolean | null = null;
99
+ private _isMergeTransitionComplete: boolean | null = null;
100
+ // capella
101
+ private _historicalSummaries: capella.HistoricalSummaries | null = null;
102
+ // electra
103
+ private _pendingPartialWithdrawals: electra.PendingPartialWithdrawals | null = null;
104
+ private _pendingConsolidations: electra.PendingConsolidations | null = null;
105
+ private _pendingDeposits: electra.PendingDeposits | null = null;
106
+ private _pendingDepositsCount: number | null = null;
107
+ private _pendingPartialWithdrawalsCount: number | null = null;
108
+ private _pendingConsolidationsCount: number | null = null;
109
+ // fulu
110
+ private _proposerLookahead: fulu.ProposerLookahead | null = null;
111
+ // gloas
112
+ private _executionPayloadAvailability: BitArray | null = null;
113
+ private _latestBlockHash: Bytes32 | null = null;
114
+ private _latestExecutionPayloadBid: ExecutionPayloadBid | null = null;
115
+ private _payloadExpectedWithdrawals: capella.Withdrawal[] | null = null;
116
+
117
+ // Per-argument caches for argument-taking methods. The binding is treated as
118
+ // immutable for the view's lifetime, so a given argument always yields the
119
+ // same result. Maps grow only with touched arguments — typical call patterns
120
+ // (e.g. a handful of slots per attestation pool scan) keep them tiny.
121
+ private readonly _getBlockRootAtSlot = new Map<Slot, Root>();
122
+ private readonly _getBlockRootAtEpoch = new Map<Epoch, Root>();
123
+ private readonly _getStateRootAtSlot = new Map<Slot, Root>();
124
+ private readonly _getRandaoMix = new Map<Epoch, Bytes32>();
125
+ private readonly _getShufflingAtEpoch = new Map<Epoch, EpochShuffling>();
126
+ private readonly _getShufflingDecisionRoot = new Map<Epoch, RootHex>();
127
+ private readonly _getBeaconProposer = new Map<Slot, ValidatorIndex>();
128
+ // getBeaconProposerOrNull can return null, so use .has() to distinguish "not cached" from "cached null"
129
+ private readonly _getBeaconProposerOrNull = new Map<Slot, ValidatorIndex | null>();
130
+ private readonly _getValidator = new Map<ValidatorIndex, phase0.Validator>();
131
+ private readonly _getBalance = new Map<number, number>();
132
+ private readonly _getIndexedSyncCommitteeAtEpoch = new Map<Epoch, SyncCommitteeCache>();
133
+ private readonly _getIndexedSyncCommittee = new Map<Slot, SyncCommitteeCache>();
134
+ private readonly _getSingleProof = new Map<bigint, Uint8Array[]>();
135
+ private readonly _getEpochPTCs = new Map<Epoch, Uint32Array[]>();
136
+ private readonly _getBuilder = new Map<BuilderIndex, gloas.Builder>();
137
+
138
+ // No-arg method caches
139
+ private _getPreviousShuffling: EpochShuffling | null = null;
140
+ private _getCurrentShuffling: EpochShuffling | null = null;
141
+ private _getNextShuffling: EpochShuffling | null = null;
142
+ private _getEffectiveBalanceIncrementsZeroInactive: EffectiveBalanceIncrements | null = null;
143
+ private _getAllValidators: phase0.Validator[] | null = null;
144
+ private _getAllBalances: number[] | null = null;
145
+ private _getLatestWeakSubjectivityCheckpointEpoch: Epoch | null = null;
146
+ private _getFinalizedRootProof: Uint8Array[] | null = null;
147
+ private _computeUnrealizedCheckpoints: {
148
+ justifiedCheckpoint: phase0.Checkpoint;
149
+ finalizedCheckpoint: phase0.Checkpoint;
150
+ } | null = null;
151
+ private _computeAnchorCheckpoint: {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} | null =
152
+ null;
153
+ private _isStateValidatorsNodesPopulated: boolean | null = null;
154
+ private _toValue: BeaconState | null = null;
155
+ private _serialize: Uint8Array | null = null;
156
+ private _serializedSize: number | null = null;
157
+ private _serializeValidators: Uint8Array | null = null;
158
+ private _serializedValidatorsSize: number | null = null;
159
+ private _hashTreeRoot: Uint8Array | null = null;
160
+ private _getSyncCommitteesWitness: SyncCommitteeWitness | null = null;
161
+ private _getExpectedWithdrawals: {
162
+ expectedWithdrawals: capella.Withdrawal[];
163
+ processedBuilderWithdrawalsCount: number;
164
+ processedPartialWithdrawalsCount: number;
165
+ processedBuildersSweepCount: number;
166
+ processedValidatorSweepCount: number;
167
+ } | null = null;
168
+
169
+ constructor(readonly binding: IBeaconStateViewNative) {}
170
+
171
+ // Binding returns pojo object {uint8Array: Uint8Array; bitLen: number}
172
+ // this class wrap it with BitArray to conform to the api
173
+ get executionPayloadAvailability(): BitArray {
174
+ if (this._executionPayloadAvailability === null) {
175
+ const pojo = this.binding.executionPayloadAvailability;
176
+ this._executionPayloadAvailability = new BitArray(pojo.uint8Array, pojo.bitLen);
177
+ }
178
+
179
+ return this._executionPayloadAvailability;
180
+ }
181
+
182
+ // ─── phase0 ──────────────────────────────────────────────────────────────
183
+
184
+ get forkName(): ForkName {
185
+ if (this._forkName === null) {
186
+ this._forkName = this.binding.forkName;
187
+ }
188
+ return this._forkName;
189
+ }
190
+
191
+ get slot(): Slot {
192
+ if (this._slot === null) {
193
+ this._slot = this.binding.slot;
194
+ }
195
+ return this._slot;
196
+ }
197
+
198
+ get fork(): Fork {
199
+ if (this._fork === null) {
200
+ this._fork = this.binding.fork;
201
+ }
202
+ return this._fork;
203
+ }
204
+
205
+ get epoch(): Epoch {
206
+ if (this._epoch === null) {
207
+ this._epoch = this.binding.epoch;
208
+ }
209
+ return this._epoch;
210
+ }
211
+
212
+ get genesisTime(): number {
213
+ if (this._genesisTime === null) {
214
+ this._genesisTime = this.binding.genesisTime;
215
+ }
216
+ return this._genesisTime;
217
+ }
218
+
219
+ get genesisValidatorsRoot(): Root {
220
+ if (this._genesisValidatorsRoot === null) {
221
+ this._genesisValidatorsRoot = this.binding.genesisValidatorsRoot;
222
+ }
223
+ return this._genesisValidatorsRoot;
224
+ }
225
+
226
+ get eth1Data(): phase0.Eth1Data {
227
+ if (this._eth1Data === null) {
228
+ this._eth1Data = this.binding.eth1Data;
229
+ }
230
+ return this._eth1Data;
231
+ }
232
+
233
+ get latestBlockHeader(): phase0.BeaconBlockHeader {
234
+ if (this._latestBlockHeader === null) {
235
+ this._latestBlockHeader = this.binding.latestBlockHeader;
236
+ }
237
+ return this._latestBlockHeader;
238
+ }
239
+
240
+ get previousJustifiedCheckpoint(): Checkpoint {
241
+ if (this._previousJustifiedCheckpoint === null) {
242
+ this._previousJustifiedCheckpoint = this.binding.previousJustifiedCheckpoint;
243
+ }
244
+ return this._previousJustifiedCheckpoint;
245
+ }
246
+
247
+ get currentJustifiedCheckpoint(): Checkpoint {
248
+ if (this._currentJustifiedCheckpoint === null) {
249
+ this._currentJustifiedCheckpoint = this.binding.currentJustifiedCheckpoint;
250
+ }
251
+ return this._currentJustifiedCheckpoint;
252
+ }
253
+
254
+ get finalizedCheckpoint(): Checkpoint {
255
+ if (this._finalizedCheckpoint === null) {
256
+ this._finalizedCheckpoint = this.binding.finalizedCheckpoint;
257
+ }
258
+ return this._finalizedCheckpoint;
259
+ }
260
+
261
+ getBlockRootAtSlot(slot: Slot): Root {
262
+ let cached = this._getBlockRootAtSlot.get(slot);
263
+ if (cached === undefined) {
264
+ cached = this.binding.getBlockRootAtSlot(slot);
265
+ this._getBlockRootAtSlot.set(slot, cached);
266
+ }
267
+ return cached;
268
+ }
269
+
270
+ getBlockRootAtEpoch(epoch: Epoch): Root {
271
+ let cached = this._getBlockRootAtEpoch.get(epoch);
272
+ if (cached === undefined) {
273
+ cached = this.binding.getBlockRootAtEpoch(epoch);
274
+ this._getBlockRootAtEpoch.set(epoch, cached);
275
+ }
276
+ return cached;
277
+ }
278
+
279
+ getStateRootAtSlot(slot: Slot): Root {
280
+ let cached = this._getStateRootAtSlot.get(slot);
281
+ if (cached === undefined) {
282
+ cached = this.binding.getStateRootAtSlot(slot);
283
+ this._getStateRootAtSlot.set(slot, cached);
284
+ }
285
+ return cached;
286
+ }
287
+
288
+ getRandaoMix(epoch: Epoch): Bytes32 {
289
+ let cached = this._getRandaoMix.get(epoch);
290
+ if (cached === undefined) {
291
+ cached = this.binding.getRandaoMix(epoch);
292
+ this._getRandaoMix.set(epoch, cached);
293
+ }
294
+ return cached;
295
+ }
296
+
297
+ // Shuffling and committees
298
+
299
+ getShufflingAtEpoch(epoch: Epoch): EpochShuffling {
300
+ let cached = this._getShufflingAtEpoch.get(epoch);
301
+ if (cached === undefined) {
302
+ cached = this.binding.getShufflingAtEpoch(epoch);
303
+ this._getShufflingAtEpoch.set(epoch, cached);
304
+ }
305
+ return cached;
306
+ }
307
+
308
+ get previousDecisionRoot(): RootHex {
309
+ if (this._previousDecisionRoot === null) {
310
+ this._previousDecisionRoot = this.binding.previousDecisionRoot;
311
+ }
312
+ return this._previousDecisionRoot;
313
+ }
314
+
315
+ get currentDecisionRoot(): RootHex {
316
+ if (this._currentDecisionRoot === null) {
317
+ this._currentDecisionRoot = this.binding.currentDecisionRoot;
318
+ }
319
+ return this._currentDecisionRoot;
320
+ }
321
+
322
+ get nextDecisionRoot(): RootHex {
323
+ if (this._nextDecisionRoot === null) {
324
+ this._nextDecisionRoot = this.binding.nextDecisionRoot;
325
+ }
326
+ return this._nextDecisionRoot;
327
+ }
328
+
329
+ getShufflingDecisionRoot(epoch: Epoch): RootHex {
330
+ let cached = this._getShufflingDecisionRoot.get(epoch);
331
+ if (cached === undefined) {
332
+ cached = this.binding.getShufflingDecisionRoot(epoch);
333
+ this._getShufflingDecisionRoot.set(epoch, cached);
334
+ }
335
+ return cached;
336
+ }
337
+
338
+ getPreviousShuffling(): EpochShuffling {
339
+ if (this._getPreviousShuffling === null) {
340
+ this._getPreviousShuffling = this.binding.getPreviousShuffling();
341
+ }
342
+ return this._getPreviousShuffling;
343
+ }
344
+
345
+ getCurrentShuffling(): EpochShuffling {
346
+ if (this._getCurrentShuffling === null) {
347
+ this._getCurrentShuffling = this.binding.getCurrentShuffling();
348
+ }
349
+ return this._getCurrentShuffling;
350
+ }
351
+
352
+ getNextShuffling(): EpochShuffling {
353
+ if (this._getNextShuffling === null) {
354
+ this._getNextShuffling = this.binding.getNextShuffling();
355
+ }
356
+ return this._getNextShuffling;
357
+ }
358
+
359
+ // Proposer shuffling
360
+
361
+ get previousProposers(): ValidatorIndex[] | null {
362
+ if (this._previousProposers === undefined) {
363
+ this._previousProposers = this.binding.previousProposers;
364
+ }
365
+ return this._previousProposers;
366
+ }
367
+
368
+ get currentProposers(): ValidatorIndex[] {
369
+ if (this._currentProposers === null) {
370
+ this._currentProposers = this.binding.currentProposers;
371
+ }
372
+ return this._currentProposers;
373
+ }
374
+
375
+ get nextProposers(): ValidatorIndex[] {
376
+ if (this._nextProposers === null) {
377
+ this._nextProposers = this.binding.nextProposers;
378
+ }
379
+ return this._nextProposers;
380
+ }
381
+
382
+ getBeaconProposer(slot: Slot): ValidatorIndex {
383
+ let cached = this._getBeaconProposer.get(slot);
384
+ if (cached === undefined) {
385
+ cached = this.binding.getBeaconProposer(slot);
386
+ this._getBeaconProposer.set(slot, cached);
387
+ }
388
+ return cached;
389
+ }
390
+
391
+ getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null {
392
+ if (!this._getBeaconProposerOrNull.has(slot)) {
393
+ this._getBeaconProposerOrNull.set(slot, this.binding.getBeaconProposerOrNull(slot));
394
+ }
395
+ // biome-ignore lint/style/noNonNullAssertion: has() check guarantees a value
396
+ return this._getBeaconProposerOrNull.get(slot)!;
397
+ }
398
+
399
+ // Validators and balances
400
+
401
+ get effectiveBalanceIncrements(): EffectiveBalanceIncrements {
402
+ if (this._effectiveBalanceIncrements === null) {
403
+ this._effectiveBalanceIncrements = this.binding.effectiveBalanceIncrements;
404
+ }
405
+ return this._effectiveBalanceIncrements;
406
+ }
407
+
408
+ getEffectiveBalanceIncrementsZeroInactive(): EffectiveBalanceIncrements {
409
+ if (this._getEffectiveBalanceIncrementsZeroInactive === null) {
410
+ this._getEffectiveBalanceIncrementsZeroInactive = this.binding.getEffectiveBalanceIncrementsZeroInactive();
411
+ }
412
+ return this._getEffectiveBalanceIncrementsZeroInactive;
413
+ }
414
+
415
+ getBalance(index: number): number {
416
+ let cached = this._getBalance.get(index);
417
+ if (cached === undefined) {
418
+ cached = this.binding.getBalance(index);
419
+ this._getBalance.set(index, cached);
420
+ }
421
+ return cached;
422
+ }
423
+
424
+ getValidator(index: ValidatorIndex): phase0.Validator {
425
+ let cached = this._getValidator.get(index);
426
+ if (cached === undefined) {
427
+ cached = this.binding.getValidator(index);
428
+ this._getValidator.set(index, cached);
429
+ }
430
+ return cached;
431
+ }
432
+
433
+ getValidatorsByStatus(statuses: Set<string>, currentEpoch: Epoch): phase0.Validator[] {
434
+ return this.binding.getValidatorsByStatus(statuses, currentEpoch);
435
+ }
436
+
437
+ get validatorCount(): number {
438
+ if (this._validatorCount === null) {
439
+ this._validatorCount = this.binding.validatorCount;
440
+ }
441
+ return this._validatorCount;
442
+ }
443
+
444
+ get activeValidatorCount(): number {
445
+ if (this._activeValidatorCount === null) {
446
+ this._activeValidatorCount = this.binding.activeValidatorCount;
447
+ }
448
+ return this._activeValidatorCount;
449
+ }
450
+
451
+ getAllValidators(): phase0.Validator[] {
452
+ if (this._getAllValidators === null) {
453
+ this._getAllValidators = this.binding.getAllValidators();
454
+ }
455
+ return this._getAllValidators;
456
+ }
457
+
458
+ getAllBalances(): number[] {
459
+ if (this._getAllBalances === null) {
460
+ this._getAllBalances = this.binding.getAllBalances();
461
+ }
462
+ return this._getAllBalances;
463
+ }
464
+
465
+ // API
466
+
467
+ get proposerRewards(): RewardCache {
468
+ return this.binding.proposerRewards;
469
+ }
470
+
471
+ computeBlockRewards(block: BeaconBlock, proposerRewards?: RewardCache): Promise<rewards.BlockRewards> {
472
+ return this.binding.computeBlockRewards(block, proposerRewards);
473
+ }
474
+
475
+ computeAttestationsRewards(validatorIds?: (ValidatorIndex | string)[]): Promise<rewards.AttestationsRewards> {
476
+ return this.binding.computeAttestationsRewards(validatorIds);
477
+ }
478
+
479
+ getLatestWeakSubjectivityCheckpointEpoch(): Epoch {
480
+ if (this._getLatestWeakSubjectivityCheckpointEpoch === null) {
481
+ this._getLatestWeakSubjectivityCheckpointEpoch = this.binding.getLatestWeakSubjectivityCheckpointEpoch();
482
+ }
483
+ return this._getLatestWeakSubjectivityCheckpointEpoch;
484
+ }
485
+
486
+ // Validation
487
+
488
+ getVoluntaryExitValidity(
489
+ signedVoluntaryExit: phase0.SignedVoluntaryExit,
490
+ verifySignature: boolean
491
+ ): VoluntaryExitValidity {
492
+ return this.binding.getVoluntaryExitValidity(signedVoluntaryExit, verifySignature);
493
+ }
494
+
495
+ isValidVoluntaryExit(signedVoluntaryExit: phase0.SignedVoluntaryExit, verifySignature: boolean): boolean {
496
+ return this.binding.isValidVoluntaryExit(signedVoluntaryExit, verifySignature);
497
+ }
498
+
499
+ // Proofs
500
+
501
+ getFinalizedRootProof(): Uint8Array[] {
502
+ if (this._getFinalizedRootProof === null) {
503
+ this._getFinalizedRootProof = this.binding.getFinalizedRootProof();
504
+ }
505
+ return this._getFinalizedRootProof;
506
+ }
507
+
508
+ getSingleProof(gindex: bigint): Uint8Array[] {
509
+ let cached = this._getSingleProof.get(gindex);
510
+ if (cached === undefined) {
511
+ cached = this.binding.getSingleProof(gindex);
512
+ this._getSingleProof.set(gindex, cached);
513
+ }
514
+ return cached;
515
+ }
516
+
517
+ createMultiProof(descriptor: Uint8Array): CompactMultiProof {
518
+ return this.binding.createMultiProof(descriptor);
519
+ }
520
+
521
+ // Fork choice
522
+
523
+ computeUnrealizedCheckpoints(): {
524
+ justifiedCheckpoint: phase0.Checkpoint;
525
+ finalizedCheckpoint: phase0.Checkpoint;
526
+ } {
527
+ if (this._computeUnrealizedCheckpoints === null) {
528
+ this._computeUnrealizedCheckpoints = this.binding.computeUnrealizedCheckpoints();
529
+ }
530
+ return this._computeUnrealizedCheckpoints;
531
+ }
532
+
533
+ computeAnchorCheckpoint(): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} {
534
+ if (this._computeAnchorCheckpoint === null) {
535
+ this._computeAnchorCheckpoint = this.binding.computeAnchorCheckpoint();
536
+ }
537
+ return this._computeAnchorCheckpoint;
538
+ }
539
+
540
+ // Backward compatibility
541
+
542
+ get clonedCount(): number {
543
+ return this.binding.clonedCount;
544
+ }
545
+
546
+ get clonedCountWithTransferCache(): number {
547
+ return this.binding.clonedCountWithTransferCache;
548
+ }
549
+
550
+ get createdWithTransferCache(): boolean {
551
+ if (this._createdWithTransferCache === null) {
552
+ this._createdWithTransferCache = this.binding.createdWithTransferCache;
553
+ }
554
+ return this._createdWithTransferCache;
555
+ }
556
+
557
+ isStateValidatorsNodesPopulated(): boolean {
558
+ if (this._isStateValidatorsNodesPopulated === null) {
559
+ this._isStateValidatorsNodesPopulated = this.binding.isStateValidatorsNodesPopulated();
560
+ }
561
+ return this._isStateValidatorsNodesPopulated;
562
+ }
563
+
564
+ // Serialization
565
+
566
+ loadOtherState(
567
+ stateBytes: Uint8Array,
568
+ seedValidatorsBytes?: Uint8Array,
569
+ opts?: {preloadValidatorsAndBalances?: boolean}
570
+ ): IBeaconStateView {
571
+ return new NativeBeaconStateView(this.binding.loadOtherState(stateBytes, seedValidatorsBytes, opts));
572
+ }
573
+
574
+ toValue(): BeaconState {
575
+ if (this._toValue === null) {
576
+ this._toValue = this.binding.toValue();
577
+ }
578
+ return this._toValue;
579
+ }
580
+
581
+ serialize(): Uint8Array {
582
+ if (this._serialize === null) {
583
+ this._serialize = this.binding.serialize();
584
+ }
585
+ return this._serialize;
586
+ }
587
+
588
+ serializedSize(): number {
589
+ if (this._serializedSize === null) {
590
+ this._serializedSize = this.binding.serializedSize();
591
+ }
592
+ return this._serializedSize;
593
+ }
594
+
595
+ serializeToBytes(output: ByteViews, offset: number): number {
596
+ return this.binding.serializeToBytes(output, offset);
597
+ }
598
+
599
+ serializeValidators(): Uint8Array {
600
+ if (this._serializeValidators === null) {
601
+ this._serializeValidators = this.binding.serializeValidators();
602
+ }
603
+ return this._serializeValidators;
604
+ }
605
+
606
+ serializedValidatorsSize(): number {
607
+ if (this._serializedValidatorsSize === null) {
608
+ this._serializedValidatorsSize = this.binding.serializedValidatorsSize();
609
+ }
610
+ return this._serializedValidatorsSize;
611
+ }
612
+
613
+ serializeValidatorsToBytes(output: ByteViews, offset: number): number {
614
+ return this.binding.serializeValidatorsToBytes(output, offset);
615
+ }
616
+
617
+ hashTreeRoot(): Uint8Array {
618
+ if (this._hashTreeRoot === null) {
619
+ this._hashTreeRoot = this.binding.hashTreeRoot();
620
+ }
621
+ return this._hashTreeRoot;
622
+ }
623
+
624
+ // State transition
625
+
626
+ stateTransition(
627
+ signedBlock: SignedBeaconBlock | SignedBlindedBeaconBlock,
628
+ options: StateTransitionOpts,
629
+ modules: StateTransitionModules
630
+ ): IBeaconStateView {
631
+ return new NativeBeaconStateView(this.binding.stateTransition(signedBlock, options, modules));
632
+ }
633
+
634
+ processSlots(
635
+ slot: Slot,
636
+ epochTransitionCacheOpts?: EpochTransitionCacheOpts & {dontTransferCache?: boolean},
637
+ modules?: StateTransitionModules
638
+ ): IBeaconStateView {
639
+ return new NativeBeaconStateView(this.binding.processSlots(slot, epochTransitionCacheOpts, modules));
640
+ }
641
+
642
+ // ─── altair ──────────────────────────────────────────────────────────────
643
+
644
+ get previousEpochParticipation(): Uint8Array {
645
+ if (this._previousEpochParticipation === null) {
646
+ this._previousEpochParticipation = this.binding.previousEpochParticipation;
647
+ }
648
+ return this._previousEpochParticipation;
649
+ }
650
+
651
+ get currentEpochParticipation(): Uint8Array {
652
+ if (this._currentEpochParticipation === null) {
653
+ this._currentEpochParticipation = this.binding.currentEpochParticipation;
654
+ }
655
+ return this._currentEpochParticipation;
656
+ }
657
+
658
+ getPreviousEpochParticipation(validatorIndex: ValidatorIndex): number {
659
+ return this.previousEpochParticipation[validatorIndex];
660
+ }
661
+
662
+ getCurrentEpochParticipation(validatorIndex: ValidatorIndex): number {
663
+ return this.currentEpochParticipation[validatorIndex];
664
+ }
665
+
666
+ get currentSyncCommittee(): altair.SyncCommittee {
667
+ if (this._currentSyncCommittee === null) {
668
+ this._currentSyncCommittee = this.binding.currentSyncCommittee;
669
+ }
670
+ return this._currentSyncCommittee;
671
+ }
672
+
673
+ get nextSyncCommittee(): altair.SyncCommittee {
674
+ if (this._nextSyncCommittee === null) {
675
+ this._nextSyncCommittee = this.binding.nextSyncCommittee;
676
+ }
677
+ return this._nextSyncCommittee;
678
+ }
679
+
680
+ get currentSyncCommitteeIndexed(): SyncCommitteeCache {
681
+ if (this._currentSyncCommitteeIndexed === null) {
682
+ this._currentSyncCommitteeIndexed = this.binding.currentSyncCommitteeIndexed;
683
+ }
684
+ return this._currentSyncCommitteeIndexed;
685
+ }
686
+
687
+ get syncProposerReward(): number {
688
+ if (this._syncProposerReward === null) {
689
+ this._syncProposerReward = this.binding.syncProposerReward;
690
+ }
691
+ return this._syncProposerReward;
692
+ }
693
+
694
+ getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache {
695
+ let cached = this._getIndexedSyncCommitteeAtEpoch.get(epoch);
696
+ if (cached === undefined) {
697
+ cached = this.binding.getIndexedSyncCommitteeAtEpoch(epoch);
698
+ this._getIndexedSyncCommitteeAtEpoch.set(epoch, cached);
699
+ }
700
+ return cached;
701
+ }
702
+
703
+ getIndexedSyncCommittee(slot: Slot): SyncCommitteeCache {
704
+ let cached = this._getIndexedSyncCommittee.get(slot);
705
+ if (cached === undefined) {
706
+ cached = this.binding.getIndexedSyncCommittee(slot);
707
+ this._getIndexedSyncCommittee.set(slot, cached);
708
+ }
709
+ return cached;
710
+ }
711
+
712
+ computeSyncCommitteeRewards(
713
+ block: BeaconBlock,
714
+ validatorIds: (ValidatorIndex | string)[]
715
+ ): Promise<rewards.SyncCommitteeRewards> {
716
+ return this.binding.computeSyncCommitteeRewards(block, validatorIds);
717
+ }
718
+
719
+ getSyncCommitteesWitness(): SyncCommitteeWitness {
720
+ if (this._getSyncCommitteesWitness === null) {
721
+ this._getSyncCommitteesWitness = this.binding.getSyncCommitteesWitness();
722
+ }
723
+ return this._getSyncCommitteesWitness;
724
+ }
725
+
726
+ // ─── bellatrix ───────────────────────────────────────────────────────────
727
+
728
+ get latestExecutionPayloadHeader(): ExecutionPayloadHeader {
729
+ if (this._latestExecutionPayloadHeader === null) {
730
+ this._latestExecutionPayloadHeader = this.binding.latestExecutionPayloadHeader;
731
+ }
732
+ return this._latestExecutionPayloadHeader;
733
+ }
734
+
735
+ get payloadBlockNumber(): number {
736
+ if (this._payloadBlockNumber === null) {
737
+ this._payloadBlockNumber = this.binding.payloadBlockNumber;
738
+ }
739
+ return this._payloadBlockNumber;
740
+ }
741
+
742
+ get isExecutionStateType(): boolean {
743
+ if (this._isExecutionStateType === null) {
744
+ this._isExecutionStateType = this.binding.isExecutionStateType;
745
+ }
746
+ return this._isExecutionStateType;
747
+ }
748
+
749
+ get isMergeTransitionComplete(): boolean {
750
+ if (this._isMergeTransitionComplete === null) {
751
+ this._isMergeTransitionComplete = this.binding.isMergeTransitionComplete;
752
+ }
753
+ return this._isMergeTransitionComplete;
754
+ }
755
+
756
+ isExecutionEnabled(block: BeaconBlock | BlindedBeaconBlock): boolean {
757
+ return this.binding.isExecutionEnabled(block);
758
+ }
759
+
760
+ // ─── capella ─────────────────────────────────────────────────────────────
761
+
762
+ get historicalSummaries(): capella.HistoricalSummaries {
763
+ if (this._historicalSummaries === null) {
764
+ this._historicalSummaries = this.binding.historicalSummaries;
765
+ }
766
+ return this._historicalSummaries;
767
+ }
768
+
769
+ getExpectedWithdrawals(): {
770
+ expectedWithdrawals: capella.Withdrawal[];
771
+ processedBuilderWithdrawalsCount: number;
772
+ processedPartialWithdrawalsCount: number;
773
+ processedBuildersSweepCount: number;
774
+ processedValidatorSweepCount: number;
775
+ } {
776
+ if (this._getExpectedWithdrawals === null) {
777
+ this._getExpectedWithdrawals = this.binding.getExpectedWithdrawals();
778
+ }
779
+ return this._getExpectedWithdrawals;
780
+ }
781
+
782
+ // ─── electra ─────────────────────────────────────────────────────────────
783
+
784
+ get pendingDeposits(): electra.PendingDeposits {
785
+ if (this._pendingDeposits === null) {
786
+ this._pendingDeposits = this.binding.pendingDeposits;
787
+ }
788
+ return this._pendingDeposits;
789
+ }
790
+
791
+ get pendingDepositsCount(): number {
792
+ if (this._pendingDepositsCount === null) {
793
+ this._pendingDepositsCount = this.binding.pendingDepositsCount;
794
+ }
795
+ return this._pendingDepositsCount;
796
+ }
797
+
798
+ get pendingPartialWithdrawals(): electra.PendingPartialWithdrawals {
799
+ if (this._pendingPartialWithdrawals === null) {
800
+ this._pendingPartialWithdrawals = this.binding.pendingPartialWithdrawals;
801
+ }
802
+ return this._pendingPartialWithdrawals;
803
+ }
804
+
805
+ get pendingPartialWithdrawalsCount(): number {
806
+ if (this._pendingPartialWithdrawalsCount === null) {
807
+ this._pendingPartialWithdrawalsCount = this.binding.pendingPartialWithdrawalsCount;
808
+ }
809
+ return this._pendingPartialWithdrawalsCount;
810
+ }
811
+
812
+ get pendingConsolidations(): electra.PendingConsolidations {
813
+ if (this._pendingConsolidations === null) {
814
+ this._pendingConsolidations = this.binding.pendingConsolidations;
815
+ }
816
+ return this._pendingConsolidations;
817
+ }
818
+
819
+ get pendingConsolidationsCount(): number {
820
+ if (this._pendingConsolidationsCount === null) {
821
+ this._pendingConsolidationsCount = this.binding.pendingConsolidationsCount;
822
+ }
823
+ return this._pendingConsolidationsCount;
824
+ }
825
+
826
+ // ─── fulu ────────────────────────────────────────────────────────────────
827
+
828
+ get proposerLookahead(): fulu.ProposerLookahead {
829
+ if (this._proposerLookahead === null) {
830
+ this._proposerLookahead = this.binding.proposerLookahead;
831
+ }
832
+ return this._proposerLookahead;
833
+ }
834
+
835
+ // ─── gloas ───────────────────────────────────────────────────────────────
836
+
837
+ get latestBlockHash(): Bytes32 {
838
+ if (this._latestBlockHash === null) {
839
+ this._latestBlockHash = this.binding.latestBlockHash;
840
+ }
841
+ return this._latestBlockHash;
842
+ }
843
+
844
+ // executionPayloadAvailability getter is defined near the top of the class.
845
+
846
+ get latestExecutionPayloadBid(): ExecutionPayloadBid {
847
+ if (this._latestExecutionPayloadBid === null) {
848
+ this._latestExecutionPayloadBid = this.binding.latestExecutionPayloadBid;
849
+ }
850
+ return this._latestExecutionPayloadBid;
851
+ }
852
+
853
+ get payloadExpectedWithdrawals(): capella.Withdrawal[] {
854
+ if (this._payloadExpectedWithdrawals === null) {
855
+ this._payloadExpectedWithdrawals = this.binding.payloadExpectedWithdrawals;
856
+ }
857
+ return this._payloadExpectedWithdrawals;
858
+ }
859
+
860
+ getBuilder(index: BuilderIndex): gloas.Builder {
861
+ let cached = this._getBuilder.get(index);
862
+ if (cached === undefined) {
863
+ cached = this.binding.getBuilder(index);
864
+ this._getBuilder.set(index, cached);
865
+ }
866
+ return cached;
867
+ }
868
+
869
+ canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean {
870
+ return this.binding.canBuilderCoverBid(builderIndex, bidAmount);
871
+ }
872
+
873
+ getEpochPTCs(epoch: Epoch): Uint32Array[] {
874
+ let cached = this._getEpochPTCs.get(epoch);
875
+ if (cached === undefined) {
876
+ cached = this.binding.getEpochPTCs(epoch);
877
+ this._getEpochPTCs.set(epoch, cached);
878
+ }
879
+ return cached;
880
+ }
881
+
882
+ getIndicesInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number[] {
883
+ return this.binding.getIndicesInPayloadTimelinessCommittee(validatorIndex, slot);
884
+ }
885
+
886
+ withParentPayloadApplied(executionRequests: electra.ExecutionRequests): IBeaconStateViewGloas {
887
+ const view = new NativeBeaconStateView(this.binding.withParentPayloadApplied(executionRequests));
888
+ if (!isStatePostGloas(view)) {
889
+ throw new Error("Expected gloas state from withParentPayloadApplied");
890
+ }
891
+ return view;
892
+ }
893
+ }