@lodestar/state-transition 1.42.0-dev.1d50253953 → 1.42.0-dev.1e596a7422

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.
Files changed (81) hide show
  1. package/lib/block/isValidIndexedAttestation.d.ts.map +1 -1
  2. package/lib/block/isValidIndexedAttestation.js +2 -3
  3. package/lib/block/isValidIndexedAttestation.js.map +1 -1
  4. package/lib/block/processAttestationsAltair.d.ts +2 -1
  5. package/lib/block/processAttestationsAltair.d.ts.map +1 -1
  6. package/lib/block/processAttestationsAltair.js +5 -3
  7. package/lib/block/processAttestationsAltair.js.map +1 -1
  8. package/lib/index.d.ts +4 -2
  9. package/lib/index.d.ts.map +1 -1
  10. package/lib/index.js +4 -1
  11. package/lib/index.js.map +1 -1
  12. package/lib/signatureSets/executionPayloadEnvelope.d.ts.map +1 -1
  13. package/lib/signatureSets/executionPayloadEnvelope.js +4 -0
  14. package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
  15. package/lib/signatureSets/index.d.ts +2 -2
  16. package/lib/signatureSets/index.d.ts.map +1 -1
  17. package/lib/signatureSets/index.js +1 -2
  18. package/lib/signatureSets/index.js.map +1 -1
  19. package/lib/signatureSets/voluntaryExits.d.ts +2 -2
  20. package/lib/signatureSets/voluntaryExits.d.ts.map +1 -1
  21. package/lib/signatureSets/voluntaryExits.js +4 -0
  22. package/lib/signatureSets/voluntaryExits.js.map +1 -1
  23. package/lib/slot/upgradeStateToAltair.d.ts.map +1 -1
  24. package/lib/slot/upgradeStateToAltair.js +2 -1
  25. package/lib/slot/upgradeStateToAltair.js.map +1 -1
  26. package/lib/stateTransition.d.ts +1 -1
  27. package/lib/stateTransition.d.ts.map +1 -1
  28. package/lib/stateTransition.js +1 -1
  29. package/lib/stateTransition.js.map +1 -1
  30. package/lib/stateView/beaconStateView.d.ts +12 -11
  31. package/lib/stateView/beaconStateView.d.ts.map +1 -1
  32. package/lib/stateView/beaconStateView.js +26 -37
  33. package/lib/stateView/beaconStateView.js.map +1 -1
  34. package/lib/stateView/index.d.ts +1 -0
  35. package/lib/stateView/index.d.ts.map +1 -1
  36. package/lib/stateView/index.js +1 -0
  37. package/lib/stateView/index.js.map +1 -1
  38. package/lib/stateView/interface.d.ts +105 -54
  39. package/lib/stateView/interface.d.ts.map +1 -1
  40. package/lib/stateView/interface.js +22 -1
  41. package/lib/stateView/interface.js.map +1 -1
  42. package/lib/stateView/stateViewFactory.d.ts +40 -0
  43. package/lib/stateView/stateViewFactory.d.ts.map +1 -0
  44. package/lib/stateView/stateViewFactory.js +46 -0
  45. package/lib/stateView/stateViewFactory.js.map +1 -0
  46. package/lib/testUtils/cache.d.ts.map +1 -1
  47. package/lib/testUtils/cache.js +1 -1
  48. package/lib/testUtils/cache.js.map +1 -1
  49. package/lib/testUtils/util.d.ts +13 -1
  50. package/lib/testUtils/util.d.ts.map +1 -1
  51. package/lib/testUtils/util.js +119 -19
  52. package/lib/testUtils/util.js.map +1 -1
  53. package/lib/util/gloas.d.ts +2 -1
  54. package/lib/util/gloas.d.ts.map +1 -1
  55. package/lib/util/gloas.js.map +1 -1
  56. package/lib/util/rootCache.d.ts +2 -2
  57. package/lib/util/rootCache.d.ts.map +1 -1
  58. package/lib/util/rootCache.js +2 -3
  59. package/lib/util/rootCache.js.map +1 -1
  60. package/lib/util/shuffling.d.ts +2 -1
  61. package/lib/util/shuffling.d.ts.map +1 -1
  62. package/lib/util/shuffling.js +2 -2
  63. package/lib/util/shuffling.js.map +1 -1
  64. package/package.json +7 -7
  65. package/src/block/isValidIndexedAttestation.ts +2 -3
  66. package/src/block/processAttestationsAltair.ts +7 -4
  67. package/src/index.ts +20 -2
  68. package/src/signatureSets/executionPayloadEnvelope.ts +5 -1
  69. package/src/signatureSets/index.ts +3 -4
  70. package/src/signatureSets/voluntaryExits.ts +5 -2
  71. package/src/slot/upgradeStateToAltair.ts +2 -1
  72. package/src/stateTransition.ts +1 -1
  73. package/src/stateView/beaconStateView.ts +42 -56
  74. package/src/stateView/index.ts +1 -0
  75. package/src/stateView/interface.ts +148 -73
  76. package/src/stateView/stateViewFactory.ts +78 -0
  77. package/src/testUtils/cache.ts +1 -1
  78. package/src/testUtils/util.ts +136 -22
  79. package/src/util/gloas.ts +2 -1
  80. package/src/util/rootCache.ts +4 -5
  81. package/src/util/shuffling.ts +5 -4
