@lodestar/state-transition 1.42.0 → 1.43.0-dev.05a33e512f

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 (132) hide show
  1. package/lib/block/index.d.ts +2 -2
  2. package/lib/block/index.d.ts.map +1 -1
  3. package/lib/block/index.js +11 -4
  4. package/lib/block/index.js.map +1 -1
  5. package/lib/block/processConsolidationRequest.d.ts.map +1 -1
  6. package/lib/block/processConsolidationRequest.js +2 -1
  7. package/lib/block/processConsolidationRequest.js.map +1 -1
  8. package/lib/block/processDepositRequest.d.ts +11 -2
  9. package/lib/block/processDepositRequest.d.ts.map +1 -1
  10. package/lib/block/processDepositRequest.js +34 -4
  11. package/lib/block/processDepositRequest.js.map +1 -1
  12. package/lib/block/processParentExecutionPayload.d.ts +20 -0
  13. package/lib/block/processParentExecutionPayload.d.ts.map +1 -0
  14. package/lib/block/processParentExecutionPayload.js +100 -0
  15. package/lib/block/processParentExecutionPayload.js.map +1 -0
  16. package/lib/block/processWithdrawals.d.ts.map +1 -1
  17. package/lib/block/processWithdrawals.js +10 -4
  18. package/lib/block/processWithdrawals.js.map +1 -1
  19. package/lib/cache/epochCache.d.ts +3 -1
  20. package/lib/cache/epochCache.d.ts.map +1 -1
  21. package/lib/cache/epochCache.js +33 -15
  22. package/lib/cache/epochCache.js.map +1 -1
  23. package/lib/cache/epochTransitionCache.d.ts +5 -0
  24. package/lib/cache/epochTransitionCache.d.ts.map +1 -1
  25. package/lib/cache/epochTransitionCache.js +1 -0
  26. package/lib/cache/epochTransitionCache.js.map +1 -1
  27. package/lib/epoch/index.d.ts +3 -1
  28. package/lib/epoch/index.d.ts.map +1 -1
  29. package/lib/epoch/index.js +8 -1
  30. package/lib/epoch/index.js.map +1 -1
  31. package/lib/epoch/processPendingDeposits.d.ts.map +1 -1
  32. package/lib/epoch/processPendingDeposits.js +4 -2
  33. package/lib/epoch/processPendingDeposits.js.map +1 -1
  34. package/lib/epoch/processPtcWindow.d.ts +11 -0
  35. package/lib/epoch/processPtcWindow.d.ts.map +1 -0
  36. package/lib/epoch/processPtcWindow.js +28 -0
  37. package/lib/epoch/processPtcWindow.js.map +1 -0
  38. package/lib/index.d.ts +4 -2
  39. package/lib/index.d.ts.map +1 -1
  40. package/lib/index.js +4 -1
  41. package/lib/index.js.map +1 -1
  42. package/lib/signatureSets/executionPayloadEnvelope.d.ts.map +1 -1
  43. package/lib/signatureSets/executionPayloadEnvelope.js +5 -1
  44. package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
  45. package/lib/signatureSets/index.d.ts +1 -0
  46. package/lib/signatureSets/index.d.ts.map +1 -1
  47. package/lib/signatureSets/index.js +1 -0
  48. package/lib/signatureSets/index.js.map +1 -1
  49. package/lib/signatureSets/proposerPreferences.d.ts +4 -0
  50. package/lib/signatureSets/proposerPreferences.d.ts.map +1 -0
  51. package/lib/signatureSets/proposerPreferences.js +8 -0
  52. package/lib/signatureSets/proposerPreferences.js.map +1 -0
  53. package/lib/signatureSets/voluntaryExits.d.ts +2 -2
  54. package/lib/signatureSets/voluntaryExits.d.ts.map +1 -1
  55. package/lib/signatureSets/voluntaryExits.js +4 -0
  56. package/lib/signatureSets/voluntaryExits.js.map +1 -1
  57. package/lib/slot/upgradeStateToElectra.d.ts.map +1 -1
  58. package/lib/slot/upgradeStateToElectra.js +2 -2
  59. package/lib/slot/upgradeStateToElectra.js.map +1 -1
  60. package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
  61. package/lib/slot/upgradeStateToGloas.js +3 -1
  62. package/lib/slot/upgradeStateToGloas.js.map +1 -1
  63. package/lib/stateTransition.d.ts +1 -2
  64. package/lib/stateTransition.d.ts.map +1 -1
  65. package/lib/stateTransition.js +1 -2
  66. package/lib/stateTransition.js.map +1 -1
  67. package/lib/stateView/beaconStateView.d.ts +18 -12
  68. package/lib/stateView/beaconStateView.d.ts.map +1 -1
  69. package/lib/stateView/beaconStateView.js +69 -42
  70. package/lib/stateView/beaconStateView.js.map +1 -1
  71. package/lib/stateView/interface.d.ts +111 -54
  72. package/lib/stateView/interface.d.ts.map +1 -1
  73. package/lib/stateView/interface.js +22 -1
  74. package/lib/stateView/interface.js.map +1 -1
  75. package/lib/util/attestation.d.ts +12 -1
  76. package/lib/util/attestation.d.ts.map +1 -1
  77. package/lib/util/attestation.js +23 -8
  78. package/lib/util/attestation.js.map +1 -1
  79. package/lib/util/computeAnchorCheckpoint.d.ts +1 -1
  80. package/lib/util/computeAnchorCheckpoint.d.ts.map +1 -1
  81. package/lib/util/computeAnchorCheckpoint.js +6 -19
  82. package/lib/util/computeAnchorCheckpoint.js.map +1 -1
  83. package/lib/util/epoch.d.ts.map +1 -1
  84. package/lib/util/epoch.js +6 -4
  85. package/lib/util/epoch.js.map +1 -1
  86. package/lib/util/execution.d.ts +4 -2
  87. package/lib/util/execution.d.ts.map +1 -1
  88. package/lib/util/execution.js +7 -0
  89. package/lib/util/execution.js.map +1 -1
  90. package/lib/util/gloas.d.ts +7 -2
  91. package/lib/util/gloas.d.ts.map +1 -1
  92. package/lib/util/gloas.js +25 -3
  93. package/lib/util/gloas.js.map +1 -1
  94. package/lib/util/loadState/loadState.js +4 -4
  95. package/lib/util/loadState/loadState.js.map +1 -1
  96. package/lib/util/validator.d.ts +14 -2
  97. package/lib/util/validator.d.ts.map +1 -1
  98. package/lib/util/validator.js +24 -2
  99. package/lib/util/validator.js.map +1 -1
  100. package/package.json +8 -8
  101. package/src/block/index.ts +12 -4
  102. package/src/block/processConsolidationRequest.ts +2 -1
  103. package/src/block/processDepositRequest.ts +50 -5
  104. package/src/block/processParentExecutionPayload.ts +116 -0
  105. package/src/block/processWithdrawals.ts +12 -4
  106. package/src/cache/epochCache.ts +35 -33
  107. package/src/cache/epochTransitionCache.ts +7 -0
  108. package/src/epoch/index.ts +9 -0
  109. package/src/epoch/processPendingDeposits.ts +5 -2
  110. package/src/epoch/processPtcWindow.ts +38 -0
  111. package/src/index.ts +20 -2
  112. package/src/signatureSets/executionPayloadEnvelope.ts +6 -2
  113. package/src/signatureSets/index.ts +1 -0
  114. package/src/signatureSets/proposerPreferences.ts +12 -0
  115. package/src/signatureSets/voluntaryExits.ts +5 -2
  116. package/src/slot/upgradeStateToElectra.ts +4 -2
  117. package/src/slot/upgradeStateToGloas.ts +5 -1
  118. package/src/stateTransition.ts +1 -2
  119. package/src/stateView/beaconStateView.ts +91 -56
  120. package/src/stateView/interface.ts +163 -79
  121. package/src/util/attestation.ts +37 -8
  122. package/src/util/computeAnchorCheckpoint.ts +6 -19
  123. package/src/util/epoch.ts +13 -4
  124. package/src/util/execution.ts +11 -1
  125. package/src/util/gloas.ts +46 -3
  126. package/src/util/loadState/loadState.ts +4 -4
  127. package/src/util/validator.ts +42 -2
  128. package/lib/block/processExecutionPayloadEnvelope.d.ts +0 -9
  129. package/lib/block/processExecutionPayloadEnvelope.d.ts.map +0 -1
  130. package/lib/block/processExecutionPayloadEnvelope.js +0 -102
  131. package/lib/block/processExecutionPayloadEnvelope.js.map +0 -1
  132. package/src/block/processExecutionPayloadEnvelope.ts +0 -170
