@lodestar/beacon-node 1.42.0-dev.78c54f483b → 1.42.0-dev.7bdb87e586

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 (252) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +24 -12
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +4 -0
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  8. package/lib/api/impl/beacon/state/index.js +13 -10
  9. package/lib/api/impl/beacon/state/index.js.map +1 -1
  10. package/lib/api/impl/debug/index.js.map +1 -1
  11. package/lib/api/impl/lodestar/index.d.ts.map +1 -1
  12. package/lib/api/impl/lodestar/index.js +4 -0
  13. package/lib/api/impl/lodestar/index.js.map +1 -1
  14. package/lib/api/impl/validator/index.d.ts.map +1 -1
  15. package/lib/api/impl/validator/index.js +7 -1
  16. package/lib/api/impl/validator/index.js.map +1 -1
  17. package/lib/chain/ColumnReconstructionTracker.d.ts +2 -1
  18. package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
  19. package/lib/chain/ColumnReconstructionTracker.js +5 -5
  20. package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
  21. package/lib/chain/GetBlobsTracker.d.ts +2 -1
  22. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  23. package/lib/chain/GetBlobsTracker.js +14 -12
  24. package/lib/chain/GetBlobsTracker.js.map +1 -1
  25. package/lib/chain/blocks/blockInput/blockInput.d.ts +5 -5
  26. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  27. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  28. package/lib/chain/blocks/blockInput/types.d.ts +4 -4
  29. package/lib/chain/blocks/blockInput/types.d.ts.map +1 -1
  30. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  31. package/lib/chain/blocks/importBlock.js +19 -5
  32. package/lib/chain/blocks/importBlock.js.map +1 -1
  33. package/lib/chain/blocks/importExecutionPayload.d.ts +10 -8
  34. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  35. package/lib/chain/blocks/importExecutionPayload.js +67 -39
  36. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  37. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +14 -6
  38. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  39. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +33 -2
  40. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  41. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +2 -1
  42. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  43. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  44. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +3 -2
  45. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  46. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  47. package/lib/chain/blocks/verifyBlocksSignatures.js +4 -2
  48. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  49. package/lib/chain/chain.d.ts +3 -2
  50. package/lib/chain/chain.d.ts.map +1 -1
  51. package/lib/chain/chain.js +64 -24
  52. package/lib/chain/chain.js.map +1 -1
  53. package/lib/chain/emitter.d.ts +29 -7
  54. package/lib/chain/emitter.d.ts.map +1 -1
  55. package/lib/chain/emitter.js +12 -3
  56. package/lib/chain/emitter.js.map +1 -1
  57. package/lib/chain/errors/dataColumnSidecarError.d.ts +31 -1
  58. package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
  59. package/lib/chain/errors/dataColumnSidecarError.js +7 -0
  60. package/lib/chain/errors/dataColumnSidecarError.js.map +1 -1
  61. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  62. package/lib/chain/forkChoice/index.js +10 -8
  63. package/lib/chain/forkChoice/index.js.map +1 -1
  64. package/lib/chain/interface.d.ts +4 -2
  65. package/lib/chain/interface.d.ts.map +1 -1
  66. package/lib/chain/lightClient/index.d.ts +2 -2
  67. package/lib/chain/lightClient/index.d.ts.map +1 -1
  68. package/lib/chain/lightClient/index.js +7 -0
  69. package/lib/chain/lightClient/index.js.map +1 -1
  70. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  71. package/lib/chain/opPools/aggregatedAttestationPool.js +5 -2
  72. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  73. package/lib/chain/opPools/executionPayloadBidPool.d.ts +2 -2
  74. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
  75. package/lib/chain/opPools/executionPayloadBidPool.js +2 -2
  76. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
  77. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  78. package/lib/chain/prepareNextSlot.js +7 -1
  79. package/lib/chain/prepareNextSlot.js.map +1 -1
  80. package/lib/chain/produceBlock/computeNewStateRoot.d.ts +2 -2
  81. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  82. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  83. package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -3
  84. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  85. package/lib/chain/produceBlock/produceBlockBody.js +10 -1
  86. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  87. package/lib/chain/seenCache/seenGossipBlockInput.d.ts +1 -1
  88. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  89. package/lib/chain/seenCache/seenGossipBlockInput.js +2 -2
  90. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  91. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +1 -1
  92. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  93. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +2 -2
  94. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  95. package/lib/chain/validation/block.d.ts.map +1 -1
  96. package/lib/chain/validation/block.js +2 -2
  97. package/lib/chain/validation/block.js.map +1 -1
  98. package/lib/chain/validation/dataColumnSidecar.d.ts +11 -4
  99. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  100. package/lib/chain/validation/dataColumnSidecar.js +184 -5
  101. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  102. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  103. package/lib/chain/validation/executionPayloadBid.js +7 -4
  104. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  105. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  106. package/lib/chain/validation/executionPayloadEnvelope.js +4 -1
  107. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  108. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  109. package/lib/chain/validation/payloadAttestationMessage.js +4 -1
  110. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  111. package/lib/chain/validation/syncCommittee.d.ts.map +1 -1
  112. package/lib/chain/validation/syncCommittee.js +4 -0
  113. package/lib/chain/validation/syncCommittee.js.map +1 -1
  114. package/lib/chain/validation/syncCommitteeContributionAndProof.js +4 -1
  115. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  116. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  117. package/lib/chain/validatorMonitor.js +3 -3
  118. package/lib/chain/validatorMonitor.js.map +1 -1
  119. package/lib/db/buckets.d.ts +2 -2
  120. package/lib/db/buckets.d.ts.map +1 -1
  121. package/lib/db/buckets.js +2 -2
  122. package/lib/db/buckets.js.map +1 -1
  123. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  124. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  125. package/lib/db/repositories/dataColumnSidecar.d.ts.map +1 -1
  126. package/lib/db/repositories/dataColumnSidecar.js +4 -2
  127. package/lib/db/repositories/dataColumnSidecar.js.map +1 -1
  128. package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
  129. package/lib/db/repositories/dataColumnSidecarArchive.js +4 -2
  130. package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
  131. package/lib/metrics/metrics/lodestar.d.ts +20 -0
  132. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  133. package/lib/metrics/metrics/lodestar.js +33 -0
  134. package/lib/metrics/metrics/lodestar.js.map +1 -1
  135. package/lib/network/interface.d.ts +3 -2
  136. package/lib/network/interface.d.ts.map +1 -1
  137. package/lib/network/libp2p/index.d.ts.map +1 -1
  138. package/lib/network/libp2p/index.js +19 -13
  139. package/lib/network/libp2p/index.js.map +1 -1
  140. package/lib/network/network.d.ts +3 -2
  141. package/lib/network/network.d.ts.map +1 -1
  142. package/lib/network/network.js +3 -0
  143. package/lib/network/network.js.map +1 -1
  144. package/lib/network/options.d.ts.map +1 -1
  145. package/lib/network/options.js +7 -2
  146. package/lib/network/options.js.map +1 -1
  147. package/lib/network/processor/extractSlotRootFns.d.ts +1 -1
  148. package/lib/network/processor/extractSlotRootFns.d.ts.map +1 -1
  149. package/lib/network/processor/extractSlotRootFns.js +25 -5
  150. package/lib/network/processor/extractSlotRootFns.js.map +1 -1
  151. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  152. package/lib/network/processor/gossipHandlers.js +260 -73
  153. package/lib/network/processor/gossipHandlers.js.map +1 -1
  154. package/lib/network/processor/index.d.ts +11 -1
  155. package/lib/network/processor/index.d.ts.map +1 -1
  156. package/lib/network/processor/index.js +234 -22
  157. package/lib/network/processor/index.js.map +1 -1
  158. package/lib/network/reqresp/types.d.ts +3 -3
  159. package/lib/network/reqresp/types.d.ts.map +1 -1
  160. package/lib/network/reqresp/types.js +9 -3
  161. package/lib/network/reqresp/types.js.map +1 -1
  162. package/lib/node/nodejs.d.ts.map +1 -1
  163. package/lib/node/nodejs.js +4 -1
  164. package/lib/node/nodejs.js.map +1 -1
  165. package/lib/node/notifier.d.ts.map +1 -1
  166. package/lib/node/notifier.js +2 -2
  167. package/lib/node/notifier.js.map +1 -1
  168. package/lib/sync/unknownBlock.js +2 -2
  169. package/lib/sync/unknownBlock.js.map +1 -1
  170. package/lib/sync/utils/downloadByRange.d.ts +3 -3
  171. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  172. package/lib/sync/utils/downloadByRange.js +4 -2
  173. package/lib/sync/utils/downloadByRange.js.map +1 -1
  174. package/lib/sync/utils/downloadByRoot.d.ts +3 -3
  175. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  176. package/lib/sync/utils/downloadByRoot.js +10 -5
  177. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  178. package/lib/util/blobs.d.ts +3 -3
  179. package/lib/util/blobs.d.ts.map +1 -1
  180. package/lib/util/blobs.js +21 -10
  181. package/lib/util/blobs.js.map +1 -1
  182. package/lib/util/dataColumns.d.ts +18 -11
  183. package/lib/util/dataColumns.d.ts.map +1 -1
  184. package/lib/util/dataColumns.js +51 -17
  185. package/lib/util/dataColumns.js.map +1 -1
  186. package/lib/util/execution.d.ts +6 -2
  187. package/lib/util/execution.d.ts.map +1 -1
  188. package/lib/util/execution.js +49 -25
  189. package/lib/util/execution.js.map +1 -1
  190. package/lib/util/sszBytes.d.ts +25 -1
  191. package/lib/util/sszBytes.d.ts.map +1 -1
  192. package/lib/util/sszBytes.js +189 -2
  193. package/lib/util/sszBytes.js.map +1 -1
  194. package/package.json +15 -15
  195. package/src/api/impl/beacon/blocks/index.ts +32 -15
  196. package/src/api/impl/beacon/pool/index.ts +4 -0
  197. package/src/api/impl/beacon/state/index.ts +15 -15
  198. package/src/api/impl/debug/index.ts +2 -2
  199. package/src/api/impl/lodestar/index.ts +4 -0
  200. package/src/api/impl/validator/index.ts +7 -0
  201. package/src/chain/ColumnReconstructionTracker.ts +6 -5
  202. package/src/chain/GetBlobsTracker.ts +14 -12
  203. package/src/chain/blocks/blockInput/blockInput.ts +8 -8
  204. package/src/chain/blocks/blockInput/types.ts +4 -4
  205. package/src/chain/blocks/importBlock.ts +29 -8
  206. package/src/chain/blocks/importExecutionPayload.ts +72 -42
  207. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +53 -12
  208. package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
  209. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +2 -1
  210. package/src/chain/blocks/verifyBlocksSignatures.ts +9 -2
  211. package/src/chain/chain.ts +73 -28
  212. package/src/chain/emitter.ts +25 -7
  213. package/src/chain/errors/dataColumnSidecarError.ts +32 -1
  214. package/src/chain/forkChoice/index.ts +11 -8
  215. package/src/chain/interface.ts +4 -2
  216. package/src/chain/lightClient/index.ts +15 -3
  217. package/src/chain/opPools/aggregatedAttestationPool.ts +6 -1
  218. package/src/chain/opPools/executionPayloadBidPool.ts +3 -3
  219. package/src/chain/prepareNextSlot.ts +8 -0
  220. package/src/chain/produceBlock/computeNewStateRoot.ts +2 -1
  221. package/src/chain/produceBlock/produceBlockBody.ts +25 -5
  222. package/src/chain/seenCache/seenGossipBlockInput.ts +2 -2
  223. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +2 -2
  224. package/src/chain/validation/block.ts +2 -1
  225. package/src/chain/validation/dataColumnSidecar.ts +230 -7
  226. package/src/chain/validation/executionPayloadBid.ts +7 -3
  227. package/src/chain/validation/executionPayloadEnvelope.ts +8 -1
  228. package/src/chain/validation/payloadAttestationMessage.ts +4 -0
  229. package/src/chain/validation/syncCommittee.ts +5 -1
  230. package/src/chain/validation/syncCommitteeContributionAndProof.ts +5 -1
  231. package/src/chain/validatorMonitor.ts +3 -2
  232. package/src/db/buckets.ts +2 -2
  233. package/src/db/repositories/dataColumnSidecar.ts +4 -2
  234. package/src/db/repositories/dataColumnSidecarArchive.ts +4 -2
  235. package/src/metrics/metrics/lodestar.ts +34 -0
  236. package/src/network/interface.ts +3 -2
  237. package/src/network/libp2p/index.ts +21 -15
  238. package/src/network/network.ts +7 -4
  239. package/src/network/options.ts +7 -2
  240. package/src/network/processor/extractSlotRootFns.ts +32 -6
  241. package/src/network/processor/gossipHandlers.ts +325 -86
  242. package/src/network/processor/index.ts +304 -22
  243. package/src/network/reqresp/types.ts +13 -5
  244. package/src/node/nodejs.ts +5 -2
  245. package/src/node/notifier.ts +7 -2
  246. package/src/sync/unknownBlock.ts +3 -3
  247. package/src/sync/utils/downloadByRange.ts +9 -7
  248. package/src/sync/utils/downloadByRoot.ts +16 -12
  249. package/src/util/blobs.ts +35 -15
  250. package/src/util/dataColumns.ts +69 -25
  251. package/src/util/execution.ts +49 -30
  252. package/src/util/sszBytes.ts +245 -3
