@lodestar/beacon-node 1.43.0-dev.2870b59b6a → 1.43.0-dev.4fb05c546d

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 (113) hide show
  1. package/lib/api/impl/validator/index.d.ts.map +1 -1
  2. package/lib/api/impl/validator/index.js +4 -3
  3. package/lib/api/impl/validator/index.js.map +1 -1
  4. package/lib/chain/GetBlobsTracker.d.ts +1 -1
  5. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  6. package/lib/chain/GetBlobsTracker.js +1 -2
  7. package/lib/chain/GetBlobsTracker.js.map +1 -1
  8. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
  9. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +2 -4
  10. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
  11. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  12. package/lib/chain/blocks/importBlock.js +23 -31
  13. package/lib/chain/blocks/importBlock.js.map +1 -1
  14. package/lib/chain/blocks/importExecutionPayload.d.ts +1 -1
  15. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  16. package/lib/chain/blocks/importExecutionPayload.js +10 -8
  17. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  18. package/lib/chain/blocks/index.js +1 -1
  19. package/lib/chain/blocks/index.js.map +1 -1
  20. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +3 -0
  21. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  22. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +20 -0
  23. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  24. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -0
  25. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  26. package/lib/chain/blocks/payloadEnvelopeProcessor.js +6 -4
  27. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  28. package/lib/chain/blocks/types.d.ts +1 -1
  29. package/lib/chain/blocks/types.d.ts.map +1 -1
  30. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +14 -0
  31. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -0
  32. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +25 -0
  33. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -0
  34. package/lib/chain/chain.d.ts.map +1 -1
  35. package/lib/chain/chain.js +14 -30
  36. package/lib/chain/chain.js.map +1 -1
  37. package/lib/chain/emitter.d.ts +13 -1
  38. package/lib/chain/emitter.d.ts.map +1 -1
  39. package/lib/chain/emitter.js +5 -0
  40. package/lib/chain/emitter.js.map +1 -1
  41. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  42. package/lib/chain/forkChoice/index.js +12 -4
  43. package/lib/chain/forkChoice/index.js.map +1 -1
  44. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  45. package/lib/chain/prepareNextSlot.js +22 -16
  46. package/lib/chain/prepareNextSlot.js.map +1 -1
  47. package/lib/chain/produceBlock/computeNewStateRoot.d.ts +3 -9
  48. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  49. package/lib/chain/produceBlock/computeNewStateRoot.js +5 -32
  50. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  51. package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -8
  52. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  53. package/lib/chain/produceBlock/produceBlockBody.js +24 -19
  54. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  55. package/lib/chain/regen/errors.d.ts +1 -11
  56. package/lib/chain/regen/errors.d.ts.map +1 -1
  57. package/lib/chain/regen/errors.js +0 -2
  58. package/lib/chain/regen/errors.js.map +1 -1
  59. package/lib/chain/regen/interface.d.ts +6 -11
  60. package/lib/chain/regen/interface.d.ts.map +1 -1
  61. package/lib/chain/regen/queued.d.ts +6 -10
  62. package/lib/chain/regen/queued.d.ts.map +1 -1
  63. package/lib/chain/regen/queued.js +3 -10
  64. package/lib/chain/regen/queued.js.map +1 -1
  65. package/lib/chain/regen/regen.d.ts +0 -5
  66. package/lib/chain/regen/regen.d.ts.map +1 -1
  67. package/lib/chain/regen/regen.js +0 -8
  68. package/lib/chain/regen/regen.js.map +1 -1
  69. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +1 -7
  70. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  71. package/lib/chain/stateCache/persistentCheckpointsCache.js +0 -8
  72. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  73. package/lib/chain/stateCache/types.d.ts +0 -6
  74. package/lib/chain/stateCache/types.d.ts.map +1 -1
  75. package/lib/chain/stateCache/types.js.map +1 -1
  76. package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
  77. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  78. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  79. package/lib/chain/validation/payloadAttestationMessage.js +4 -3
  80. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  81. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  82. package/lib/network/processor/gossipHandlers.js +19 -3
  83. package/lib/network/processor/gossipHandlers.js.map +1 -1
  84. package/lib/node/nodejs.d.ts.map +1 -1
  85. package/lib/node/nodejs.js +4 -2
  86. package/lib/node/nodejs.js.map +1 -1
  87. package/package.json +16 -16
  88. package/src/api/impl/validator/index.ts +6 -5
  89. package/src/chain/GetBlobsTracker.ts +1 -2
  90. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +2 -4
  91. package/src/chain/blocks/importBlock.ts +22 -35
  92. package/src/chain/blocks/importExecutionPayload.ts +11 -7
  93. package/src/chain/blocks/index.ts +1 -1
  94. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +27 -0
  95. package/src/chain/blocks/payloadEnvelopeProcessor.ts +6 -5
  96. package/src/chain/blocks/types.ts +1 -1
  97. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +38 -0
  98. package/src/chain/chain.ts +13 -32
  99. package/src/chain/emitter.ts +12 -0
  100. package/src/chain/forkChoice/index.ts +12 -4
  101. package/src/chain/prepareNextSlot.ts +25 -16
  102. package/src/chain/produceBlock/computeNewStateRoot.ts +6 -43
  103. package/src/chain/produceBlock/produceBlockBody.ts +34 -20
  104. package/src/chain/regen/errors.ts +1 -6
  105. package/src/chain/regen/interface.ts +6 -11
  106. package/src/chain/regen/queued.ts +6 -14
  107. package/src/chain/regen/regen.ts +0 -8
  108. package/src/chain/stateCache/persistentCheckpointsCache.ts +1 -14
  109. package/src/chain/stateCache/types.ts +0 -3
  110. package/src/chain/validation/executionPayloadEnvelope.ts +1 -1
  111. package/src/chain/validation/payloadAttestationMessage.ts +5 -3
  112. package/src/network/processor/gossipHandlers.ts +23 -7
  113. package/src/node/nodejs.ts +4 -2