@@ -1,4 +1,4 @@
1
- import {FAR_FUTURE_EPOCH, GENESIS_SLOT, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params";
1
+ import {FAR_FUTURE_EPOCH, ForkSeq, GENESIS_SLOT, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params";
2
2
  import {ValidatorIndex, ssz} from "@lodestar/types";
3
3
  import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js";
4
4
  import {G2_POINT_AT_INFINITY} from "../constants/constants.js";
@@ -78,7 +78,9 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache
78
78
  stateElectraView.commit();
79
79
  const tmpElectraState = getCachedBeaconState(stateElectraView, stateDeneb);
80
80
  stateElectraView.exitBalanceToConsume = BigInt(getActivationExitChurnLimit(tmpElectraState.epochCtx));
81
- stateElectraView.consolidationBalanceToConsume = BigInt(getConsolidationChurnLimit(tmpElectraState.epochCtx));
81
+ stateElectraView.consolidationBalanceToConsume = BigInt(
82
+ getConsolidationChurnLimit(ForkSeq.electra, tmpElectraState.epochCtx)
83
+ );
82
84
 
83
85
  preActivation.sort((i0, i1) => {
84
86
  const res = validatorsArr[i0].activationEligibilityEpoch - validatorsArr[i1].activationEligibilityEpoch;
@@ -5,7 +5,7 @@ import {isValidDepositSignature} from "../block/processDeposit.js";
5
5
  import {applyDepositForBuilder} from "../block/processDepositRequest.js";
6
6
  import {getCachedBeaconState} from "../cache/stateCache.js";
7
7
  import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
8
- import {isBuilderWithdrawalCredential} from "../util/gloas.js";
8
+ import {initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
9
9
  import {isValidatorKnown} from "../util/index.js";
10
10
 
11
11
  /**
@@ -48,6 +48,9 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
48
48
  stateGloasView.currentSyncCommittee = stateGloasCloned.currentSyncCommittee;
49
49
  stateGloasView.nextSyncCommittee = stateGloasCloned.nextSyncCommittee;
50
50
  stateGloasView.latestExecutionPayloadBid.blockHash = stateFulu.latestExecutionPayloadHeader.blockHash;
51
+ stateGloasView.latestExecutionPayloadBid.executionRequestsRoot = ssz.electra.ExecutionRequests.hashTreeRoot(
52
+ ssz.electra.ExecutionRequests.defaultValue()
53
+ );
51
54
  stateGloasView.nextWithdrawalIndex = stateGloasCloned.nextWithdrawalIndex;
52
55
  stateGloasView.nextWithdrawalValidatorIndex = stateGloasCloned.nextWithdrawalValidatorIndex;
53
56
  stateGloasView.historicalSummaries = stateGloasCloned.historicalSummaries;
@@ -61,6 +64,7 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
61
64
  stateGloasView.pendingPartialWithdrawals = stateGloasCloned.pendingPartialWithdrawals;
62
65
  stateGloasView.pendingConsolidations = stateGloasCloned.pendingConsolidations;
63
66
  stateGloasView.proposerLookahead = stateGloasCloned.proposerLookahead;
67
+ stateGloasView.ptcWindow = ssz.gloas.PtcWindow.toViewDU(initializePtcWindow(stateFulu));
64
68
 
65
69
  for (let i = 0; i < SLOTS_PER_HISTORICAL_ROOT; i++) {
66
70
  stateGloasView.executionPayloadAvailability.set(i, true);
@@ -76,7 +76,6 @@ 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",
80
79
  }
81
80
 
82
81
  /**
@@ -283,7 +282,7 @@ function processSlotsWithTransientCache(
283
282
  {
284
283
  const timer = metrics?.epochTransitionStepTime.startTimer({step: EpochTransitionStep.finalProcessEpoch});
285
284
  // last step to prepare epoch data that depends on the upgraded state, for example proposerLookahead of BeaconStateFulu
286
- postState.epochCtx.finalProcessEpoch(postState);
285
+ postState.epochCtx.finalProcessEpoch(postState, epochTransitionCache);
287
286
  timer?.();
288
287
  }
289
288
 
@@ -1,7 +1,7 @@
1
1
  import {CompactMultiProof, ProofType, Tree, createProof} from "@chainsafe/persistent-merkle-tree";
2
2
  import {BitArray, ByteViews} from "@chainsafe/ssz";
3
3
  import {BeaconConfig} from "@lodestar/config";
4
- import {ForkSeq, SLOTS_PER_HISTORICAL_ROOT, isForkPostGloas} from "@lodestar/params";
4
+ import {ForkName, ForkSeq, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
5
5
  import {
6
6
  BeaconBlock,
7
7
  BeaconState,
@@ -28,8 +28,7 @@ import {
28
28
  rewards,
29
29
  } from "@lodestar/types";
30
30
  import {Checkpoint, Fork} from "@lodestar/types/phase0";
31
- import {processExecutionPayloadEnvelope} from "../block/index.js";
32
- import {ProcessExecutionPayloadEnvelopeOpts} from "../block/processExecutionPayloadEnvelope.js";
31
+ import {applyParentExecutionPayload} from "../block/processParentExecutionPayload.js";
33
32
  import {VoluntaryExitValidity, getVoluntaryExitValidity} from "../block/processVoluntaryExit.js";
34
33
  import {getExpectedWithdrawals} from "../block/processWithdrawals.js";
35
34
  import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
@@ -59,14 +58,19 @@ import {getBlockRootAtSlot} from "../util/blockRoot.js";
59
58
  import {computeAnchorCheckpoint} from "../util/computeAnchorCheckpoint.js";
60
59
  import {computeEpochAtSlot, computeStartSlotAtEpoch} from "../util/epoch.js";
61
60
  import {EpochShuffling} from "../util/epochShuffling.js";
62
- import {isExecutionEnabled, isExecutionStateType, isMergeTransitionComplete} from "../util/execution.js";
61
+ import {
62
+ isExecutionEnabled,
63
+ isExecutionStateType,
64
+ isGloasStateType,
65
+ isMergeTransitionComplete,
66
+ } from "../util/execution.js";
63
67
  import {canBuilderCoverBid} from "../util/gloas.js";
64
68
  import {loadState} from "../util/loadState/loadState.js";
65
69
  import {getRandaoMix} from "../util/seed.js";
66
70
  import {getLatestWeakSubjectivityCheckpointEpoch} from "../util/weakSubjectivity.js";
67
- import {IBeaconStateView} from "./interface.js";
71
+ import {IBeaconStateView, IBeaconStateViewGloas, IBeaconStateViewLatestFork, isStatePostGloas} from "./interface.js";
68
72
 
69
- export class BeaconStateView implements IBeaconStateView {
73
+ export class BeaconStateView implements IBeaconStateViewLatestFork {
70
74
  private readonly config: BeaconConfig;
71
75
  // Cached values extracted from the tree
72
76
  // phase0
@@ -79,8 +83,6 @@ export class BeaconStateView implements IBeaconStateView {
79
83
  private _currentEpochParticipation: Uint8Array | null = null;
80
84
  // bellatrix
81
85
  private _latestExecutionPayloadHeader: ExecutionPayloadHeader | null = null;
82
- // Caches the cross-fork latestBlockHash value
83
- private _latestBlockHash: Bytes32 | null = null;
84
86
  // capella
85
87
  private _historicalSummaries: capella.HistoricalSummaries | null = null;
86
88
  // electra
@@ -92,6 +94,7 @@ export class BeaconStateView implements IBeaconStateView {
92
94
  // gloas
93
95
  private _executionPayloadAvailability: BitArray | null = null;
94
96
  private _latestExecutionPayloadBid: ExecutionPayloadBid | null = null;
97
+ private _payloadExpectedWithdrawals: capella.Withdrawal[] | null = null;
95
98
 
96
99
  constructor(readonly cachedState: CachedBeaconStateAllForks) {
97
100
  this.config = cachedState.config;
@@ -99,6 +102,10 @@ export class BeaconStateView implements IBeaconStateView {
99
102
 
100
103
  // phase0
101
104
 
105
+ get forkName(): ForkName {
106
+ return this.config.getForkName(this.cachedState.slot);
107
+ }
108
+
102
109
  get slot(): number {
103
110
  return this.cachedState.slot;
104
111
  }
@@ -208,9 +215,13 @@ export class BeaconStateView implements IBeaconStateView {
208
215
  // bellatrix
209
216
 
210
217
  get latestExecutionPayloadHeader(): ExecutionPayloadHeader {
211
- if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.bellatrix) {
218
+ const forkSeq = this.config.getForkSeq(this.cachedState.slot);
219
+ if (forkSeq < ForkSeq.bellatrix) {
212
220
  throw new Error("latestExecutionPayloadHeader is not available before Bellatrix");
213
221
  }
222
+ if (forkSeq >= ForkSeq.gloas) {
223
+ throw new Error("latestExecutionPayloadHeader is not available after Gloas");
224
+ }
214
225
 
215
226
  if (this._latestExecutionPayloadHeader === null) {
216
227
  this._latestExecutionPayloadHeader = (
@@ -221,30 +232,6 @@ export class BeaconStateView implements IBeaconStateView {
221
232
  return this._latestExecutionPayloadHeader;
222
233
  }
223
234
 
224
- /**
225
- * Cross-fork accessor for the execution block hash of the most recently included payload.
226
- * Pre-gloas: reads from latestExecutionPayloadHeader.blockHash.
227
- * Gloas+: reads the dedicated latestBlockHash field (EIP-7732).
228
- */
229
- get latestBlockHash(): Bytes32 {
230
- const forkSeq = this.config.getForkSeq(this.cachedState.slot);
231
- if (forkSeq < ForkSeq.bellatrix) {
232
- throw new Error("latestBlockHash is not available before Bellatrix");
233
- }
234
-
235
- if (this._latestBlockHash === null) {
236
- if (forkSeq >= ForkSeq.gloas) {
237
- this._latestBlockHash = (this.cachedState as CachedBeaconStateGloas).latestBlockHash;
238
- } else {
239
- this._latestBlockHash = (
240
- this.cachedState as CachedBeaconStateExecutions
241
- ).latestExecutionPayloadHeader.blockHash;
242
- }
243
- }
244
-
245
- return this._latestBlockHash;
246
- }
247
-
248
235
  /**
249
236
  * The execution block number of the most recently included payload.
250
237
  * Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
@@ -355,9 +342,16 @@ export class BeaconStateView implements IBeaconStateView {
355
342
 
356
343
  // gloas
357
344
 
345
+ get latestBlockHash(): Bytes32 {
346
+ if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
347
+ throw new Error("latestBlockHash is not available before Gloas");
348
+ }
349
+ return (this.cachedState as CachedBeaconStateGloas).latestBlockHash;
350
+ }
351
+
358
352
  get executionPayloadAvailability(): BitArray {
359
353
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
360
- throw new Error("executionPayloadAvailability is not available before GLOAS");
354
+ throw new Error("executionPayloadAvailability is not available before Gloas");
361
355
  }
362
356
 
363
357
  if (this._executionPayloadAvailability === null) {
@@ -371,7 +365,7 @@ export class BeaconStateView implements IBeaconStateView {
371
365
 
372
366
  get latestExecutionPayloadBid(): ExecutionPayloadBid {
373
367
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
374
- throw new Error("latestExecutionPayloadBid is not available before GLOAS");
368
+ throw new Error("latestExecutionPayloadBid is not available before Gloas");
375
369
  }
376
370
 
377
371
  if (this._latestExecutionPayloadBid === null) {
@@ -382,9 +376,22 @@ export class BeaconStateView implements IBeaconStateView {
382
376
  return this._latestExecutionPayloadBid;
383
377
  }
384
378
 
379
+ get payloadExpectedWithdrawals(): capella.Withdrawal[] {
380
+ if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
381
+ throw new Error("payloadExpectedWithdrawals is not available before Gloas");
382
+ }
383
+
384
+ if (this._payloadExpectedWithdrawals === null) {
385
+ this._payloadExpectedWithdrawals = (
386
+ this.cachedState as CachedBeaconStateGloas
387
+ ).payloadExpectedWithdrawals.toValue();
388
+ }
389
+ return this._payloadExpectedWithdrawals;
390
+ }
391
+
385
392
  getBuilder(index: BuilderIndex): gloas.Builder {
386
393
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
387
- throw new Error("Builders are not supported before GLOAS");
394
+ throw new Error("Builders are not supported before Gloas");
388
395
  }
389
396
 
390
397
  return (this.cachedState as CachedBeaconStateGloas).builders.getReadonly(index);
@@ -392,19 +399,36 @@ export class BeaconStateView implements IBeaconStateView {
392
399
 
393
400
  canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean {
394
401
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
395
- throw new Error("Builders are not supported before GLOAS");
402
+ throw new Error("Builders are not supported before Gloas");
396
403
  }
397
404
 
398
405
  return canBuilderCoverBid(this.cachedState as CachedBeaconStateGloas, builderIndex, bidAmount);
399
406
  }
400
407
 
408
+ /**
409
+ * Return the PTCs for an epoch
410
+ */
411
+ getEpochPTCs(epoch: Epoch): Uint32Array[] {
412
+ if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
413
+ throw new Error("PTC committees are not supported before Gloas");
414
+ }
415
+
416
+ const epochCtx = (this.cachedState as CachedBeaconStateGloas).epochCtx;
417
+ if (epoch === epochCtx.epoch) {
418
+ return epochCtx.payloadTimelinessCommittees;
419
+ }
420
+ if (epoch === epochCtx.nextEpoch) {
421
+ return epochCtx.nextPayloadTimelinessCommittees;
422
+ }
423
+ throw new Error(`PTC committees are not available for epoch=${epoch}`);
424
+ }
401
425
  /**
402
426
  * Return the index of the validator in the PTC committee for the given slot.
403
427
  * return -1 if validator is not in the PTC committee for the given slot.
404
428
  */
405
429
  getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number {
406
430
  if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
407
- throw new Error("PTC committees are not supported before GLOAS");
431
+ throw new Error("PTC committees are not supported before Gloas");
408
432
  }
409
433
 
410
434
  const ptcCommittee = (this.cachedState as CachedBeaconStateGloas).epochCtx.getPayloadTimelinessCommittee(slot);
@@ -571,7 +595,10 @@ export class BeaconStateView implements IBeaconStateView {
571
595
  }
572
596
 
573
597
  get isMergeTransitionComplete(): boolean {
574
- return isExecutionStateType(this.cachedState) && isMergeTransitionComplete(this.cachedState);
598
+ return (
599
+ (isExecutionStateType(this.cachedState) || isGloasStateType(this.cachedState)) &&
600
+ isMergeTransitionComplete(this.cachedState)
601
+ );
575
602
  }
576
603
 
577
604
  // Block production
@@ -693,7 +720,11 @@ export class BeaconStateView implements IBeaconStateView {
693
720
 
694
721
  // Serialization
695
722
 
696
- loadOtherState(stateBytes: Uint8Array, seedValidatorsBytes?: Uint8Array): IBeaconStateView {
723
+ loadOtherState(
724
+ stateBytes: Uint8Array,
725
+ seedValidatorsBytes?: Uint8Array,
726
+ opts?: {preloadValidatorsAndBalances?: boolean}
727
+ ): IBeaconStateView {
697
728
  const {state} = loadState(this.config, this.cachedState, stateBytes, seedValidatorsBytes);
698
729
 
699
730
  const cachedState = createCachedBeaconState(
@@ -708,9 +739,10 @@ export class BeaconStateView implements IBeaconStateView {
708
739
  }
709
740
  );
710
741
 
711
- // load all cache in order for consumers (usually regen.getState()) to process blocks faster
712
- cachedState.validators.getAllReadonlyValues();
713
- cachedState.balances.getAll();
742
+ if (opts?.preloadValidatorsAndBalances) {
743
+ cachedState.validators.getAllReadonlyValues();
744
+ cachedState.balances.getAll();
745
+ }
714
746
 
715
747
  return new BeaconStateView(cachedState);
716
748
  }
@@ -768,19 +800,22 @@ export class BeaconStateView implements IBeaconStateView {
768
800
  return new BeaconStateView(newState);
769
801
  }
770
802
 
771
- processExecutionPayloadEnvelope(
772
- signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
773
- opts?: ProcessExecutionPayloadEnvelopeOpts
774
- ): BeaconStateView {
775
- const fork = this.config.getForkName(this.cachedState.slot);
776
- if (!isForkPostGloas(fork)) {
777
- throw Error(`processExecutionPayloadEnvelope is only available for gloas+ forks, got fork=${fork}`);
803
+ /**
804
+ * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.5/specs/gloas/validator.md#executionpayload
805
+ */
806
+ withParentPayloadApplied(executionRequests: electra.ExecutionRequests): IBeaconStateViewGloas {
807
+ if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
808
+ throw new Error("withParentPayloadApplied is not available before Gloas");
778
809
  }
779
- const postPayloadState = processExecutionPayloadEnvelope(
780
- this.cachedState as CachedBeaconStateGloas,
781
- signedEnvelope,
782
- opts
783
- );
784
- return new BeaconStateView(postPayloadState);
810
+ const stateCopy = this.cachedState.clone(true) as CachedBeaconStateGloas;
811
+
812
+ applyParentExecutionPayload(stateCopy, executionRequests);
813
+
814
+ const stateView = new BeaconStateView(stateCopy);
815
+ if (!isStatePostGloas(stateView)) {
816
+ throw new Error("Expected gloas state after clone");
817
+ }
818
+
819
+ return stateView;
785
820
  }
786
821
  }
@@ -1,5 +1,22 @@
1
1
  import {CompactMultiProof} from "@chainsafe/persistent-merkle-tree";
2
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,
5
22
  BeaconState,
@@ -24,7 +41,6 @@ import {
24
41
  rewards,
25
42
  } from "@lodestar/types";
26
43
  import {Checkpoint, Fork} from "@lodestar/types/phase0";
27
- import {ProcessExecutionPayloadEnvelopeOpts} from "../block/processExecutionPayloadEnvelope.js";
28
44
  import {VoluntaryExitValidity} from "../block/processVoluntaryExit.js";
29
45
  import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
30
46
  import {EpochTransitionCacheOpts} from "../cache/epochTransitionCache.js";
@@ -41,6 +57,7 @@ export interface IBeaconStateView {
41
57
  // State access
42
58
 
43
59
  // phase0
60
+ forkName: ForkName;
44
61
  slot: Slot;
45
62
  fork: Fork;
46
63
  epoch: Epoch;
@@ -56,50 +73,6 @@ export interface IBeaconStateView {
56
73
  getStateRootAtSlot(slot: Slot): Root;
57
74
  getRandaoMix(epoch: Epoch): Bytes32;
58
75
 
59
- // altair
60
- previousEpochParticipation: Uint8Array;
61
- currentEpochParticipation: Uint8Array;
62
- getPreviousEpochParticipation(validatorIndex: ValidatorIndex): number;
63
- getCurrentEpochParticipation(validatorIndex: ValidatorIndex): number;
64
-
65
- // bellatrix
66
- latestExecutionPayloadHeader: ExecutionPayloadHeader;
67
- /**
68
- * Cross-fork accessor for the execution block hash of the most recently included payload.
69
- * Pre-gloas: returns latestExecutionPayloadHeader.blockHash (bellatrix–fulu).
70
- * Gloas+: returns the dedicated latestBlockHash state field (EIP-7732).
71
- * Throws before bellatrix.
72
- */
73
- latestBlockHash: Bytes32;
74
- /**
75
- * The execution block number of the most recently included payload.
76
- * Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
77
- * Only available from bellatrix through fulu — not tracked on BeaconState in gloas+ (EIP-7732).
78
- * Throws before bellatrix and from gloas onwards.
79
- */
80
- payloadBlockNumber: number;
81
-
82
- // capella
83
- historicalSummaries: capella.HistoricalSummaries;
84
-
85
- // electra
86
- pendingDeposits: electra.PendingDeposits;
87
- pendingDepositsCount: number;
88
- pendingPartialWithdrawals: electra.PendingPartialWithdrawals;
89
- pendingPartialWithdrawalsCount: number;
90
- pendingConsolidations: electra.PendingConsolidations;
91
- pendingConsolidationsCount: number;
92
-
93
- // fulu
94
- proposerLookahead: fulu.ProposerLookahead;
95
-
96
- // gloas
97
- executionPayloadAvailability: BitArray;
98
- latestExecutionPayloadBid: ExecutionPayloadBid;
99
- getBuilder(index: BuilderIndex): gloas.Builder;
100
- canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean;
101
- getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number;
102
-
103
76
  // Shuffling and committees
104
77
  getShufflingAtEpoch(epoch: Epoch): EpochShuffling;
105
78
  // Decision roots
@@ -117,15 +90,6 @@ export interface IBeaconStateView {
117
90
  nextProposers: ValidatorIndex[];
118
91
  getBeaconProposer(slot: Slot): ValidatorIndex;
119
92
 
120
- // Sync committees
121
- currentSyncCommittee: altair.SyncCommittee;
122
- nextSyncCommittee: altair.SyncCommittee;
123
- currentSyncCommitteeIndexed: SyncCommitteeCache;
124
- syncProposerReward: number;
125
- getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache;
126
- /** Get indexed sync committee with slot+1 offset for duty lookups */
127
- getIndexedSyncCommittee(slot: Slot): SyncCommitteeCache;
128
-
129
93
  // Validators and balances
130
94
  effectiveBalanceIncrements: EffectiveBalanceIncrements;
131
95
  getEffectiveBalanceIncrementsZeroInactive(): EffectiveBalanceIncrements;
@@ -140,29 +104,10 @@ export interface IBeaconStateView {
140
104
  getAllValidators(): phase0.Validator[];
141
105
  getAllBalances(): number[];
142
106
 
143
- // Merge
144
- isExecutionStateType: boolean;
145
- isMergeTransitionComplete: boolean;
146
- // TODO this should go away (or rather only need block)
147
- isExecutionEnabled(block: BeaconBlock | BlindedBeaconBlock): boolean;
148
-
149
- // Block production
150
- getExpectedWithdrawals(): {
151
- expectedWithdrawals: capella.Withdrawal[];
152
- processedBuilderWithdrawalsCount: number;
153
- processedPartialWithdrawalsCount: number;
154
- processedBuildersSweepCount: number;
155
- processedValidatorSweepCount: number;
156
- };
157
-
158
107
  // API
159
108
  proposerRewards: RewardCache;
160
109
  computeBlockRewards(block: BeaconBlock, proposerRewards?: RewardCache): Promise<rewards.BlockRewards>;
161
110
  computeAttestationsRewards(validatorIds?: (ValidatorIndex | string)[]): Promise<rewards.AttestationsRewards>;
162
- computeSyncCommitteeRewards(
163
- block: BeaconBlock,
164
- validatorIds: (ValidatorIndex | string)[]
165
- ): Promise<rewards.SyncCommitteeRewards>;
166
111
  getLatestWeakSubjectivityCheckpointEpoch(): Epoch;
167
112
 
168
113
  // Validation
@@ -174,7 +119,6 @@ export interface IBeaconStateView {
174
119
 
175
120
  // Proofs
176
121
  getFinalizedRootProof(): Uint8Array[];
177
- getSyncCommitteesWitness(): SyncCommitteeWitness;
178
122
  getSingleProof(gindex: bigint): Uint8Array[];
179
123
  createMultiProof(descriptor: Uint8Array): CompactMultiProof;
180
124
 
@@ -193,7 +137,13 @@ export interface IBeaconStateView {
193
137
  isStateValidatorsNodesPopulated(): boolean;
194
138
 
195
139
  // Serialization
196
- loadOtherState(stateBytes: Uint8Array, seedValidatorsBytes?: Uint8Array): IBeaconStateView;
140
+ /** Set `preloadValidatorsAndBalances` only when the whole state will be consumed
141
+ * immediately (e.g. CP reload before block replay). */
142
+ loadOtherState(
143
+ stateBytes: Uint8Array,
144
+ seedValidatorsBytes?: Uint8Array,
145
+ opts?: {preloadValidatorsAndBalances?: boolean}
146
+ ): IBeaconStateView;
197
147
  toValue(): BeaconState;
198
148
  serialize(): Uint8Array;
199
149
  serializedSize(): number;
@@ -215,8 +165,142 @@ export interface IBeaconStateView {
215
165
  epochTransitionCacheOpts?: EpochTransitionCacheOpts & {dontTransferCache?: boolean},
216
166
  modules?: StateTransitionModules
217
167
  ): IBeaconStateView;
218
- processExecutionPayloadEnvelope(
219
- signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
220
- opts?: ProcessExecutionPayloadEnvelopeOpts
221
- ): IBeaconStateView;
168
+ }
169
+
170
+ /** Altair+ state fields — use isStatePostAltair() guard */
171
+ export interface IBeaconStateViewAltair extends IBeaconStateView {
172
+ forkName: ForkPostAltair;
173
+ previousEpochParticipation: Uint8Array;
174
+ currentEpochParticipation: Uint8Array;
175
+ getPreviousEpochParticipation(validatorIndex: ValidatorIndex): number;
176
+ getCurrentEpochParticipation(validatorIndex: ValidatorIndex): number;
177
+ currentSyncCommittee: altair.SyncCommittee;
178
+ nextSyncCommittee: altair.SyncCommittee;
179
+ currentSyncCommitteeIndexed: SyncCommitteeCache;
180
+ syncProposerReward: number;
181
+ getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache;
182
+ /** Get indexed sync committee with slot+1 offset for duty lookups */
183
+ getIndexedSyncCommittee(slot: Slot): SyncCommitteeCache;
184
+ computeSyncCommitteeRewards(
185
+ block: BeaconBlock,
186
+ validatorIds: (ValidatorIndex | string)[]
187
+ ): Promise<rewards.SyncCommitteeRewards>;
188
+ getSyncCommitteesWitness(): SyncCommitteeWitness;
189
+ }
190
+
191
+ /** Bellatrix+ state fields — use isStatePostBellatrix() guard */
192
+ export interface IBeaconStateViewBellatrix extends IBeaconStateViewAltair {
193
+ forkName: ForkPostBellatrix;
194
+ latestExecutionPayloadHeader: ExecutionPayloadHeader;
195
+ /**
196
+ * The execution block number of the most recently included payload.
197
+ * Named payloadBlockNumber (not latestBlockNumber) to mirror ExecutionPayloadHeader.blockNumber pre-gloas.
198
+ * Only available from bellatrix through fulu — not tracked on BeaconState in gloas+ (EIP-7732).
199
+ * Throws before bellatrix and from gloas onwards.
200
+ */
201
+ payloadBlockNumber: number;
202
+ isExecutionStateType: boolean;
203
+ isMergeTransitionComplete: boolean;
204
+ isExecutionEnabled(block: BeaconBlock | BlindedBeaconBlock): boolean;
205
+ }
206
+
207
+ /** Capella+ state fields — use isStatePostCapella() guard */
208
+ export interface IBeaconStateViewCapella extends IBeaconStateViewBellatrix {
209
+ forkName: ForkPostCapella;
210
+ historicalSummaries: capella.HistoricalSummaries;
211
+ getExpectedWithdrawals(): {
212
+ expectedWithdrawals: capella.Withdrawal[];
213
+ processedBuilderWithdrawalsCount: number;
214
+ processedPartialWithdrawalsCount: number;
215
+ processedBuildersSweepCount: number;
216
+ processedValidatorSweepCount: number;
217
+ };
218
+ }
219
+
220
+ /** Deneb+ state — no new state-view fields; placeholder for fork completeness and isStatePostDeneb() narrowing */
221
+ export interface IBeaconStateViewDeneb extends IBeaconStateViewCapella {
222
+ forkName: ForkPostDeneb;
223
+ }
224
+
225
+ /** Electra+ state fields — use isStatePostElectra() guard */
226
+ export interface IBeaconStateViewElectra extends IBeaconStateViewDeneb {
227
+ forkName: ForkPostElectra;
228
+ pendingDeposits: electra.PendingDeposits;
229
+ pendingDepositsCount: number;
230
+ pendingPartialWithdrawals: electra.PendingPartialWithdrawals;
231
+ pendingPartialWithdrawalsCount: number;
232
+ pendingConsolidations: electra.PendingConsolidations;
233
+ pendingConsolidationsCount: number;
234
+ }
235
+
236
+ /** Fulu+ state fields — use isStatePostFulu() guard */
237
+ export interface IBeaconStateViewFulu extends IBeaconStateViewElectra {
238
+ forkName: ForkPostFulu;
239
+ proposerLookahead: fulu.ProposerLookahead;
240
+ }
241
+
242
+ /** Gloas+ state fields — use isStatePostGloas() guard */
243
+ export interface IBeaconStateViewGloas extends IBeaconStateViewFulu {
244
+ forkName: ForkPostGloas;
245
+ /** Removed from BeaconState in gloas. Use `latestBlockHash` instead. */
246
+ latestExecutionPayloadHeader: never;
247
+ /** Removed from BeaconState in gloas. */
248
+ payloadBlockNumber: never;
249
+ latestBlockHash: Bytes32;
250
+ executionPayloadAvailability: BitArray;
251
+ latestExecutionPayloadBid: ExecutionPayloadBid;
252
+ payloadExpectedWithdrawals: capella.Withdrawal[];
253
+ getBuilder(index: BuilderIndex): gloas.Builder;
254
+ canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean;
255
+ getEpochPTCs(epoch: Epoch): Uint32Array[];
256
+ getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number;
257
+ /**
258
+ * Clone the state and apply parent execution payload effects.
259
+ * Used during block production and prepareNextSlot so that withdrawals and
260
+ * operation selection (e.g. voluntary exits) see the same post-apply state that the block
261
+ * processor will see at import.
262
+ */
263
+ withParentPayloadApplied(executionRequests: electra.ExecutionRequests): IBeaconStateViewGloas;
264
+ }
265
+
266
+ /**
267
+ * Type constraint for the concrete BeaconStateView class.
268
+ * Requires all fields from the latest fork interface (IBeaconStateViewGloas) but keeps
269
+ * forkName as ForkName since the class wraps any fork's state.
270
+ * Sub-interfaces retain their narrowed forkName discriminants for caller-side type guards.
271
+ */
272
+ export type IBeaconStateViewLatestFork = Omit<
273
+ IBeaconStateViewGloas,
274
+ "forkName" | "latestExecutionPayloadHeader" | "payloadBlockNumber"
275
+ > & {
276
+ forkName: ForkName;
277
+ latestExecutionPayloadHeader: ExecutionPayloadHeader;
278
+ payloadBlockNumber: number;
279
+ };
280
+ export function isStatePostAltair(state: IBeaconStateView): state is IBeaconStateViewAltair {
281
+ return isForkPostAltair(state.forkName);
282
+ }
283
+
284
+ export function isStatePostBellatrix(state: IBeaconStateView): state is IBeaconStateViewBellatrix {
285
+ return isForkPostBellatrix(state.forkName);
286
+ }
287
+
288
+ export function isStatePostCapella(state: IBeaconStateView): state is IBeaconStateViewCapella {
289
+ return isForkPostCapella(state.forkName);
290
+ }
291
+
292
+ export function isStatePostDeneb(state: IBeaconStateView): state is IBeaconStateViewDeneb {
293
+ return isForkPostDeneb(state.forkName);
294
+ }
295
+
296
+ export function isStatePostElectra(state: IBeaconStateView): state is IBeaconStateViewElectra {
297
+ return isForkPostElectra(state.forkName);
298
+ }
299
+
300
+ export function isStatePostFulu(state: IBeaconStateView): state is IBeaconStateViewFulu {
301
+ return isForkPostFulu(state.forkName);
302
+ }
303
+
304
+ export function isStatePostGloas(state: IBeaconStateView): state is IBeaconStateViewGloas {
305
+ return isForkPostGloas(state.forkName);
222
306
  }