@@ -21,7 +21,7 @@ import {
21
21
  isForkPostElectra,
22
22
  } from "@lodestar/params";
23
23
  import {
24
- IBeaconStateView,
24
+ type IBeaconStateViewAltair,
25
25
  computeStartSlotAtEpoch,
26
26
  computeSyncPeriodAtEpoch,
27
27
  computeSyncPeriodAtSlot,
@@ -260,7 +260,11 @@ export class LightClientServer {
260
260
  * - Persist state witness
261
261
  * - Use block's syncAggregate
262
262
  */
263
- onImportBlockHead(block: BeaconBlock<ForkPostAltair>, postState: IBeaconStateView, parentBlockSlot: Slot): void {
263
+ onImportBlockHead(
264
+ block: BeaconBlock<ForkPostAltair>,
265
+ postState: IBeaconStateViewAltair,
266
+ parentBlockSlot: Slot
267
+ ): void {
264
268
  // TEMP: To disable this functionality for fork_choice spec tests.
265
269
  // Since the tests have deep-reorgs attested data is not available often printing lots of error logs.
266
270
  // While this function is only called for head blocks, best to disable.
@@ -268,6 +272,14 @@ export class LightClientServer {
268
272
  return;
269
273
  }
270
274
 
275
+ // TODO GLOAS: Light client updates for gloas are not yet updated in the spec.
276
+ // The block body no longer contains execution payload, so `blockToLightClientHeader`
277
+ // cannot construct a header from a gloas block. Skip all light client processing
278
+ // for post-gloas blocks, revisit once there is a spec for it.
279
+ if (this.config.getForkSeq(block.slot) >= ForkSeq.gloas) {
280
+ return;
281
+ }
282
+
271
283
  // What is the syncAggregate signing?
272
284
  // From the state-transition
273
285
  // ```
@@ -396,7 +408,7 @@ export class LightClientServer {
396
408
 
397
409
  private async persistPostBlockImportData(
398
410
  block: BeaconBlock<ForkPostAltair>,
399
- postState: IBeaconStateView,
411
+ postState: IBeaconStateViewAltair,
400
412
  parentBlockSlot: Slot
401
413
  ): Promise<void> {
402
414
  const blockSlot = block.slot;
@@ -26,6 +26,8 @@ import {
26
26
  computeSlotsSinceEpochStart,
27
27
  computeStartSlotAtEpoch,
28
28
  getAttestationParticipationStatus,
29
+ isStatePostAltair,
30
+ isStatePostGloas,
29
31
  } from "@lodestar/state-transition";
30
32
  import {Attestation, Epoch, RootHex, Slot, electra, isElectraAttestation, phase0, ssz} from "@lodestar/types";
31
33
  import {MapDef, assert, toRootHex} from "@lodestar/utils";
@@ -359,7 +361,7 @@ export class AggregatedAttestationPool {
359
361
  inclusionDistance,
360
362
  stateEpoch,
361
363
  rootCache,
362
- ForkSeq[fork] >= ForkSeq.gloas ? state.executionPayloadAvailability : null
364
+ isStatePostGloas(state) ? state.executionPayloadAvailability : null
363
365
  );
364
366
 
365
367
  const weight =
@@ -742,6 +744,9 @@ export function getNotSeenValidatorsFn(
742
744
  if (config.getForkName(stateSlot) === ForkName.phase0) {
743
745
  throw new Error("getNotSeenValidatorsFn is not supported phase0 state");
744
746
  }
747
+ if (!isStatePostAltair(state)) {
748
+ throw new Error("Expected Altair state for participation tracking");
749
+ }
745
750
 
746
751
  // altair and future forks
747
752
  // Get attestations to be included in an altair block.
@@ -59,13 +59,13 @@ export class ExecutionPayloadBidPool {
59
59
  }
60
60
 
61
61
  /**
62
- * Return the highest-value bid matching slot, parent block root, and parent block hash.
62
+ * Return the highest-value bid matching slot, parent block hash, and parent block root.
63
63
  * Used for gossip validation and block production.
64
64
  */
65
65
  getBestBid(
66
- parentBlockRoot: BlockRootHex,
66
+ slot: Slot,
67
67
  parentBlockHash: BlockHashHex,
68
- slot: Slot
68
+ parentBlockRoot: BlockRootHex
69
69
  ): gloas.ExecutionPayloadBid | null {
70
70
  const bidByParentHash = this.bidByParentHashByParentRootBySlot.get(slot)?.get(parentBlockRoot);
71
71
  return bidByParentHash?.get(parentBlockHash) ?? null;
@@ -7,6 +7,7 @@ import {
7
7
  StateHashTreeRootSource,
8
8
  computeEpochAtSlot,
9
9
  computeTimeAtSlot,
10
+ isStatePostBellatrix,
10
11
  } from "@lodestar/state-transition";
11
12
  import {Slot} from "@lodestar/types";
12
13
  import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils";
@@ -159,6 +160,9 @@ export class PrepareNextSlotScheduler {
159
160
  const preparationTime =
160
161
  computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
161
162
  this.metrics?.blockPayload.payloadAdvancePrepTime.observe(preparationTime);
163
+ if (!isStatePostBellatrix(updatedPrepareState)) {
164
+ throw new Error("Expected Bellatrix state for payload preparation");
165
+ }
162
166
 
163
167
  const safeBlockHash = getSafeExecutionBlockHash(this.chain.forkChoice);
164
168
  const finalizedBlockHash =
@@ -183,6 +187,10 @@ export class PrepareNextSlotScheduler {
183
187
  });
184
188
  }
185
189
 
190
+ if (!isStatePostBellatrix(updatedPrepareState)) {
191
+ throw new Error("Expected Bellatrix state for payload attributes");
192
+ }
193
+
186
194
  this.computeStateHashTreeRoot(updatedPrepareState, isEpochTransition);
187
195
 
188
196
  // If emitPayloadAttributes is true emit a SSE payloadAttributes event
@@ -3,6 +3,7 @@ import {
3
3
  ExecutionPayloadStatus,
4
4
  G2_POINT_AT_INFINITY,
5
5
  IBeaconStateView,
6
+ IBeaconStateViewGloas,
6
7
  StateHashTreeRootSource,
7
8
  } from "@lodestar/state-transition";
8
9
  import {BeaconBlock, BlindedBeaconBlock, Gwei, Root, gloas} from "@lodestar/types";
@@ -60,7 +61,7 @@ export function computeNewStateRoot(
60
61
  */
61
62
  export function computeEnvelopeStateRoot(
62
63
  metrics: Metrics | null,
63
- postBlockState: IBeaconStateView,
64
+ postBlockState: IBeaconStateViewGloas,
64
65
  envelope: gloas.ExecutionPayloadEnvelope
65
66
  ): Root {
66
67
  const signedEnvelope: gloas.SignedExecutionPayloadEnvelope = {
@@ -14,7 +14,15 @@ import {
14
14
  isForkPostBellatrix,
15
15
  isForkPostGloas,
16
16
  } from "@lodestar/params";
17
- import {G2_POINT_AT_INFINITY, IBeaconStateView, computeTimeAtSlot} from "@lodestar/state-transition";
17
+ import {
18
+ G2_POINT_AT_INFINITY,
19
+ IBeaconStateView,
20
+ type IBeaconStateViewBellatrix,
21
+ computeTimeAtSlot,
22
+ isStatePostBellatrix,
23
+ isStatePostCapella,
24
+ isStatePostGloas,
25
+ } from "@lodestar/state-transition";
18
26
  import {
19
27
  BLSPubkey,
20
28
  BLSSignature,
@@ -191,6 +199,10 @@ export async function produceBlockBody<T extends BlockType>(
191
199
  this.logger.verbose("Producing beacon block body", logMeta);
192
200
 
193
201
  if (isForkPostGloas(fork)) {
202
+ if (!isStatePostGloas(currentState)) {
203
+ throw new Error("Expected Gloas state for Gloas block production");
204
+ }
205
+
194
206
  // TODO GLOAS: support non self-building here, the block type differentiation between
195
207
  // full and blinded no longer makes sense in gloas, it might be a good idea to move
196
208
  // this into a completely separate function and have pre/post gloas more separated
@@ -297,6 +309,10 @@ export async function produceBlockBody<T extends BlockType>(
297
309
  shouldOverrideBuilder,
298
310
  });
299
311
  } else if (isForkPostBellatrix(fork)) {
312
+ if (!isStatePostBellatrix(currentState)) {
313
+ throw new Error("Expected Bellatrix state for execution block production");
314
+ }
315
+
300
316
  const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
301
317
  const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
302
318
  const feeRecipient = requestedFeeRecipient ?? this.beaconProposerCache.getOrDefault(proposerIndex);
@@ -598,7 +614,7 @@ export async function prepareExecutionPayload(
598
614
  parentBlockRoot: Root,
599
615
  safeBlockHash: RootHex,
600
616
  finalizedBlockHash: RootHex,
601
- state: IBeaconStateView,
617
+ state: IBeaconStateViewBellatrix,
602
618
  suggestedFeeRecipient: string
603
619
  ): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
604
620
  const parentHash = state.latestBlockHash;
@@ -666,7 +682,7 @@ async function prepareExecutionPayloadHeader(
666
682
  config: ChainForkConfig;
667
683
  },
668
684
  fork: ForkPostBellatrix,
669
- state: IBeaconStateView,
685
+ state: IBeaconStateViewBellatrix,
670
686
  proposerPubKey: BLSPubkey
671
687
  ): Promise<{
672
688
  header: ExecutionPayloadHeader;
@@ -693,7 +709,7 @@ export function getPayloadAttributesForSSE(
693
709
  prepareSlot,
694
710
  parentBlockRoot,
695
711
  feeRecipient,
696
- }: {prepareState: IBeaconStateView; prepareSlot: Slot; parentBlockRoot: Root; feeRecipient: string}
712
+ }: {prepareState: IBeaconStateViewBellatrix; prepareSlot: Slot; parentBlockRoot: Root; feeRecipient: string}
697
713
  ): SSEPayloadAttributes {
698
714
  const parentHash = prepareState.latestBlockHash;
699
715
  const payloadAttributes = preparePayloadAttributes(fork, chain, {
@@ -736,7 +752,7 @@ function preparePayloadAttributes(
736
752
  parentBlockRoot,
737
753
  feeRecipient,
738
754
  }: {
739
- prepareState: IBeaconStateView;
755
+ prepareState: IBeaconStateViewBellatrix;
740
756
  prepareSlot: Slot;
741
757
  parentBlockRoot: Root;
742
758
  feeRecipient: string;
@@ -751,6 +767,10 @@ function preparePayloadAttributes(
751
767
  };
752
768
 
753
769
  if (ForkSeq[fork] >= ForkSeq.capella) {
770
+ if (!isStatePostCapella(prepareState)) {
771
+ throw new Error("Expected Capella state for withdrawals");
772
+ }
773
+
754
774
  // withdrawals logic is now fork aware as it changes on electra fork post capella
755
775
  (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
756
776
  prepareState.getExpectedWithdrawals().expectedWithdrawals;
@@ -149,8 +149,8 @@ export class SeenBlockInput {
149
149
  });
150
150
  }
151
151
 
152
- has(rootHex: RootHex): boolean {
153
- return this.blockInputs.has(rootHex);
152
+ hasBlock(rootHex: RootHex): boolean {
153
+ return this.blockInputs.get(rootHex)?.hasBlock() ?? false;
154
154
  }
155
155
 
156
156
  get(rootHex: RootHex): IBlockInput | undefined {
@@ -84,8 +84,8 @@ export class SeenPayloadEnvelopeInput {
84
84
  return this.payloadInputs.get(blockRootHex);
85
85
  }
86
86
 
87
- has(blockRootHex: RootHex): boolean {
88
- return this.payloadInputs.has(blockRootHex);
87
+ hasPayload(blockRootHex: RootHex): boolean {
88
+ return this.payloadInputs.get(blockRootHex)?.hasPayloadEnvelope() ?? false;
89
89
  }
90
90
 
91
91
  prune(blockRootHex: RootHex): void {
@@ -6,6 +6,7 @@ import {
6
6
  computeTimeAtSlot,
7
7
  getBlockProposerSignatureSet,
8
8
  isExecutionBlockBodyType,
9
+ isStatePostBellatrix,
9
10
  } from "@lodestar/state-transition";
10
11
  import {SignedBeaconBlock, deneb, gloas, isGloasBeaconBlock} from "@lodestar/types";
11
12
  import {byteArrayEquals, sleep, toRootHex} from "@lodestar/utils";
@@ -174,7 +175,7 @@ export async function validateGossipBlock(
174
175
  if (isForkPostBellatrix(fork) && !isForkPostGloas(fork)) {
175
176
  if (!isExecutionBlockBodyType(block.body)) throw Error("Not execution block body type");
176
177
  const executionPayload = block.body.executionPayload;
177
- if (blockState.isExecutionStateType && blockState.isExecutionEnabled(block)) {
178
+ if (isStatePostBellatrix(blockState) && blockState.isExecutionStateType && blockState.isExecutionEnabled(block)) {
178
179
  const expectedTimestamp = computeTimeAtSlot(config, blockSlot, chain.genesisTime);
179
180
  if (executionPayload.timestamp !== computeTimeAtSlot(config, blockSlot, chain.genesisTime)) {
180
181
  throw new BlockGossipError(GossipAction.REJECT, {
@@ -10,11 +10,13 @@ import {
10
10
  getBlockHeaderProposerSignatureSetByHeaderSlot,
11
11
  getBlockHeaderProposerSignatureSetByParentStateSlot,
12
12
  } from "@lodestar/state-transition";
13
- import {DataColumnSidecar, Root, Slot, SubnetID, fulu, ssz} from "@lodestar/types";
13
+ import {DataColumnSidecar, Root, Slot, SubnetID, fulu, gloas, ssz} from "@lodestar/types";
14
14
  import {byteArrayEquals, toRootHex, verifyMerkleBranch} from "@lodestar/utils";
15
15
  import {BeaconMetrics} from "../../metrics/metrics/beacon.js";
16
16
  import {Metrics} from "../../metrics/metrics.js";
17
+ import {getDataColumnSidecarSlot} from "../../util/dataColumns.js";
17
18
  import {kzg} from "../../util/kzg.js";
19
+ import {PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
18
20
  import {
19
21
  DataColumnSidecarErrorCode,
20
22
  DataColumnSidecarGossipError,
@@ -26,7 +28,7 @@ import {RegenCaller} from "../regen/interface.js";
26
28
 
27
29
  // SPEC FUNCTION
28
30
  // https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.4/specs/fulu/p2p-interface.md#data_column_sidecar_subnet_id
29
- export async function validateGossipDataColumnSidecar(
31
+ export async function validateGossipFuluDataColumnSidecar(
30
32
  chain: IBeaconChain,
31
33
  dataColumnSidecar: fulu.DataColumnSidecar,
32
34
  gossipSubnet: SubnetID,
@@ -36,7 +38,7 @@ export async function validateGossipDataColumnSidecar(
36
38
  const blockRootHex = toRootHex(ssz.phase0.BeaconBlockHeader.hashTreeRoot(blockHeader));
37
39
 
38
40
  // 1) [REJECT] The sidecar is valid as verified by verify_data_column_sidecar
39
- verifyDataColumnSidecar(chain.config, dataColumnSidecar);
41
+ verifyFuluDataColumnSidecar(chain.config, dataColumnSidecar);
40
42
 
41
43
  // 2) [REJECT] The sidecar is for the correct subnet -- i.e. compute_subnet_for_data_column_sidecar(sidecar.index) == subnet_id
42
44
  if (computeSubnetForDataColumnSidecar(chain.config, dataColumnSidecar) !== gossipSubnet) {
@@ -203,11 +205,75 @@ export async function validateGossipDataColumnSidecar(
203
205
  // -- Handled in seenGossipBlockInput
204
206
  }
205
207
 
208
+ // SPEC FUNCTION
209
+ // https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.3/specs/gloas/p2p-interface.md#data_column_sidecar_subnet_id
210
+ export async function validateGossipGloasDataColumnSidecar(
211
+ chain: IBeaconChain,
212
+ payloadInput: PayloadEnvelopeInput,
213
+ dataColumnSidecar: gloas.DataColumnSidecar,
214
+ gossipSubnet: SubnetID,
215
+ metrics: Metrics | null
216
+ ): Promise<void> {
217
+ const blockRootHex = toRootHex(dataColumnSidecar.beaconBlockRoot);
218
+ const block = chain.forkChoice.getBlockHexDefaultStatus(blockRootHex);
219
+
220
+ // [IGNORE] A valid block for the sidecar's `slot` has been seen.
221
+ if (block === null) {
222
+ throw new DataColumnSidecarGossipError(GossipAction.IGNORE, {
223
+ code: DataColumnSidecarErrorCode.BLOCK_UNKNOWN,
224
+ blockRoot: blockRootHex,
225
+ slot: dataColumnSidecar.slot,
226
+ });
227
+ }
228
+
229
+ // [REJECT] The sidecar slot matches the slot of the block with root beacon_block_root.
230
+ if (block.slot !== dataColumnSidecar.slot) {
231
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
232
+ code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_SLOT,
233
+ columnIndex: dataColumnSidecar.index,
234
+ expected: block.slot,
235
+ actual: dataColumnSidecar.slot,
236
+ });
237
+ }
238
+
239
+ // [REJECT] The sidecar must pass verify_data_column_sidecar against the block commitments
240
+ const kzgCommitments = payloadInput.getBlobKzgCommitments();
241
+ verifyGloasDataColumnSidecar(dataColumnSidecar, kzgCommitments);
242
+
243
+ // [REJECT] The sidecar must be on the correct subnet
244
+ if (computeSubnetForDataColumnSidecar(chain.config, dataColumnSidecar) !== gossipSubnet) {
245
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
246
+ code: DataColumnSidecarErrorCode.INVALID_SUBNET,
247
+ columnIndex: dataColumnSidecar.index,
248
+ gossipSubnet,
249
+ });
250
+ }
251
+
252
+ // [REJECT] The sidecar kzg proofs must verify
253
+ const kzgProofTimer = metrics?.peerDas.dataColumnSidecarKzgProofsVerificationTime.startTimer();
254
+ try {
255
+ await verifyDataColumnSidecarKzgProofs(
256
+ kzgCommitments,
257
+ Array.from({length: dataColumnSidecar.column.length}, () => dataColumnSidecar.index),
258
+ dataColumnSidecar.column,
259
+ dataColumnSidecar.kzgProofs
260
+ );
261
+ } catch {
262
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
263
+ code: DataColumnSidecarErrorCode.INVALID_KZG_PROOF,
264
+ slot: dataColumnSidecar.slot,
265
+ columnIndex: dataColumnSidecar.index,
266
+ });
267
+ } finally {
268
+ kzgProofTimer?.();
269
+ }
270
+ }
271
+
206
272
  /**
207
273
  * SPEC FUNCTION
208
274
  * https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.4/specs/fulu/p2p-interface.md#verify_data_column_sidecar
209
275
  */
210
- function verifyDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar: fulu.DataColumnSidecar): void {
276
+ function verifyFuluDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar: fulu.DataColumnSidecar): void {
211
277
  if (dataColumnSidecar.index >= NUMBER_OF_COLUMNS) {
212
278
  throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
213
279
  code: DataColumnSidecarErrorCode.INVALID_INDEX,
@@ -250,6 +316,41 @@ function verifyDataColumnSidecar(config: ChainForkConfig, dataColumnSidecar: ful
250
316
  }
251
317
  }
252
318
 
319
+ /**
320
+ * SPEC FUNCTION
321
+ * https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.3/specs/gloas/p2p-interface.md#modified-verify_data_column_sidecar
322
+ */
323
+ function verifyGloasDataColumnSidecar(dataColumnSidecar: gloas.DataColumnSidecar, kzgCommitments: Uint8Array[]): void {
324
+ const slot = getDataColumnSidecarSlot(dataColumnSidecar);
325
+ if (dataColumnSidecar.index >= NUMBER_OF_COLUMNS) {
326
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
327
+ code: DataColumnSidecarErrorCode.INVALID_INDEX,
328
+ slot,
329
+ columnIndex: dataColumnSidecar.index,
330
+ });
331
+ }
332
+
333
+ if (dataColumnSidecar.column.length === 0) {
334
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
335
+ code: DataColumnSidecarErrorCode.NO_COMMITMENTS,
336
+ slot,
337
+ columnIndex: dataColumnSidecar.index,
338
+ });
339
+ }
340
+
341
+ if (
342
+ dataColumnSidecar.column.length !== kzgCommitments.length ||
343
+ dataColumnSidecar.column.length !== dataColumnSidecar.kzgProofs.length
344
+ ) {
345
+ throw new DataColumnSidecarGossipError(GossipAction.REJECT, {
346
+ code: DataColumnSidecarErrorCode.MISMATCHED_LENGTHS,
347
+ columnLength: dataColumnSidecar.column.length,
348
+ commitmentsLength: kzgCommitments.length,
349
+ proofsLength: dataColumnSidecar.kzgProofs.length,
350
+ });
351
+ }
352
+ }
353
+
253
354
  /**
254
355
  * SPEC FUNCTION
255
356
  * https://github.com/ethereum/consensus-specs/blob/v1.6.0-alpha.4/specs/fulu/p2p-interface.md#verify_data_column_sidecar_kzg_proofs
@@ -287,19 +388,19 @@ export function verifyDataColumnSidecarInclusionProof(dataColumnSidecar: fulu.Da
287
388
  }
288
389
 
289
390
  /**
290
- * Validate a subset of data column sidecars in a block
391
+ * Validate a subset of fulu data column sidecars against a block
291
392
  *
292
393
  * Requires the block to be known to the node
293
394
  *
294
395
  * NOTE: chain is optional to skip signature verification. Helpful for testing purposes and so that can control whether
295
396
  * signature gets checked depending on the reqresp method that is being checked
296
397
  */
297
- export async function validateBlockDataColumnSidecars(
398
+ export async function validateFuluBlockDataColumnSidecars(
298
399
  chain: IBeaconChain | null,
299
400
  blockSlot: Slot,
300
401
  blockRoot: Root,
301
402
  blockBlobCount: number,
302
- dataColumnSidecars: fulu.DataColumnSidecars,
403
+ dataColumnSidecars: fulu.DataColumnSidecar[],
303
404
  metrics?: BeaconMetrics["peerDas"] | null
304
405
  ): Promise<void> {
305
406
  metrics?.dataColumnSidecarProcessingRequests.inc(dataColumnSidecars.length);
@@ -467,6 +568,128 @@ export async function validateBlockDataColumnSidecars(
467
568
  "DataColumnSidecar has invalid KZG proof batch"
468
569
  );
469
570
  }
571
+
572
+ metrics?.dataColumnSidecarProcessingSuccesses.inc();
573
+ } finally {
574
+ verificationTimer?.();
575
+ }
576
+ }
577
+
578
+ /**
579
+ * Validate a subset of gloas data column sidecars against a block
580
+ * Gloas sidecars don't carry signed block headers, kzg commitments, or inclusion proofs
581
+ */
582
+ export async function validateGloasBlockDataColumnSidecars(
583
+ blockSlot: Slot,
584
+ blockRoot: Root,
585
+ blockKzgCommitments: Uint8Array[],
586
+ dataColumnSidecars: gloas.DataColumnSidecar[],
587
+ metrics?: BeaconMetrics["peerDas"] | null
588
+ ): Promise<void> {
589
+ metrics?.dataColumnSidecarProcessingRequests.inc(dataColumnSidecars.length);
590
+ const verificationTimer = metrics?.dataColumnSidecarGossipVerificationTime.startTimer();
591
+ try {
592
+ if (dataColumnSidecars.length === 0) {
593
+ return;
594
+ }
595
+
596
+ if (blockKzgCommitments.length === 0) {
597
+ throw new DataColumnSidecarValidationError(
598
+ {
599
+ code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_COUNT,
600
+ slot: blockSlot,
601
+ expected: 0,
602
+ actual: dataColumnSidecars.length,
603
+ },
604
+ "Block has no blob commitments but data column sidecars were provided"
605
+ );
606
+ }
607
+
608
+ const commitments: Uint8Array[] = [];
609
+ const cellIndices: number[] = [];
610
+ const cells: Uint8Array[] = [];
611
+ const proofs: Uint8Array[] = [];
612
+ for (const columnSidecar of dataColumnSidecars) {
613
+ if (columnSidecar.slot !== blockSlot) {
614
+ throw new DataColumnSidecarValidationError({
615
+ code: DataColumnSidecarErrorCode.INCORRECT_SIDECAR_SLOT,
616
+ columnIndex: columnSidecar.index,
617
+ expected: blockSlot,
618
+ actual: columnSidecar.slot,
619
+ });
620
+ }
621
+
622
+ if (!byteArrayEquals(columnSidecar.beaconBlockRoot, blockRoot)) {
623
+ throw new DataColumnSidecarValidationError({
624
+ code: DataColumnSidecarErrorCode.INCORRECT_BLOCK,
625
+ slot: blockSlot,
626
+ columnIndex: columnSidecar.index,
627
+ expected: toRootHex(blockRoot),
628
+ actual: toRootHex(columnSidecar.beaconBlockRoot),
629
+ });
630
+ }
631
+
632
+ if (columnSidecar.index >= NUMBER_OF_COLUMNS) {
633
+ throw new DataColumnSidecarValidationError(
634
+ {
635
+ code: DataColumnSidecarErrorCode.INVALID_INDEX,
636
+ slot: blockSlot,
637
+ columnIndex: columnSidecar.index,
638
+ },
639
+ "DataColumnSidecar has invalid index"
640
+ );
641
+ }
642
+
643
+ if (columnSidecar.column.length !== blockKzgCommitments.length) {
644
+ throw new DataColumnSidecarValidationError({
645
+ code: DataColumnSidecarErrorCode.INCORRECT_CELL_COUNT,
646
+ slot: blockSlot,
647
+ columnIndex: columnSidecar.index,
648
+ expected: blockKzgCommitments.length,
649
+ actual: columnSidecar.column.length,
650
+ });
651
+ }
652
+
653
+ if (columnSidecar.column.length !== columnSidecar.kzgProofs.length) {
654
+ throw new DataColumnSidecarValidationError({
655
+ code: DataColumnSidecarErrorCode.INCORRECT_KZG_PROOF_COUNT,
656
+ slot: blockSlot,
657
+ columnIndex: columnSidecar.index,
658
+ expected: columnSidecar.column.length,
659
+ actual: columnSidecar.kzgProofs.length,
660
+ });
661
+ }
662
+
663
+ commitments.push(...blockKzgCommitments);
664
+ cellIndices.push(...Array.from({length: columnSidecar.column.length}, () => columnSidecar.index));
665
+ cells.push(...columnSidecar.column);
666
+ proofs.push(...columnSidecar.kzgProofs);
667
+ }
668
+
669
+ let reason: string | undefined;
670
+ // batch verification for the cases: downloadByRange and downloadByRoot
671
+ const kzgVerificationTimer = metrics?.kzgVerificationDataColumnBatchTime.startTimer();
672
+ try {
673
+ const valid = await kzg.asyncVerifyCellKzgProofBatch(commitments, cellIndices, cells, proofs);
674
+ if (!valid) {
675
+ reason = "Invalid KZG proof batch";
676
+ }
677
+ } catch (e) {
678
+ reason = (e as Error).message;
679
+ } finally {
680
+ kzgVerificationTimer?.();
681
+ }
682
+ if (reason !== undefined) {
683
+ throw new DataColumnSidecarValidationError(
684
+ {
685
+ code: DataColumnSidecarErrorCode.INVALID_KZG_PROOF_BATCH,
686
+ slot: blockSlot,
687
+ reason,
688
+ },
689
+ "DataColumnSidecar has invalid KZG proof batch"
690
+ );
691
+ }
692
+
470
693
  metrics?.dataColumnSidecarProcessingSuccesses.inc();
471
694
  } finally {
472
695
  verificationTimer?.();
@@ -3,6 +3,7 @@ import {
3
3
  createSingleSignatureSetFromComponents,
4
4
  getExecutionPayloadBidSigningRoot,
5
5
  isActiveBuilder,
6
+ isStatePostGloas,
6
7
  } from "@lodestar/state-transition";
7
8
  import {gloas} from "@lodestar/types";
8
9
  import {toRootHex} from "@lodestar/utils";
@@ -32,6 +33,9 @@ async function validateExecutionPayloadBid(
32
33
  const parentBlockRootHex = toRootHex(bid.parentBlockRoot);
33
34
  const parentBlockHashHex = toRootHex(bid.parentBlockHash);
34
35
  const state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.validateGossipExecutionPayloadBid);
36
+ if (!isStatePostGloas(state)) {
37
+ throw new Error(`Expected gloas+ state for execution payload bid validation, got fork=${state.forkName}`);
38
+ }
35
39
 
36
40
  // [IGNORE] `bid.slot` is the current slot or the next slot.
37
41
  const currentSlot = chain.clock.currentSlot;
@@ -83,9 +87,9 @@ async function validateExecutionPayloadBid(
83
87
  });
84
88
  }
85
89
 
86
- // [IGNORE] this bid is the highest value bid seen for the corresponding slot
87
- // and the given parent block hash.
88
- const bestBid = chain.executionPayloadBidPool.getBestBid(parentBlockRootHex, parentBlockHashHex, bid.slot);
90
+ // [IGNORE] this bid is the highest value bid seen for the tuple
91
+ // `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`.
92
+ const bestBid = chain.executionPayloadBidPool.getBestBid(bid.slot, parentBlockHashHex, parentBlockRootHex);
89
93
  if (bestBid !== null && bestBid.value >= bid.value) {
90
94
  throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
91
95
  code: ExecutionPayloadBidErrorCode.BID_TOO_LOW,
@@ -1,5 +1,9 @@
1
1
  import {PayloadStatus} from "@lodestar/fork-choice";
2
- import {computeStartSlotAtEpoch, getExecutionPayloadEnvelopeSignatureSet} from "@lodestar/state-transition";
2
+ import {
3
+ computeStartSlotAtEpoch,
4
+ getExecutionPayloadEnvelopeSignatureSet,
5
+ isStatePostGloas,
6
+ } from "@lodestar/state-transition";
3
7
  import {gloas} from "@lodestar/types";
4
8
  import {toRootHex} from "@lodestar/utils";
5
9
  import {ExecutionPayloadEnvelopeError, ExecutionPayloadEnvelopeErrorCode, GossipAction} from "../errors/index.js";
@@ -113,6 +117,9 @@ async function validateExecutionPayloadEnvelope(
113
117
  slot: envelope.slot,
114
118
  });
115
119
  });
120
+ if (!isStatePostGloas(blockState)) {
121
+ throw new Error(`Expected gloas+ state for execution payload envelope validation, got fork=${blockState.forkName}`);
122
+ }
116
123
 
117
124
  const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
118
125
  chain.config,
@@ -2,6 +2,7 @@ import {
2
2
  computeEpochAtSlot,
3
3
  createSingleSignatureSetFromComponents,
4
4
  getPayloadAttestationDataSigningRoot,
5
+ isStatePostGloas,
5
6
  } from "@lodestar/state-transition";
6
7
  import {RootHex, gloas, ssz} from "@lodestar/types";
7
8
  import {toRootHex} from "@lodestar/utils";
@@ -66,6 +67,9 @@ async function validatePayloadAttestationMessage(
66
67
  }
67
68
 
68
69
  const state = chain.getHeadState();
70
+ if (!isStatePostGloas(state)) {
71
+ throw new Error(`Expected gloas+ state for payload attestation validation, got fork=${state.forkName}`);
72
+ }
69
73
 
70
74
  // [REJECT] The message's block `data.beacon_block_root` passes validation.
71
75
  // TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
@@ -1,5 +1,5 @@
1
1
  import {SYNC_COMMITTEE_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params";
2
- import {IBeaconStateView} from "@lodestar/state-transition";
2
+ import {IBeaconStateView, isStatePostAltair} from "@lodestar/state-transition";
3
3
  import {SubnetID, altair} from "@lodestar/types";
4
4
  import {toRootHex} from "@lodestar/utils";
5
5
  import {GossipAction, SyncCommitteeError, SyncCommitteeErrorCode} from "../errors/index.js";
@@ -148,6 +148,10 @@ function getIndicesInSubcommittee(
148
148
  subnet: SubnetID,
149
149
  data: Pick<altair.SyncCommitteeMessage, "slot" | "validatorIndex">
150
150
  ): IndexInSubcommittee[] | null {
151
+ if (!isStatePostAltair(headState)) {
152
+ return null;
153
+ }
154
+
151
155
  const syncCommittee = headState.getIndexedSyncCommittee(data.slot);
152
156
  const indexesInCommittee = syncCommittee.validatorIndexMap.get(data.validatorIndex);
153
157
  if (indexesInCommittee === undefined) {
@@ -1,5 +1,5 @@
1
1
  import {SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params";
2
- import {IBeaconStateView, isSyncCommitteeAggregator} from "@lodestar/state-transition";
2
+ import {IBeaconStateView, isStatePostAltair, isSyncCommitteeAggregator} from "@lodestar/state-transition";
3
3
  import {ValidatorIndex, altair} from "@lodestar/types";
4
4
  import {GossipAction, SyncCommitteeError, SyncCommitteeErrorCode} from "../errors/index.js";
5
5
  import {IBeaconChain} from "../interface.js";
@@ -107,6 +107,10 @@ function getContributionIndices(
107
107
  state: IBeaconStateView,
108
108
  contribution: altair.SyncCommitteeContribution
109
109
  ): ValidatorIndex[] {
110
+ if (!isStatePostAltair(state)) {
111
+ throw new Error("Expected Altair state for sync committee contribution");
112
+ }
113
+
110
114
  const startIndex = contribution.subcommitteeIndex * SYNC_COMMITTEE_SUBNET_SIZE;
111
115
 
112
116
  const syncCommittee = state.getIndexedSyncCommittee(contribution.slot);