@@ -19,7 +19,6 @@ import {
19
19
  IBeaconStateView,
20
20
  type IBeaconStateViewBellatrix,
21
21
  computeTimeAtSlot,
22
- isParentBlockFull,
23
22
  isStatePostBellatrix,
24
23
  isStatePostCapella,
25
24
  isStatePostGloas,
@@ -48,7 +47,7 @@ import {
48
47
  fulu,
49
48
  gloas,
50
49
  } from "@lodestar/types";
51
- import {Logger, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
50
+ import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
52
51
  import {ZERO_HASH_HEX} from "../../constants/index.js";
53
52
  import {numToQuantity} from "../../execution/engine/utils.js";
54
53
  import {
@@ -111,12 +110,6 @@ export type ProduceFullGloas = {
111
110
  executionRequests: electra.ExecutionRequests;
112
111
  blobsBundle: BlobsBundle<ForkPostGloas>;
113
112
  cells: fulu.Cell[][];
114
- /**
115
- * Cached payload envelope state root computed during block production.
116
- * This is the state root after running `processExecutionPayloadEnvelope` on the
117
- * post-block state, and later used to construct the `ExecutionPayloadEnvelope`.
118
- */
119
- payloadEnvelopeStateRoot: Root;
120
113
  };
121
114
  export type ProduceFullFulu = {
122
115
  type: BlockType.Full;
@@ -220,11 +213,15 @@ export async function produceBlockBody<T extends BlockType>(
220
213
  });
221
214
 
222
215
  // Get execution payload from EL
216
+ const parentBlockHash = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot))
217
+ ? currentState.latestExecutionPayloadBid.blockHash
218
+ : currentState.latestExecutionPayloadBid.parentBlockHash;
223
219
  const prepareRes = await prepareExecutionPayload(
224
220
  this,
225
221
  this.logger,
226
222
  fork,
227
223
  parentBlockRoot,
224
+ parentBlockHash,
228
225
  safeBlockHash,
229
226
  finalizedBlockHash ?? ZERO_HASH_HEX,
230
227
  currentState,
@@ -261,8 +258,8 @@ export async function produceBlockBody<T extends BlockType>(
261
258
 
262
259
  // Create self-build execution payload bid
263
260
  const bid: gloas.ExecutionPayloadBid = {
264
- parentBlockHash: currentState.latestBlockHash,
265
- parentBlockRoot: parentBlockRoot,
261
+ parentBlockHash,
262
+ parentBlockRoot,
266
263
  blockHash: executionPayload.blockHash,
267
264
  prevRandao: currentState.getRandaoMix(currentState.epoch),
268
265
  feeRecipient: executionPayload.feeRecipient,
@@ -340,6 +337,7 @@ export async function produceBlockBody<T extends BlockType>(
340
337
  this.logger,
341
338
  fork,
342
339
  parentBlockRoot,
340
+ currentState.latestExecutionPayloadHeader.blockHash,
343
341
  safeBlockHash,
344
342
  finalizedBlockHash ?? ZERO_HASH_HEX,
345
343
  currentState,
@@ -448,6 +446,7 @@ export async function produceBlockBody<T extends BlockType>(
448
446
  this.logger,
449
447
  fork,
450
448
  parentBlockRoot,
449
+ currentState.latestExecutionPayloadHeader.blockHash,
451
450
  safeBlockHash,
452
451
  finalizedBlockHash ?? ZERO_HASH_HEX,
453
452
  currentState,
@@ -613,17 +612,17 @@ export async function prepareExecutionPayload(
613
612
  logger: Logger,
614
613
  fork: ForkPostBellatrix,
615
614
  parentBlockRoot: Root,
615
+ parentBlockHash: Bytes32,
616
616
  safeBlockHash: RootHex,
617
617
  finalizedBlockHash: RootHex,
618
618
  state: IBeaconStateViewBellatrix,
619
619
  suggestedFeeRecipient: string
620
620
  ): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
621
- const parentHash = state.latestBlockHash;
622
621
  const timestamp = computeTimeAtSlot(chain.config, state.slot, state.genesisTime);
623
622
  const prevRandao = state.getRandaoMix(state.epoch);
624
623
 
625
624
  const payloadIdCached = chain.executionEngine.payloadIdCache.get({
626
- headBlockHash: toRootHex(parentHash),
625
+ headBlockHash: toRootHex(parentBlockHash),
627
626
  finalizedBlockHash,
628
627
  timestamp: numToQuantity(timestamp),
629
628
  prevRandao: toHex(prevRandao),
@@ -652,12 +651,13 @@ export async function prepareExecutionPayload(
652
651
  prepareState: state,
653
652
  prepareSlot: state.slot,
654
653
  parentBlockRoot,
654
+ parentBlockHash,
655
655
  feeRecipient: suggestedFeeRecipient,
656
656
  });
657
657
 
658
658
  payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
659
659
  fork,
660
- toRootHex(parentHash),
660
+ toRootHex(parentBlockHash),
661
661
  safeBlockHash,
662
662
  finalizedBlockHash,
663
663
  attributes
@@ -709,20 +709,30 @@ export function getPayloadAttributesForSSE(
709
709
  prepareState,
710
710
  prepareSlot,
711
711
  parentBlockRoot,
712
+ parentBlockHash,
712
713
  feeRecipient,
713
- }: {prepareState: IBeaconStateViewBellatrix; prepareSlot: Slot; parentBlockRoot: Root; feeRecipient: string}
714
+ }: {
715
+ prepareState: IBeaconStateViewBellatrix;
716
+ prepareSlot: Slot;
717
+ parentBlockRoot: Root;
718
+ parentBlockHash: Bytes32;
719
+ feeRecipient: string;
720
+ }
714
721
  ): SSEPayloadAttributes {
715
- const parentHash = prepareState.latestBlockHash;
716
722
  const payloadAttributes = preparePayloadAttributes(fork, chain, {
717
723
  prepareState,
718
724
  prepareSlot,
719
725
  parentBlockRoot,
726
+ parentBlockHash,
720
727
  feeRecipient,
721
728
  });
722
729
 
723
730
  let parentBlockNumber: number;
724
731
  if (isForkPostGloas(fork)) {
725
- const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(toRootHex(parentBlockRoot), toRootHex(parentHash));
732
+ const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
733
+ toRootHex(parentBlockRoot),
734
+ toRootHex(parentBlockHash)
735
+ );
726
736
  if (parentBlock?.executionPayloadBlockHash == null) {
727
737
  throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
728
738
  }
@@ -736,7 +746,7 @@ export function getPayloadAttributesForSSE(
736
746
  proposalSlot: prepareSlot,
737
747
  parentBlockNumber,
738
748
  parentBlockRoot,
739
- parentBlockHash: parentHash,
749
+ parentBlockHash,
740
750
  payloadAttributes,
741
751
  };
742
752
  return ssePayloadAttributes;
@@ -751,11 +761,13 @@ function preparePayloadAttributes(
751
761
  prepareState,
752
762
  prepareSlot,
753
763
  parentBlockRoot,
764
+ parentBlockHash,
754
765
  feeRecipient,
755
766
  }: {
756
767
  prepareState: IBeaconStateViewBellatrix;
757
768
  prepareSlot: Slot;
758
769
  parentBlockRoot: Root;
770
+ parentBlockHash: Bytes32;
759
771
  feeRecipient: string;
760
772
  }
761
773
  ): SSEPayloadAttributes["payloadAttributes"] {
@@ -772,13 +784,15 @@ function preparePayloadAttributes(
772
784
  throw new Error("Expected Capella state for withdrawals");
773
785
  }
774
786
 
775
- if (isStatePostGloas(prepareState) && !isParentBlockFull(prepareState)) {
787
+ if (isStatePostGloas(prepareState)) {
788
+ const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
776
789
  // When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
777
790
  // already deducted from CL balances but never credited on the EL (the envelope
778
791
  // was not delivered). The next payload must carry those same withdrawals to
779
792
  // restore CL/EL consistency, otherwise validators permanently lose that balance.
780
- (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
781
- prepareState.payloadExpectedWithdrawals;
793
+ (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals = isExtendingPayload
794
+ ? prepareState.getExpectedWithdrawals().expectedWithdrawals
795
+ : prepareState.payloadExpectedWithdrawals;
782
796
  } else {
783
797
  // withdrawals logic is now fork aware as it changes on electra fork post capella
784
798
  (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
@@ -1,4 +1,3 @@
1
- import {PayloadStatus} from "@lodestar/fork-choice";
2
1
  import {Root, RootHex, Slot} from "@lodestar/types";
3
2
 
4
3
  export enum RegenErrorCode {
@@ -10,8 +9,6 @@ export enum RegenErrorCode {
10
9
  BLOCK_NOT_IN_DB = "REGEN_ERROR_BLOCK_NOT_IN_DB",
11
10
  STATE_TRANSITION_ERROR = "REGEN_ERROR_STATE_TRANSITION_ERROR",
12
11
  INVALID_STATE_ROOT = "REGEN_ERROR_INVALID_STATE_ROOT",
13
- UNEXPECTED_PAYLOAD_STATUS = "REGEN_ERROR_UNEXPECTED_PAYLOAD_STATUS",
14
- INTERNAL_ERROR = "REGEN_ERROR_INTERNAL_ERROR",
15
12
  }
16
13
 
17
14
  export type RegenErrorType =
@@ -22,9 +19,7 @@ export type RegenErrorType =
22
19
  | {code: RegenErrorCode.TOO_MANY_BLOCK_PROCESSED; stateRoot: RootHex | Root}
23
20
  | {code: RegenErrorCode.BLOCK_NOT_IN_DB; blockRoot: RootHex | Root}
24
21
  | {code: RegenErrorCode.STATE_TRANSITION_ERROR; error: Error}
25
- | {code: RegenErrorCode.INVALID_STATE_ROOT; slot: Slot; expected: RootHex; actual: RootHex}
26
- | {code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS; blockRoot: RootHex | Root; payloadStatus: PayloadStatus}
27
- | {code: RegenErrorCode.INTERNAL_ERROR; message: string};
22
+ | {code: RegenErrorCode.INVALID_STATE_ROOT; slot: Slot; expected: RootHex; actual: RootHex};
28
23
 
29
24
  export class RegenError extends Error {
30
25
  type: RegenErrorType;
@@ -2,7 +2,7 @@ import {routes} from "@lodestar/api";
2
2
  import {ProtoBlock} from "@lodestar/fork-choice";
3
3
  import {IBeaconStateView} from "@lodestar/state-transition";
4
4
  import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
5
- import {CheckpointHexPayload} from "../stateCache/types.js";
5
+ import {CheckpointHex} from "../stateCache/types.js";
6
6
 
7
7
  export enum RegenCaller {
8
8
  getDuties = "getDuties",
@@ -40,20 +40,15 @@ export interface IStateRegenerator extends IStateRegeneratorInternal {
40
40
  dumpCacheSummary(): routes.lodestar.StateCacheItem[];
41
41
  getStateSync(stateRoot: RootHex): IBeaconStateView | null;
42
42
  getPreStateSync(block: BeaconBlock): IBeaconStateView | null;
43
- getCheckpointStateOrBytes(cp: CheckpointHexPayload): Promise<IBeaconStateView | Uint8Array | null>;
44
- getCheckpointStateSync(cp: CheckpointHexPayload): IBeaconStateView | null;
43
+ getCheckpointStateOrBytes(cp: CheckpointHex): Promise<IBeaconStateView | Uint8Array | null>;
44
+ getCheckpointStateSync(cp: CheckpointHex): IBeaconStateView | null;
45
45
  getClosestHeadState(head: ProtoBlock): IBeaconStateView | null;
46
46
  pruneOnCheckpoint(finalizedEpoch: Epoch, justifiedEpoch: Epoch, headStateRoot: RootHex): void;
47
47
  pruneOnFinalized(finalizedEpoch: Epoch): void;
48
- processBlockState(blockRootHex: RootHex, postState: IBeaconStateView): void;
49
- processPayloadState(payloadState: IBeaconStateView): void;
50
- /**
51
- * payloadPresent is true if this is payload state, false if block state.
52
- * payloadPresent is always true for pre-gloas.
53
- */
54
- addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView, payloadPresent: boolean): void;
48
+ processState(blockRootHex: RootHex, postState: IBeaconStateView): void;
49
+ addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView): void;
55
50
  updateHeadState(newHead: ProtoBlock, maybeHeadState: IBeaconStateView): void;
56
- updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch, payloadPresent: boolean): number | null;
51
+ updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null;
57
52
  }
58
53
 
59
54
  /**
@@ -5,7 +5,7 @@ import {BeaconBlock, Epoch, RootHex, Slot, isGloasBeaconBlock, phase0} from "@lo
5
5
  import {Logger, toRootHex} from "@lodestar/utils";
6
6
  import {Metrics} from "../../metrics/index.js";
7
7
  import {JobItemQueue} from "../../util/queue/index.js";
8
- import {BlockStateCache, CheckpointHexPayload, CheckpointStateCache} from "../stateCache/types.js";
8
+ import {BlockStateCache, CheckpointHex, CheckpointStateCache} from "../stateCache/types.js";
9
9
  import {RegenError, RegenErrorCode} from "./errors.js";
10
10
  import {
11
11
  IStateRegenerator,
@@ -125,14 +125,14 @@ export class QueuedStateRegenerator implements IStateRegenerator {
125
125
  return null;
126
126
  }
127
127
 
128
- async getCheckpointStateOrBytes(cp: CheckpointHexPayload): Promise<IBeaconStateView | Uint8Array | null> {
128
+ async getCheckpointStateOrBytes(cp: CheckpointHex): Promise<IBeaconStateView | Uint8Array | null> {
129
129
  return this.checkpointStateCache.getStateOrBytes(cp);
130
130
  }
131
131
 
132
132
  /**
133
133
  * Get checkpoint state from cache
134
134
  */
135
- getCheckpointStateSync(cp: CheckpointHexPayload): IBeaconStateView | null {
135
+ getCheckpointStateSync(cp: CheckpointHex): IBeaconStateView | null {
136
136
  return this.checkpointStateCache.get(cp);
137
137
  }
138
138
 
@@ -153,22 +153,14 @@ export class QueuedStateRegenerator implements IStateRegenerator {
153
153
  this.blockStateCache.deleteAllBeforeEpoch(finalizedEpoch);
154
154
  }
155
155
 
156
- processBlockState(blockRootHex: RootHex, postState: IBeaconStateView): void {
156
+ processState(blockRootHex: RootHex, postState: IBeaconStateView): void {
157
157
  this.blockStateCache.add(postState);
158
158
  this.checkpointStateCache.processState(blockRootHex, postState).catch((e) => {
159
159
  this.logger.debug("Error processing block state", {blockRootHex, slot: postState.slot}, e);
160
160
  });
161
161
  }
162
162
 
163
- /**
164
- * Process payload state for caching after importing execution payload.
165
- */
166
- processPayloadState(payloadState: IBeaconStateView): void {
167
- // Add payload state to block state cache (keyed by payload state root)
168
- this.blockStateCache.add(payloadState);
169
- }
170
-
171
- addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView, _payloadPresent: boolean): void {
163
+ addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView): void {
172
164
  this.checkpointStateCache.add(cp, item);
173
165
  }
174
166
 
@@ -205,7 +197,7 @@ export class QueuedStateRegenerator implements IStateRegenerator {
205
197
  }
206
198
  }
207
199
 
208
- updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch, _payloadPresent: boolean): number | null {
200
+ updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null {
209
201
  return this.checkpointStateCache.updatePreComputedCheckpoint(rootHex, epoch);
210
202
  }
211
203
 
@@ -332,11 +332,6 @@ async function processSlotsByCheckpoint(
332
332
  * emitting "checkpoint" events after every epoch processed.
333
333
  *
334
334
  * Stops processing after no more full epochs can be processed.
335
- *
336
- * Output state variant:
337
- * - Post-Gloas: If slots are processed, returns block state (payloadPresent=false).
338
- * If no slots processed, returns preState as-is (preserves variant).
339
- * - Pre-Gloas: Always payloadPresent=true (no block/payload distinction).
340
335
  */
341
336
  export async function processSlotsToNearestCheckpoint(
342
337
  modules: {
@@ -380,9 +375,6 @@ export async function processSlotsToNearestCheckpoint(
380
375
  // This may becomes the "official" checkpoint state if the 1st block of epoch is skipped
381
376
  const checkpointState = postState;
382
377
  const cp = getCheckpointFromState(checkpointState);
383
- // processSlots() only does epoch transitions, never processes payloads
384
- // Pre-Gloas: payloadPresent is always true (execution payload embedded in block)
385
- // Post-Gloas: result is a block state (payloadPresent=false)
386
378
  checkpointStateCache.add(cp, checkpointState);
387
379
  // consumers should not mutate state ever
388
380
  emitter?.emit(ChainEvent.checkpoint, cp, checkpointState);
@@ -9,7 +9,7 @@ import {IClock} from "../../util/clock.js";
9
9
  import {serializeState} from "../serializeState.js";
10
10
  import {CPStateDatastore, DatastoreKey} from "./datastore/index.js";
11
11
  import {MapTracker} from "./mapMetrics.js";
12
- import {BlockStateCache, CacheItemType, CheckpointHex, CheckpointHexPayload, CheckpointStateCache} from "./types.js";
12
+ import {BlockStateCache, CacheItemType, CheckpointHex, CheckpointStateCache} from "./types.js";
13
13
 
14
14
  export type PersistentCheckpointStateCacheOpts = {
15
15
  /** Keep max n state epochs in memory, persist the rest to disk */
@@ -843,19 +843,6 @@ export function toCheckpointHex(checkpoint: phase0.Checkpoint): CheckpointHex {
843
843
  };
844
844
  }
845
845
 
846
- /** TODO GLOAS: remove after rolling back regen dual-state changes */
847
- export function fcCheckpointToHexPayload(checkpoint: {
848
- epoch: Epoch;
849
- rootHex: RootHex;
850
- payloadStatus?: number;
851
- }): CheckpointHexPayload {
852
- return {
853
- epoch: checkpoint.epoch,
854
- rootHex: checkpoint.rootHex,
855
- payloadPresent: true,
856
- };
857
- }
858
-
859
846
  export function toCheckpointKey(cp: CheckpointHex): string {
860
847
  return `${cp.rootHex}:${cp.epoch}`;
861
848
  }
@@ -4,9 +4,6 @@ import {Epoch, RootHex, phase0} from "@lodestar/types";
4
4
 
5
5
  export type CheckpointHex = {epoch: Epoch; rootHex: RootHex};
6
6
 
7
- /** TODO GLOAS: payloadPresent is ignored — remove after rolling back regen dual-state changes */
8
- export type CheckpointHexPayload = {epoch: Epoch; rootHex: RootHex; payloadPresent: boolean};
9
-
10
7
  /**
11
8
  * Lodestar currently keeps two state caches around.
12
9
  *
@@ -107,7 +107,7 @@ async function validateExecutionPayloadEnvelope(
107
107
  });
108
108
  }
109
109
 
110
- // Get the post block state which is the pre-payload state to verify the builder's signature.
110
+ // Get the block state to verify the builder's signature.
111
111
  const blockState = await chain.regen
112
112
  .getState(block.stateRoot, RegenCaller.validateGossipPayloadEnvelope)
113
113
  .catch(() => {
@@ -18,7 +18,8 @@ export async function validateApiPayloadAttestationMessage(
18
18
  chain: IBeaconChain,
19
19
  payloadAttestationMessage: gloas.PayloadAttestationMessage
20
20
  ): Promise<PayloadAttestationValidationResult> {
21
- return validatePayloadAttestationMessage(chain, payloadAttestationMessage);
21
+ const prioritizeBls = true;
22
+ return validatePayloadAttestationMessage(chain, payloadAttestationMessage, prioritizeBls);
22
23
  }
23
24
 
24
25
  export async function validateGossipPayloadAttestationMessage(
@@ -30,7 +31,8 @@ export async function validateGossipPayloadAttestationMessage(
30
31
 
31
32
  async function validatePayloadAttestationMessage(
32
33
  chain: IBeaconChain,
33
- payloadAttestationMessage: gloas.PayloadAttestationMessage
34
+ payloadAttestationMessage: gloas.PayloadAttestationMessage,
35
+ prioritizeBls = false
34
36
  ): Promise<PayloadAttestationValidationResult> {
35
37
  const {data, validatorIndex} = payloadAttestationMessage;
36
38
  const epoch = computeEpochAtSlot(data.slot);
@@ -102,7 +104,7 @@ async function validatePayloadAttestationMessage(
102
104
  payloadAttestationMessage.signature
103
105
  );
104
106
 
105
- if (!(await chain.bls.verifySignatureSets([signatureSet]))) {
107
+ if (!(await chain.bls.verifySignatureSets([signatureSet], {batchable: true, priority: prioritizeBls}))) {
106
108
  throw new PayloadAttestationError(GossipAction.REJECT, {
107
109
  code: PayloadAttestationErrorCode.INVALID_SIGNATURE,
108
110
  });
@@ -745,13 +745,29 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
745
745
  });
746
746
  }
747
747
 
748
- chain.processExecutionPayload(payloadInput, {validSignature: true}).catch((e) => {
749
- chain.logger.debug(
750
- "Error processing execution payload from gossip data column",
751
- {slot: dataColumnSlot, root: payloadInput.blockRootHex},
752
- e as Error
753
- );
754
- });
748
+ // NOTE: we do NOT call chain.processExecutionPayload here. That is triggered only by
749
+ // envelope arrival (gossip or API). An in-flight importExecutionPayload is awaiting
750
+ // payloadInput.waitForAllData(); addColumn above will resolve it once hasAllData flips.
751
+
752
+ if (!payloadInput.isComplete()) {
753
+ const cutoffTimeMs = getCutoffTimeMs(chain, dataColumnSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
754
+ // do not await here to not delay gossip validation
755
+ payloadInput.waitForEnvelopeAndAllData(cutoffTimeMs).catch((_e) => {
756
+ chain.logger.debug(
757
+ "Waited for envelope and data after receiving gossip column. Cut-off reached so emitting incompletePayloadEnvelope",
758
+ {
759
+ dataColumnIndex: index,
760
+ ...payloadInputMeta,
761
+ }
762
+ );
763
+ // TODO GLOAS: UnknownBlockSync to handle this event
764
+ chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
765
+ payloadInput,
766
+ peer: peerIdStr,
767
+ source: BlockInputSource.gossip,
768
+ });
769
+ });
770
+ }
755
771
  } else {
756
772
  if (config.getForkSeq(dataColumnSlot) < ForkSeq.fulu) {
757
773
  throw new GossipActionError(GossipAction.REJECT, {code: "PRE_FULU_BLOCK"});
@@ -6,7 +6,7 @@ import {BeaconApiMethods} from "@lodestar/api/beacon/server";
6
6
  import {BeaconConfig} from "@lodestar/config";
7
7
  import type {LoggerNode} from "@lodestar/logger/node";
8
8
  import {ZERO_HASH_HEX} from "@lodestar/params";
9
- import {IBeaconStateView, PubkeyCache, isStatePostBellatrix} from "@lodestar/state-transition";
9
+ import {IBeaconStateView, PubkeyCache, isStatePostBellatrix, isStatePostGloas} from "@lodestar/state-transition";
10
10
  import {phase0} from "@lodestar/types";
11
11
  import {sleep, toRootHex} from "@lodestar/utils";
12
12
  import {ProcessShutdownCallback} from "@lodestar/validator";
@@ -223,7 +223,9 @@ export class BeaconNode {
223
223
  if (opts.executionEngine.mode === "mock") {
224
224
  const eth1BlockHash =
225
225
  isStatePostBellatrix(anchorState) && anchorState.isExecutionStateType
226
- ? toRootHex(anchorState.latestBlockHash)
226
+ ? isStatePostGloas(anchorState)
227
+ ? toRootHex(anchorState.latestBlockHash)
228
+ : toRootHex(anchorState.latestExecutionPayloadHeader.blockHash)
227
229
  : undefined;
228
230
  executionEngineOpts = {
229
231
  ...opts.executionEngine,