@lodestar/state-transition 1.42.0 → 1.43.0-dev.07452fe3b7

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 (108) 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/processDepositRequest.d.ts +11 -2
  6. package/lib/block/processDepositRequest.d.ts.map +1 -1
  7. package/lib/block/processDepositRequest.js +34 -4
  8. package/lib/block/processDepositRequest.js.map +1 -1
  9. package/lib/block/processParentExecutionPayload.d.ts +20 -0
  10. package/lib/block/processParentExecutionPayload.d.ts.map +1 -0
  11. package/lib/block/processParentExecutionPayload.js +100 -0
  12. package/lib/block/processParentExecutionPayload.js.map +1 -0
  13. package/lib/block/processWithdrawals.d.ts.map +1 -1
  14. package/lib/block/processWithdrawals.js +10 -4
  15. package/lib/block/processWithdrawals.js.map +1 -1
  16. package/lib/cache/epochCache.d.ts +3 -1
  17. package/lib/cache/epochCache.d.ts.map +1 -1
  18. package/lib/cache/epochCache.js +31 -13
  19. package/lib/cache/epochCache.js.map +1 -1
  20. package/lib/cache/epochTransitionCache.d.ts +5 -0
  21. package/lib/cache/epochTransitionCache.d.ts.map +1 -1
  22. package/lib/cache/epochTransitionCache.js +1 -0
  23. package/lib/cache/epochTransitionCache.js.map +1 -1
  24. package/lib/epoch/index.d.ts +3 -1
  25. package/lib/epoch/index.d.ts.map +1 -1
  26. package/lib/epoch/index.js +8 -1
  27. package/lib/epoch/index.js.map +1 -1
  28. package/lib/epoch/processPtcWindow.d.ts +11 -0
  29. package/lib/epoch/processPtcWindow.d.ts.map +1 -0
  30. package/lib/epoch/processPtcWindow.js +28 -0
  31. package/lib/epoch/processPtcWindow.js.map +1 -0
  32. package/lib/index.d.ts +4 -2
  33. package/lib/index.d.ts.map +1 -1
  34. package/lib/index.js +4 -1
  35. package/lib/index.js.map +1 -1
  36. package/lib/signatureSets/executionPayloadEnvelope.d.ts.map +1 -1
  37. package/lib/signatureSets/executionPayloadEnvelope.js +5 -1
  38. package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
  39. package/lib/signatureSets/index.d.ts +1 -0
  40. package/lib/signatureSets/index.d.ts.map +1 -1
  41. package/lib/signatureSets/index.js +1 -0
  42. package/lib/signatureSets/index.js.map +1 -1
  43. package/lib/signatureSets/proposerPreferences.d.ts +4 -0
  44. package/lib/signatureSets/proposerPreferences.d.ts.map +1 -0
  45. package/lib/signatureSets/proposerPreferences.js +8 -0
  46. package/lib/signatureSets/proposerPreferences.js.map +1 -0
  47. package/lib/signatureSets/voluntaryExits.d.ts +2 -2
  48. package/lib/signatureSets/voluntaryExits.d.ts.map +1 -1
  49. package/lib/signatureSets/voluntaryExits.js +4 -0
  50. package/lib/signatureSets/voluntaryExits.js.map +1 -1
  51. package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
  52. package/lib/slot/upgradeStateToGloas.js +3 -1
  53. package/lib/slot/upgradeStateToGloas.js.map +1 -1
  54. package/lib/stateTransition.d.ts +1 -2
  55. package/lib/stateTransition.d.ts.map +1 -1
  56. package/lib/stateTransition.js +1 -2
  57. package/lib/stateTransition.js.map +1 -1
  58. package/lib/stateView/beaconStateView.d.ts +18 -12
  59. package/lib/stateView/beaconStateView.d.ts.map +1 -1
  60. package/lib/stateView/beaconStateView.js +69 -42
  61. package/lib/stateView/beaconStateView.js.map +1 -1
  62. package/lib/stateView/interface.d.ts +111 -54
  63. package/lib/stateView/interface.d.ts.map +1 -1
  64. package/lib/stateView/interface.js +22 -1
  65. package/lib/stateView/interface.js.map +1 -1
  66. package/lib/util/attestation.d.ts +12 -1
  67. package/lib/util/attestation.d.ts.map +1 -1
  68. package/lib/util/attestation.js +23 -8
  69. package/lib/util/attestation.js.map +1 -1
  70. package/lib/util/computeAnchorCheckpoint.d.ts +1 -1
  71. package/lib/util/computeAnchorCheckpoint.d.ts.map +1 -1
  72. package/lib/util/computeAnchorCheckpoint.js +6 -19
  73. package/lib/util/computeAnchorCheckpoint.js.map +1 -1
  74. package/lib/util/execution.d.ts +4 -2
  75. package/lib/util/execution.d.ts.map +1 -1
  76. package/lib/util/execution.js +7 -0
  77. package/lib/util/execution.js.map +1 -1
  78. package/lib/util/gloas.d.ts +7 -2
  79. package/lib/util/gloas.d.ts.map +1 -1
  80. package/lib/util/gloas.js +25 -3
  81. package/lib/util/gloas.js.map +1 -1
  82. package/package.json +8 -8
  83. package/src/block/index.ts +12 -4
  84. package/src/block/processDepositRequest.ts +50 -5
  85. package/src/block/processParentExecutionPayload.ts +116 -0
  86. package/src/block/processWithdrawals.ts +12 -4
  87. package/src/cache/epochCache.ts +32 -30
  88. package/src/cache/epochTransitionCache.ts +7 -0
  89. package/src/epoch/index.ts +9 -0
  90. package/src/epoch/processPtcWindow.ts +38 -0
  91. package/src/index.ts +20 -2
  92. package/src/signatureSets/executionPayloadEnvelope.ts +6 -2
  93. package/src/signatureSets/index.ts +1 -0
  94. package/src/signatureSets/proposerPreferences.ts +12 -0
  95. package/src/signatureSets/voluntaryExits.ts +5 -2
  96. package/src/slot/upgradeStateToGloas.ts +5 -1
  97. package/src/stateTransition.ts +1 -2
  98. package/src/stateView/beaconStateView.ts +91 -56
  99. package/src/stateView/interface.ts +163 -79
  100. package/src/util/attestation.ts +37 -8
  101. package/src/util/computeAnchorCheckpoint.ts +6 -19
  102. package/src/util/execution.ts +11 -1
  103. package/src/util/gloas.ts +46 -3
  104. package/lib/block/processExecutionPayloadEnvelope.d.ts +0 -9
  105. package/lib/block/processExecutionPayloadEnvelope.d.ts.map +0 -1
  106. package/lib/block/processExecutionPayloadEnvelope.js +0 -102
  107. package/lib/block/processExecutionPayloadEnvelope.js.map +0 -1
  108. package/src/block/processExecutionPayloadEnvelope.ts +0 -170