package/src/index.ts CHANGED
@@ -35,14 +35,32 @@ export {
35
35
  isStateValidatorsNodesPopulated,
36
36
  loadCachedBeaconState,
37
37
  } from "./cache/stateCache.js";
38
- export {type SyncCommitteeCache} from "./cache/syncCommitteeCache.js";
38
+ export {type SyncCommitteeCache, SyncCommitteeCacheEmpty} from "./cache/syncCommitteeCache.js";
39
39
  export * from "./constants/index.js";
40
40
  export type {EpochTransitionStep} from "./epoch/index.js";
41
41
  export {type BeaconStateTransitionMetrics, getMetrics} from "./metrics.js";
42
42
  export * from "./rewards/index.js";
43
43
  export * from "./signatureSets/index.js";
44
44
  export * from "./stateTransition.js";
45
- export * from "./stateView/index.js";
45
+ export {BeaconStateView} from "./stateView/beaconStateView.js";
46
+ export {
47
+ type IBeaconStateView,
48
+ type IBeaconStateViewAltair,
49
+ type IBeaconStateViewBellatrix,
50
+ type IBeaconStateViewCapella,
51
+ type IBeaconStateViewDeneb,
52
+ type IBeaconStateViewElectra,
53
+ type IBeaconStateViewFulu,
54
+ type IBeaconStateViewGloas,
55
+ isStatePostAltair,
56
+ isStatePostBellatrix,
57
+ isStatePostCapella,
58
+ isStatePostDeneb,
59
+ isStatePostElectra,
60
+ isStatePostFulu,
61
+ isStatePostGloas,
62
+ } from "./stateView/interface.js";
63
+ export {createBeaconStateView, createBeaconStateViewForHistoricalRegen} from "./stateView/stateViewFactory.js";
46
64
  export type {
47
65
  BeaconStateAllForks,
48
66
  BeaconStateAltair,
@@ -3,7 +3,7 @@ import {BeaconConfig} from "@lodestar/config";
3
3
  import {BUILDER_INDEX_SELF_BUILD, DOMAIN_BEACON_BUILDER} from "@lodestar/params";
4
4
  import {ValidatorIndex, gloas, ssz} from "@lodestar/types";
5
5
  import {PubkeyCache} from "../cache/pubkeyCache.js";
6
- import {IBeaconStateView} from "../stateView/interface.js";
6
+ import {IBeaconStateView, isStatePostGloas} from "../stateView/interface.js";
7
7
  import {computeSigningRoot} from "../util/index.js";
8
8
  import {type SingleSignatureSet, createSingleSignatureSetFromComponents} from "../util/signatureSets.js";
9
9
 
@@ -23,6 +23,10 @@ export function getExecutionPayloadEnvelopeSignatureSet(
23
23
  signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
24
24
  proposerIndex: ValidatorIndex
25
25
  ): SingleSignatureSet {
26
+ if (!isStatePostGloas(state)) {
27
+ throw new Error(`Expected gloas+ state for execution payload envelope signature, got fork=${state.forkName}`);
28
+ }
29
+
26
30
  const envelope = signedEnvelope.message;
27
31
  const pubkey =
28
32
  envelope.builderIndex === BUILDER_INDEX_SELF_BUILD
@@ -3,8 +3,7 @@ import {ForkSeq} from "@lodestar/params";
3
3
  import {IndexedAttestation, SignedBeaconBlock, altair, capella} from "@lodestar/types";
4
4
  import {getSyncCommitteeSignatureSet} from "../block/processSyncCommittee.js";
5
5
  import {SyncCommitteeCache} from "../cache/syncCommitteeCache.js";
6
- import {BeaconStateView} from "../stateView/beaconStateView.js";
7
- import {CachedBeaconStateAllForks} from "../types.js";
6
+ import {IBeaconStateView} from "../stateView/interface.js";
8
7
  import {ISignatureSet} from "../util/index.js";
9
8
  import {getAttesterSlashingsSignatureSets} from "./attesterSlashings.js";
10
9
  import {getBlsToExecutionChangeSignatureSets} from "./blsToExecutionChange.js";
@@ -32,7 +31,7 @@ export * from "./voluntaryExits.js";
32
31
  export function getBlockSignatureSets(
33
32
  config: BeaconConfig,
34
33
  currentSyncCommitteeIndexed: SyncCommitteeCache,
35
- state: CachedBeaconStateAllForks,
34
+ state: IBeaconStateView,
36
35
  signedBlock: SignedBeaconBlock,
37
36
  indexedAttestations: IndexedAttestation[],
38
37
  opts?: {
@@ -48,7 +47,7 @@ export function getBlockSignatureSets(
48
47
  ...getProposerSlashingsSignatureSets(config, signedBlock),
49
48
  ...getAttesterSlashingsSignatureSets(config, signedBlock),
50
49
  ...getAttestationsSignatureSets(config, signedBlock, indexedAttestations),
51
- ...getVoluntaryExitsSignatureSets(config, new BeaconStateView(state), signedBlock),
50
+ ...getVoluntaryExitsSignatureSets(config, state, signedBlock),
52
51
  ];
53
52
 
54
53
  if (!opts?.skipProposerSignature) {
@@ -3,7 +3,7 @@ import {BeaconConfig} from "@lodestar/config";
3
3
  import {ForkSeq} from "@lodestar/params";
4
4
  import {SignedBeaconBlock, Slot, phase0, ssz} from "@lodestar/types";
5
5
  import {PubkeyCache} from "../cache/pubkeyCache.js";
6
- import {IBeaconStateView} from "../stateView/interface.js";
6
+ import {IBeaconStateView, IBeaconStateViewGloas, isStatePostGloas} from "../stateView/interface.js";
7
7
  import {
8
8
  ISignatureSet,
9
9
  SignatureSetType,
@@ -34,6 +34,9 @@ export function getVoluntaryExitSignatureSet(
34
34
  const fork = config.getForkSeq(state.slot);
35
35
 
36
36
  if (fork >= ForkSeq.gloas && isBuilderVoluntaryExit(signedVoluntaryExit)) {
37
+ if (!isStatePostGloas(state)) {
38
+ throw new Error(`Expected gloas+ state for builder voluntary exit signature, got fork=${state.forkName}`);
39
+ }
37
40
  return getBuilderVoluntaryExitSignatureSet(config, state, signedVoluntaryExit);
38
41
  }
39
42
 
@@ -68,7 +71,7 @@ export function getValidatorVoluntaryExitSignatureSet(
68
71
 
69
72
  export function getBuilderVoluntaryExitSignatureSet(
70
73
  config: BeaconConfig,
71
- state: IBeaconStateView,
74
+ state: IBeaconStateViewGloas,
72
75
  signedVoluntaryExit: phase0.SignedVoluntaryExit
73
76
  ): ISignatureSet {
74
77
  const messageSlot = computeStartSlotAtEpoch(signedVoluntaryExit.message.epoch);
@@ -3,6 +3,7 @@ import {ForkSeq} from "@lodestar/params";
3
3
  import {ssz} from "@lodestar/types";
4
4
  import {getAttestationParticipationStatus} from "../block/processAttestationsAltair.js";
5
5
  import {getCachedBeaconState} from "../cache/stateCache.js";
6
+ import {BeaconStateView} from "../stateView/beaconStateView.js";
6
7
  import {CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../types.js";
7
8
  import {RootCache, newZeroedArray} from "../util/index.js";
8
9
  import {getNextSyncCommittee} from "../util/syncCommittee.js";
@@ -125,7 +126,7 @@ function translateParticipation(
125
126
  pendingAttesations: CompositeViewDU<typeof ssz.phase0.EpochAttestations>
126
127
  ): void {
127
128
  const {epochCtx} = state;
128
- const rootCache = new RootCache(state);
129
+ const rootCache = new RootCache(new BeaconStateView(state));
129
130
  const epochParticipation = state.previousEpochParticipation;
130
131
 
131
132
  for (const attestation of pendingAttesations.getAllReadonly()) {
@@ -76,7 +76,7 @@ export enum StateHashTreeRootSource {
76
76
  prepareNextEpoch = "prepare_next_epoch",
77
77
  regenState = "regen_state",
78
78
  computeNewStateRoot = "compute_new_state_root",
79
- computeEnvelopeStateRoot = "compute_envelope_state_root",
79
+ computePayloadEnvelopeStateRoot = "compute_payload_envelope_state_root",
80
80
  }
81
81
 
82
82
  /**
@@ -1,9 +1,10 @@
1
1
  import {CompactMultiProof, ProofType, Tree, createProof} from "@chainsafe/persistent-merkle-tree";
2
- import {ByteViews} from "@chainsafe/ssz";
2
+ import {BitArray, ByteViews} from "@chainsafe/ssz";
3
3
  import {BeaconConfig} from "@lodestar/config";
4
- import {ForkSeq, SLOTS_PER_HISTORICAL_ROOT, isForkPostGloas} from "@lodestar/params";
4
+ import {ForkName, ForkSeq, SLOTS_PER_HISTORICAL_ROOT, isForkPostGloas} from "@lodestar/params";
5
5
  import {
6
6
  BeaconBlock,
7
+ BeaconState,
7
8
  BlindedBeaconBlock,
8
9
  BuilderIndex,
9
10
  Bytes32,
@@ -33,7 +34,6 @@ import {VoluntaryExitValidity, getVoluntaryExitValidity} from "../block/processV
33
34
  import {getExpectedWithdrawals} from "../block/processWithdrawals.js";
34
35
  import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
35
36
  import {EpochTransitionCacheOpts} from "../cache/epochTransitionCache.js";
36
- import {PubkeyCache, createPubkeyCache} from "../cache/pubkeyCache.js";
37
37
  import {RewardCache} from "../cache/rewardCache.js";
38
38
  import {
39
39
  CachedBeaconStateAllForks,
@@ -47,7 +47,6 @@ import {
47
47
  isStateValidatorsNodesPopulated,
48
48
  } from "../cache/stateCache.js";
49
49
  import {SyncCommitteeCache} from "../cache/syncCommitteeCache.js";
50
- import {BeaconStateAllForks} from "../cache/types.js";
51
50
  import {computeUnrealizedCheckpoints} from "../epoch/computeUnrealizedCheckpoints.js";
52
51
  import {getFinalizedRootProof, getSyncCommitteesWitness} from "../lightClient/proofs.js";
53
52
  import {SyncCommitteeWitness} from "../lightClient/types.js";
@@ -64,11 +63,10 @@ import {isExecutionEnabled, isExecutionStateType, isMergeTransitionComplete} fro
64
63
  import {canBuilderCoverBid} from "../util/gloas.js";
65
64
  import {loadState} from "../util/loadState/loadState.js";
66
65
  import {getRandaoMix} from "../util/seed.js";
67
- import {getStateTypeFromBytes} from "../util/sszBytes.js";
68
66
  import {getLatestWeakSubjectivityCheckpointEpoch} from "../util/weakSubjectivity.js";
69
- import {IBeaconStateView} from "./interface.js";
67
+ import {IBeaconStateView, IBeaconStateViewLatestFork} from "./interface.js";
70
68
 
71
- export class BeaconStateView implements IBeaconStateView {
69
+ export class BeaconStateView implements IBeaconStateViewLatestFork {
72
70
  private readonly config: BeaconConfig;
73
71
  // Cached values extracted from the tree
74
72
  // phase0
@@ -92,8 +90,9 @@ export class BeaconStateView implements IBeaconStateView {
92
90
  // fulu
93
91
  private _proposerLookahead: fulu.ProposerLookahead | null = null;
94
92
  // gloas
95
- private _executionPayloadAvailability: boolean[] | null = null;
93
+ private _executionPayloadAvailability: BitArray | null = null;
96
94
  private _latestExecutionPayloadBid: ExecutionPayloadBid | null = null;
95
+ private _payloadExpectedWithdrawals: capella.Withdrawal[] | null = null;
97
96
 
98
97
  constructor(readonly cachedState: CachedBeaconStateAllForks) {
99
98
  this.config = cachedState.config;
@@ -101,6 +100,10 @@ export class BeaconStateView implements IBeaconStateView {
101
100
 
102
101
  // phase0
103
102
 
103
+ get forkName(): ForkName {
104
+ return this.config.getForkName(this.cachedState.slot);
105
+ }
106
+
104
107
  get slot(): number {
105
108
  return this.cachedState.slot;
106
109
  }
@@ -357,15 +360,15 @@ export class BeaconStateView implements IBeaconStateView {
357
360
 
358
361
  // gloas
359
362
 
360
- get executionPayloadAvailability(): boolean[] {
363
+ get executionPayloadAvailability(): BitArray {
361
364
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
362
- throw new Error("executionPayloadAvailability is not available before GLOAS");
365
+ throw new Error("executionPayloadAvailability is not available before Gloas");
363
366
  }
364
367
 
365
368
  if (this._executionPayloadAvailability === null) {
366
- this._executionPayloadAvailability = (this.cachedState as CachedBeaconStateGloas).executionPayloadAvailability
367
- .toValue()
368
- .toBoolArray();
369
+ this._executionPayloadAvailability = (
370
+ this.cachedState as CachedBeaconStateGloas
371
+ ).executionPayloadAvailability.toValue();
369
372
  }
370
373
 
371
374
  return this._executionPayloadAvailability;
@@ -373,7 +376,7 @@ export class BeaconStateView implements IBeaconStateView {
373
376
 
374
377
  get latestExecutionPayloadBid(): ExecutionPayloadBid {
375
378
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
376
- throw new Error("latestExecutionPayloadBid is not available before GLOAS");
379
+ throw new Error("latestExecutionPayloadBid is not available before Gloas");
377
380
  }
378
381
 
379
382
  if (this._latestExecutionPayloadBid === null) {
@@ -384,9 +387,22 @@ export class BeaconStateView implements IBeaconStateView {
384
387
  return this._latestExecutionPayloadBid;
385
388
  }
386
389
 
390
+ get payloadExpectedWithdrawals(): capella.Withdrawal[] {
391
+ if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
392
+ throw new Error("payloadExpectedWithdrawals is not available before Gloas");
393
+ }
394
+
395
+ if (this._payloadExpectedWithdrawals === null) {
396
+ this._payloadExpectedWithdrawals = (
397
+ this.cachedState as CachedBeaconStateGloas
398
+ ).payloadExpectedWithdrawals.toValue();
399
+ }
400
+ return this._payloadExpectedWithdrawals;
401
+ }
402
+
387
403
  getBuilder(index: BuilderIndex): gloas.Builder {
388
404
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
389
- throw new Error("Builders are not supported before GLOAS");
405
+ throw new Error("Builders are not supported before Gloas");
390
406
  }
391
407
 
392
408
  return (this.cachedState as CachedBeaconStateGloas).builders.getReadonly(index);
@@ -394,7 +410,7 @@ export class BeaconStateView implements IBeaconStateView {
394
410
 
395
411
  canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean {
396
412
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
397
- throw new Error("Builders are not supported before GLOAS");
413
+ throw new Error("Builders are not supported before Gloas");
398
414
  }
399
415
 
400
416
  return canBuilderCoverBid(this.cachedState as CachedBeaconStateGloas, builderIndex, bidAmount);
@@ -404,9 +420,9 @@ export class BeaconStateView implements IBeaconStateView {
404
420
  * Return the index of the validator in the PTC committee for the given slot.
405
421
  * return -1 if validator is not in the PTC committee for the given slot.
406
422
  */
407
- validatorPTCCommitteeIndex(validatorIndex: ValidatorIndex, slot: Slot): number {
423
+ getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number {
408
424
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
409
- throw new Error("PTC committees are not supported before GLOAS");
425
+ throw new Error("PTC committees are not supported before Gloas");
410
426
  }
411
427
 
412
428
  const ptcCommittee = (this.cachedState as CachedBeaconStateGloas).epochCtx.getPayloadTimelinessCommittee(slot);
@@ -503,6 +519,10 @@ export class BeaconStateView implements IBeaconStateView {
503
519
  return this.cachedState.epochCtx.syncProposerReward;
504
520
  }
505
521
 
522
+ getIndexedSyncCommittee(slot: Slot): SyncCommitteeCache {
523
+ return this.cachedState.epochCtx.getIndexedSyncCommittee(slot);
524
+ }
525
+
506
526
  getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache {
507
527
  return this.cachedState.epochCtx.getIndexedSyncCommitteeAtEpoch(epoch);
508
528
  }
@@ -713,6 +733,10 @@ export class BeaconStateView implements IBeaconStateView {
713
733
  return new BeaconStateView(cachedState);
714
734
  }
715
735
 
736
+ toValue(): BeaconState {
737
+ return this.cachedState.toValue();
738
+ }
739
+
716
740
  serialize(): Uint8Array {
717
741
  return this.cachedState.serialize();
718
742
  }
@@ -778,41 +802,3 @@ export class BeaconStateView implements IBeaconStateView {
778
802
  return new BeaconStateView(postPayloadState);
779
803
  }
780
804
  }
781
-
782
- /**
783
- * Create BeaconStateView for historical state regen, no need to sync pubkey cache there.
784
- */
785
- export function createBeaconStateViewForHistoricalRegen(
786
- config: BeaconConfig,
787
- stateBytes: Uint8Array
788
- ): IBeaconStateView {
789
- const state = getStateTypeFromBytes(config, stateBytes).deserializeToViewDU(stateBytes);
790
-
791
- const pubkeyCache = createPubkeyCache();
792
- syncPubkeyCache(state, pubkeyCache);
793
- const cachedState = createCachedBeaconState(
794
- state,
795
- {
796
- config,
797
- pubkeyCache,
798
- },
799
- {
800
- skipSyncPubkeys: true,
801
- }
802
- );
803
-
804
- return new BeaconStateView(cachedState);
805
- }
806
-
807
- /**
808
- * Populate a PubkeyIndexMap with any new entries based on a BeaconState
809
- */
810
- function syncPubkeyCache(state: BeaconStateAllForks, pubkeyCache: PubkeyCache): void {
811
- // Get the validators sub tree once for all the loop
812
-
813
- const newCount = state.validators.length;
814
- for (let i = pubkeyCache.size; i < newCount; i++) {
815
- const pubkey = state.validators.getReadonly(i).pubkey;
816
- pubkeyCache.set(i, pubkey);
817
- }
818
- }
@@ -1,2 +1,3 @@
1
1
  export * from "./beaconStateView.js";
2
2
  export * from "./interface.js";
3
+ export * from "./stateViewFactory.js";
@@ -1,7 +1,25 @@
1
1
  import {CompactMultiProof} from "@chainsafe/persistent-merkle-tree";
2
- import {ByteViews} from "@chainsafe/ssz";
2
+ import {BitArray, ByteViews} from "@chainsafe/ssz";
3
+ import {
4
+ ForkName,
5
+ ForkPostAltair,
6
+ ForkPostBellatrix,
7
+ ForkPostCapella,
8
+ ForkPostDeneb,
9
+ ForkPostElectra,
10
+ ForkPostFulu,
11
+ ForkPostGloas,
12
+ isForkPostAltair,
13
+ isForkPostBellatrix,
14
+ isForkPostCapella,
15
+ isForkPostDeneb,
16
+ isForkPostElectra,
17
+ isForkPostFulu,
18
+ isForkPostGloas,
19
+ } from "@lodestar/params";
3
20
  import {
4
21
  BeaconBlock,
22
+ BeaconState,
5
23
  BlindedBeaconBlock,
6
24
  BuilderIndex,
7
25
  Bytes32,
@@ -40,6 +58,7 @@ export interface IBeaconStateView {
40
58
  // State access
41
59
 
42
60
  // phase0
61
+ forkName: ForkName;
43
62
  slot: Slot;
44
63
  fork: Fork;
45
64
  epoch: Epoch;
@@ -55,50 +74,6 @@ export interface IBeaconStateView {
55
74
  getStateRootAtSlot(slot: Slot): Root;
56
75
  getRandaoMix(epoch: Epoch): Bytes32;
57
76
 
58
- // altair
59
- previousEpochParticipation: Uint8Array;
60
- currentEpochParticipation: Uint8Array;
61
- getPreviousEpochParticipation(validatorIndex: ValidatorIndex): number;
62
- getCurrentEpochParticipation(validatorIndex: ValidatorIndex): number;
63
-
64
- // bellatrix
65
- latestExecutionPayloadHeader: ExecutionPayloadHeader;
66
- /**
67
- * Cross-fork accessor for the execution block hash of the most recently included payload.
68
- * Pre-gloas: returns latestExecutionPayloadHeader.blockHash (bellatrix–fulu).
69
- * Gloas+: returns the dedicated latestBlockHash state field (EIP-7732).
70
- * Throws before bellatrix.
71
- */
72
- latestBlockHash: Bytes32;
73
- /**
74
- * The execution block number of the most recently included payload.
75
- * Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
76
- * Only available from bellatrix through fulu — not tracked on BeaconState in gloas+ (EIP-7732).
77
- * Throws before bellatrix and from gloas onwards.
78
- */
79
- payloadBlockNumber: number;
80
-
81
- // capella
82
- historicalSummaries: capella.HistoricalSummaries;
83
-
84
- // electra
85
- pendingDeposits: electra.PendingDeposits;
86
- pendingDepositsCount: number;
87
- pendingPartialWithdrawals: electra.PendingPartialWithdrawals;
88
- pendingPartialWithdrawalsCount: number;
89
- pendingConsolidations: electra.PendingConsolidations;
90
- pendingConsolidationsCount: number;
91
-
92
- // fulu
93
- proposerLookahead: fulu.ProposerLookahead;
94
-
95
- // gloas
96
- executionPayloadAvailability: boolean[];
97
- latestExecutionPayloadBid: ExecutionPayloadBid;
98
- getBuilder(index: BuilderIndex): gloas.Builder;
99
- canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean;
100
- validatorPTCCommitteeIndex(validatorIndex: ValidatorIndex, slot: Slot): number;
101
-
102
77
  // Shuffling and committees
103
78
  getShufflingAtEpoch(epoch: Epoch): EpochShuffling;
104
79
  // Decision roots
@@ -110,19 +85,11 @@ export interface IBeaconStateView {
110
85
  getCurrentShuffling(): EpochShuffling;
111
86
  getNextShuffling(): EpochShuffling;
112
87
 
113
- // utils: proposers, anchor checkpoint
88
+ // Proposer shuffling
114
89
  previousProposers: ValidatorIndex[] | null;
115
90
  currentProposers: ValidatorIndex[];
116
91
  nextProposers: ValidatorIndex[];
117
92
  getBeaconProposer(slot: Slot): ValidatorIndex;
118
- computeAnchorCheckpoint(): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader};
119
-
120
- // Sync committees
121
- currentSyncCommittee: altair.SyncCommittee;
122
- nextSyncCommittee: altair.SyncCommittee;
123
- currentSyncCommitteeIndexed: SyncCommitteeCache;
124
- syncProposerReward: number;
125
- getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache;
126
93
 
127
94
  // Validators and balances
128
95
  effectiveBalanceIncrements: EffectiveBalanceIncrements;
@@ -138,28 +105,10 @@ export interface IBeaconStateView {
138
105
  getAllValidators(): phase0.Validator[];
139
106
  getAllBalances(): number[];
140
107
 
141
- // Merge
142
- isExecutionStateType: boolean;
143
- isMergeTransitionComplete: boolean;
144
- // TODO this should go away (or rather only need block)
145
- isExecutionEnabled(block: BeaconBlock | BlindedBeaconBlock): boolean;
146
-
147
- // Block production
148
- getExpectedWithdrawals(): {
149
- expectedWithdrawals: capella.Withdrawal[];
150
- processedBuilderWithdrawalsCount: number;
151
- processedPartialWithdrawalsCount: number;
152
- processedValidatorSweepCount: number;
153
- };
154
-
155
108
  // API
156
109
  proposerRewards: RewardCache;
157
110
  computeBlockRewards(block: BeaconBlock, proposerRewards?: RewardCache): Promise<rewards.BlockRewards>;
158
111
  computeAttestationsRewards(validatorIds?: (ValidatorIndex | string)[]): Promise<rewards.AttestationsRewards>;
159
- computeSyncCommitteeRewards(
160
- block: BeaconBlock,
161
- validatorIds: (ValidatorIndex | string)[]
162
- ): Promise<rewards.SyncCommitteeRewards>;
163
112
  getLatestWeakSubjectivityCheckpointEpoch(): Epoch;
164
113
 
165
114
  // Validation
@@ -171,7 +120,6 @@ export interface IBeaconStateView {
171
120
 
172
121
  // Proofs
173
122
  getFinalizedRootProof(): Uint8Array[];
174
- getSyncCommitteesWitness(): SyncCommitteeWitness;
175
123
  getSingleProof(gindex: bigint): Uint8Array[];
176
124
  createMultiProof(descriptor: Uint8Array): CompactMultiProof;
177
125
 
@@ -180,6 +128,7 @@ export interface IBeaconStateView {
180
128
  justifiedCheckpoint: phase0.Checkpoint;
181
129
  finalizedCheckpoint: phase0.Checkpoint;
182
130
  };
131
+ computeAnchorCheckpoint(): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader};
183
132
 
184
133
  // this is for backward compatible
185
134
  clonedCount: number;
@@ -190,6 +139,7 @@ export interface IBeaconStateView {
190
139
 
191
140
  // Serialization
192
141
  loadOtherState(stateBytes: Uint8Array, seedValidatorsBytes?: Uint8Array): IBeaconStateView;
142
+ toValue(): BeaconState;
193
143
  serialize(): Uint8Array;
194
144
  serializedSize(): number;
195
145
  serializeToBytes(output: ByteViews, offset: number): number;
@@ -210,8 +160,133 @@ export interface IBeaconStateView {
210
160
  epochTransitionCacheOpts?: EpochTransitionCacheOpts & {dontTransferCache?: boolean},
211
161
  modules?: StateTransitionModules
212
162
  ): IBeaconStateView;
163
+ }
164
+
165
+ /** Altair+ state fields — use isStatePostAltair() guard */
166
+ export interface IBeaconStateViewAltair extends IBeaconStateView {
167
+ forkName: ForkPostAltair;
168
+ previousEpochParticipation: Uint8Array;
169
+ currentEpochParticipation: Uint8Array;
170
+ getPreviousEpochParticipation(validatorIndex: ValidatorIndex): number;
171
+ getCurrentEpochParticipation(validatorIndex: ValidatorIndex): number;
172
+ currentSyncCommittee: altair.SyncCommittee;
173
+ nextSyncCommittee: altair.SyncCommittee;
174
+ currentSyncCommitteeIndexed: SyncCommitteeCache;
175
+ syncProposerReward: number;
176
+ getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache;
177
+ /** Get indexed sync committee with slot+1 offset for duty lookups */
178
+ getIndexedSyncCommittee(slot: Slot): SyncCommitteeCache;
179
+ computeSyncCommitteeRewards(
180
+ block: BeaconBlock,
181
+ validatorIds: (ValidatorIndex | string)[]
182
+ ): Promise<rewards.SyncCommitteeRewards>;
183
+ getSyncCommitteesWitness(): SyncCommitteeWitness;
184
+ }
185
+
186
+ /** Bellatrix+ state fields — use isStatePostBellatrix() guard */
187
+ export interface IBeaconStateViewBellatrix extends IBeaconStateViewAltair {
188
+ forkName: ForkPostBellatrix;
189
+ latestExecutionPayloadHeader: ExecutionPayloadHeader;
190
+ /**
191
+ * Cross-fork accessor for the execution block hash of the most recently included payload.
192
+ * Pre-gloas: returns latestExecutionPayloadHeader.blockHash (bellatrix–fulu).
193
+ * Gloas+: returns the dedicated latestBlockHash state field (EIP-7732).
194
+ * Throws before bellatrix.
195
+ */
196
+ latestBlockHash: Bytes32;
197
+ /**
198
+ * The execution block number of the most recently included payload.
199
+ * Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
200
+ * Only available from bellatrix through fulu — not tracked on BeaconState in gloas+ (EIP-7732).
201
+ * Throws before bellatrix and from gloas onwards.
202
+ */
203
+ payloadBlockNumber: number;
204
+ isExecutionStateType: boolean;
205
+ isMergeTransitionComplete: boolean;
206
+ isExecutionEnabled(block: BeaconBlock | BlindedBeaconBlock): boolean;
207
+ }
208
+
209
+ /** Capella+ state fields — use isStatePostCapella() guard */
210
+ export interface IBeaconStateViewCapella extends IBeaconStateViewBellatrix {
211
+ forkName: ForkPostCapella;
212
+ historicalSummaries: capella.HistoricalSummaries;
213
+ getExpectedWithdrawals(): {
214
+ expectedWithdrawals: capella.Withdrawal[];
215
+ processedBuilderWithdrawalsCount: number;
216
+ processedPartialWithdrawalsCount: number;
217
+ processedBuildersSweepCount: number;
218
+ processedValidatorSweepCount: number;
219
+ };
220
+ }
221
+
222
+ /** Deneb+ state — no new state-view fields; placeholder for fork completeness and isStatePostDeneb() narrowing */
223
+ export interface IBeaconStateViewDeneb extends IBeaconStateViewCapella {
224
+ forkName: ForkPostDeneb;
225
+ }
226
+
227
+ /** Electra+ state fields — use isStatePostElectra() guard */
228
+ export interface IBeaconStateViewElectra extends IBeaconStateViewDeneb {
229
+ forkName: ForkPostElectra;
230
+ pendingDeposits: electra.PendingDeposits;
231
+ pendingDepositsCount: number;
232
+ pendingPartialWithdrawals: electra.PendingPartialWithdrawals;
233
+ pendingPartialWithdrawalsCount: number;
234
+ pendingConsolidations: electra.PendingConsolidations;
235
+ pendingConsolidationsCount: number;
236
+ }
237
+
238
+ /** Fulu+ state fields — use isStatePostFulu() guard */
239
+ export interface IBeaconStateViewFulu extends IBeaconStateViewElectra {
240
+ forkName: ForkPostFulu;
241
+ proposerLookahead: fulu.ProposerLookahead;
242
+ }
243
+
244
+ /** Gloas+ state fields — use isStatePostGloas() guard */
245
+ export interface IBeaconStateViewGloas extends IBeaconStateViewFulu {
246
+ forkName: ForkPostGloas;
247
+ executionPayloadAvailability: BitArray;
248
+ latestExecutionPayloadBid: ExecutionPayloadBid;
249
+ payloadExpectedWithdrawals: capella.Withdrawal[];
250
+ getBuilder(index: BuilderIndex): gloas.Builder;
251
+ canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean;
252
+ getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number;
213
253
  processExecutionPayloadEnvelope(
214
254
  signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
215
255
  opts?: ProcessExecutionPayloadEnvelopeOpts
216
256
  ): IBeaconStateView;
217
257
  }
258
+
259
+ /**
260
+ * Type constraint for the concrete BeaconStateView class.
261
+ * Requires all fields from the latest fork interface (IBeaconStateViewGloas) but keeps
262
+ * forkName as ForkName since the class wraps any fork's state.
263
+ * Sub-interfaces retain their narrowed forkName discriminants for caller-side type guards.
264
+ */
265
+ export type IBeaconStateViewLatestFork = Omit<IBeaconStateViewGloas, "forkName"> & {forkName: ForkName};
266
+ export function isStatePostAltair(state: IBeaconStateView): state is IBeaconStateViewAltair {
267
+ return isForkPostAltair(state.forkName);
268
+ }
269
+
270
+ export function isStatePostBellatrix(state: IBeaconStateView): state is IBeaconStateViewBellatrix {
271
+ return isForkPostBellatrix(state.forkName);
272
+ }
273
+
274
+ export function isStatePostCapella(state: IBeaconStateView): state is IBeaconStateViewCapella {
275
+ return isForkPostCapella(state.forkName);
276
+ }
277
+
278
+ export function isStatePostDeneb(state: IBeaconStateView): state is IBeaconStateViewDeneb {
279
+ return isForkPostDeneb(state.forkName);
280
+ }
281
+
282
+ export function isStatePostElectra(state: IBeaconStateView): state is IBeaconStateViewElectra {
283
+ return isForkPostElectra(state.forkName);
284
+ }
285
+
286
+ export function isStatePostFulu(state: IBeaconStateView): state is IBeaconStateViewFulu {
287
+ return isForkPostFulu(state.forkName);
288
+ }
289
+
290
+ export function isStatePostGloas(state: IBeaconStateView): state is IBeaconStateViewGloas {
291
+ return isForkPostGloas(state.forkName);
292
+ }