@@ -0,0 +1,38 @@
1
+ import {MIN_SEED_LOOKAHEAD} from "@lodestar/params";
2
+ import {ssz} from "@lodestar/types";
3
+ import {CachedBeaconStateGloas, EpochTransitionCache} from "../types.js";
4
+ import {computeEpochShuffling} from "../util/epochShuffling.js";
5
+ import {computePayloadTimelinessCommitteesForEpoch} from "../util/seed.js";
6
+
7
+ /**
8
+ * Update the `ptc_window` field in the beacon state by shifting out the oldest epoch's
9
+ * PTC entries and appending newly computed entries for the next lookahead epoch.
10
+ * Stashes the computed PTCs in the transition cache for finalProcessEpoch to shift
11
+ * into the epoch cache without reading from state.
12
+ *
13
+ * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.4/specs/gloas/beacon-chain.md#new-process_ptc_window
14
+ */
15
+ export function processPtcWindow(state: CachedBeaconStateGloas, cache: EpochTransitionCache): void {
16
+ const nextEpoch = state.epochCtx.epoch + MIN_SEED_LOOKAHEAD + 1;
17
+ const nextEpochShuffling =
18
+ cache.nextShuffling ?? computeEpochShuffling(state, cache.nextShufflingActiveIndices, nextEpoch);
19
+ cache.nextShuffling = nextEpochShuffling;
20
+
21
+ const newNextPayloadTimelinessCommittees = computePayloadTimelinessCommitteesForEpoch(
22
+ state,
23
+ nextEpoch,
24
+ nextEpochShuffling.committees,
25
+ state.epochCtx.effectiveBalanceIncrements
26
+ );
27
+
28
+ // Stash for finalProcessEpoch to shift into epoch cache
29
+ cache.nextEpochPayloadTimelinessCommittees = newNextPayloadTimelinessCommittees;
30
+
31
+ // Write shifted window to state: current(N) + next(N+1) + newlyComputed(N+2)
32
+ // From the perspective of upcoming epoch N+1, this is previous + current + next
33
+ state.ptcWindow = ssz.gloas.PtcWindow.toViewDU([
34
+ ...state.epochCtx.payloadTimelinessCommittees,
35
+ ...state.epochCtx.nextPayloadTimelinessCommittees,
36
+ ...newNextPayloadTimelinessCommittees,
37
+ ]);
38
+ }
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
 
@@ -11,7 +11,7 @@ export function getExecutionPayloadEnvelopeSigningRoot(
11
11
  config: BeaconConfig,
12
12
  envelope: gloas.ExecutionPayloadEnvelope
13
13
  ): Uint8Array {
14
- const domain = config.getDomain(envelope.slot, DOMAIN_BEACON_BUILDER);
14
+ const domain = config.getDomain(envelope.payload.slotNumber, DOMAIN_BEACON_BUILDER);
15
15
 
16
16
  return computeSigningRoot(ssz.gloas.ExecutionPayloadEnvelope, envelope, domain);
17
17
  }
@@ -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
@@ -20,6 +20,7 @@ export * from "./executionPayloadEnvelope.js";
20
20
  export * from "./indexedAttestation.js";
21
21
  export * from "./indexedPayloadAttestation.js";
22
22
  export * from "./proposer.js";
23
+ export * from "./proposerPreferences.js";
23
24
  export * from "./proposerSlashings.js";
24
25
  export * from "./randao.js";
25
26
  export * from "./voluntaryExits.js";
@@ -0,0 +1,12 @@
1
+ import {BeaconConfig} from "@lodestar/config";
2
+ import {DOMAIN_PROPOSER_PREFERENCES} from "@lodestar/params";
3
+ import {gloas, ssz} from "@lodestar/types";
4
+ import {computeSigningRoot} from "../util/index.js";
5
+
6
+ export function getProposerPreferencesSigningRoot(
7
+ config: BeaconConfig,
8
+ preferences: gloas.ProposerPreferences
9
+ ): Uint8Array {
10
+ const domain = config.getDomain(preferences.proposalSlot, DOMAIN_PROPOSER_PREFERENCES);
11
+ return computeSigningRoot(ssz.gloas.ProposerPreferences, preferences, domain);
12
+ }
@@ -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);
@@ -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
  }