@lodestar/beacon-node 1.43.0-dev.9fa9f08ef6 → 1.43.0-dev.a142c56215

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 (233) hide show
  1. package/lib/api/impl/beacon/blocks/index.js +4 -6
  2. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  3. package/lib/api/impl/beacon/state/utils.d.ts +2 -2
  4. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  6. package/lib/api/impl/lodestar/index.js +1 -1
  7. package/lib/api/impl/lodestar/index.js.map +1 -1
  8. package/lib/api/impl/validator/index.d.ts.map +1 -1
  9. package/lib/api/impl/validator/index.js +0 -4
  10. package/lib/api/impl/validator/index.js.map +1 -1
  11. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  12. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  13. package/lib/chain/archiveStore/interface.d.ts +4 -4
  14. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  15. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
  16. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
  17. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
  18. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +2 -2
  19. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  20. package/lib/chain/archiveStore/utils/archiveBlocks.js +110 -58
  21. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  22. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  23. package/lib/chain/blocks/importBlock.js +6 -3
  24. package/lib/chain/blocks/importBlock.js.map +1 -1
  25. package/lib/chain/blocks/importExecutionPayload.d.ts +26 -14
  26. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  27. package/lib/chain/blocks/importExecutionPayload.js +73 -86
  28. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  29. package/lib/chain/blocks/index.d.ts +5 -3
  30. package/lib/chain/blocks/index.d.ts.map +1 -1
  31. package/lib/chain/blocks/index.js +28 -10
  32. package/lib/chain/blocks/index.js.map +1 -1
  33. package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
  34. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  35. package/lib/chain/blocks/types.d.ts +14 -20
  36. package/lib/chain/blocks/types.d.ts.map +1 -1
  37. package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
  38. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  39. package/lib/chain/blocks/utils/chainSegment.js +81 -12
  40. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  41. package/lib/chain/blocks/verifyBlock.d.ts +3 -2
  42. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  43. package/lib/chain/blocks/verifyBlock.js +30 -5
  44. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  45. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  46. package/lib/chain/blocks/verifyBlocksSanityChecks.js +15 -4
  47. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  48. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
  49. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
  50. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +76 -0
  51. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
  52. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
  53. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
  54. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
  55. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  56. package/lib/chain/chain.d.ts +6 -5
  57. package/lib/chain/chain.d.ts.map +1 -1
  58. package/lib/chain/chain.js +16 -5
  59. package/lib/chain/chain.js.map +1 -1
  60. package/lib/chain/emitter.d.ts +3 -3
  61. package/lib/chain/emitter.d.ts.map +1 -1
  62. package/lib/chain/errors/blockError.d.ts +8 -1
  63. package/lib/chain/errors/blockError.d.ts.map +1 -1
  64. package/lib/chain/errors/blockError.js +2 -0
  65. package/lib/chain/errors/blockError.js.map +1 -1
  66. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  67. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  68. package/lib/chain/errors/executionPayloadBid.js +1 -0
  69. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  70. package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
  71. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  72. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  73. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  74. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  75. package/lib/chain/forkChoice/index.js +5 -17
  76. package/lib/chain/forkChoice/index.js.map +1 -1
  77. package/lib/chain/interface.d.ts +5 -4
  78. package/lib/chain/interface.d.ts.map +1 -1
  79. package/lib/chain/interface.js.map +1 -1
  80. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  81. package/lib/chain/prepareNextSlot.js +30 -10
  82. package/lib/chain/prepareNextSlot.js.map +1 -1
  83. package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -2
  84. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  85. package/lib/chain/produceBlock/produceBlockBody.js +39 -13
  86. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  87. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +11 -4
  88. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  89. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +20 -18
  90. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  91. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  92. package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -1
  93. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  94. package/lib/chain/validation/block.d.ts.map +1 -1
  95. package/lib/chain/validation/block.js +1 -0
  96. package/lib/chain/validation/block.js.map +1 -1
  97. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  98. package/lib/chain/validation/executionPayloadBid.js +13 -1
  99. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  100. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  101. package/lib/chain/validation/executionPayloadEnvelope.js +19 -9
  102. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  103. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  104. package/lib/chain/validation/payloadAttestationMessage.js +4 -3
  105. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  106. package/lib/db/repositories/executionPayloadEnvelopeArchive.js +1 -1
  107. package/lib/db/repositories/executionPayloadEnvelopeArchive.js.map +1 -1
  108. package/lib/execution/engine/http.d.ts.map +1 -1
  109. package/lib/execution/engine/http.js +21 -14
  110. package/lib/execution/engine/http.js.map +1 -1
  111. package/lib/execution/engine/interface.d.ts +1 -0
  112. package/lib/execution/engine/interface.d.ts.map +1 -1
  113. package/lib/execution/engine/mock.d.ts.map +1 -1
  114. package/lib/execution/engine/mock.js +6 -0
  115. package/lib/execution/engine/mock.js.map +1 -1
  116. package/lib/execution/engine/types.d.ts +20 -0
  117. package/lib/execution/engine/types.d.ts.map +1 -1
  118. package/lib/execution/engine/types.js +18 -0
  119. package/lib/execution/engine/types.js.map +1 -1
  120. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  121. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  122. package/lib/metrics/metrics/lodestar.js +4 -0
  123. package/lib/metrics/metrics/lodestar.js.map +1 -1
  124. package/lib/network/gossip/topic.d.ts +23 -2
  125. package/lib/network/gossip/topic.d.ts.map +1 -1
  126. package/lib/network/network.js +1 -1
  127. package/lib/network/network.js.map +1 -1
  128. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  129. package/lib/network/processor/gossipHandlers.js +5 -4
  130. package/lib/network/processor/gossipHandlers.js.map +1 -1
  131. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  132. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  133. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  134. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  135. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  136. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  137. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  138. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  139. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  140. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  141. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  142. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  143. package/lib/node/notifier.js +7 -1
  144. package/lib/node/notifier.js.map +1 -1
  145. package/lib/sync/range/batch.d.ts +12 -2
  146. package/lib/sync/range/batch.d.ts.map +1 -1
  147. package/lib/sync/range/batch.js +56 -30
  148. package/lib/sync/range/batch.js.map +1 -1
  149. package/lib/sync/range/chain.d.ts +6 -2
  150. package/lib/sync/range/chain.d.ts.map +1 -1
  151. package/lib/sync/range/chain.js +4 -3
  152. package/lib/sync/range/chain.js.map +1 -1
  153. package/lib/sync/range/range.d.ts.map +1 -1
  154. package/lib/sync/range/range.js +17 -6
  155. package/lib/sync/range/range.js.map +1 -1
  156. package/lib/sync/types.d.ts +34 -0
  157. package/lib/sync/types.d.ts.map +1 -1
  158. package/lib/sync/types.js +34 -0
  159. package/lib/sync/types.js.map +1 -1
  160. package/lib/sync/unknownBlock.d.ts +24 -1
  161. package/lib/sync/unknownBlock.d.ts.map +1 -1
  162. package/lib/sync/unknownBlock.js +649 -53
  163. package/lib/sync/unknownBlock.js.map +1 -1
  164. package/lib/sync/utils/downloadByRange.d.ts +46 -10
  165. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  166. package/lib/sync/utils/downloadByRange.js +147 -24
  167. package/lib/sync/utils/downloadByRange.js.map +1 -1
  168. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  169. package/lib/sync/utils/downloadByRoot.js +6 -2
  170. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  171. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  172. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  173. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  174. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  175. package/lib/util/sszBytes.d.ts.map +1 -1
  176. package/lib/util/sszBytes.js +16 -3
  177. package/lib/util/sszBytes.js.map +1 -1
  178. package/package.json +17 -16
  179. package/src/api/impl/beacon/blocks/index.ts +6 -6
  180. package/src/api/impl/beacon/state/utils.ts +2 -2
  181. package/src/api/impl/lodestar/index.ts +1 -1
  182. package/src/api/impl/validator/index.ts +0 -4
  183. package/src/chain/archiveStore/archiveStore.ts +5 -5
  184. package/src/chain/archiveStore/interface.ts +4 -4
  185. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +4 -4
  186. package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
  187. package/src/chain/blocks/importBlock.ts +4 -2
  188. package/src/chain/blocks/importExecutionPayload.ts +92 -107
  189. package/src/chain/blocks/index.ts +44 -13
  190. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  191. package/src/chain/blocks/types.ts +14 -25
  192. package/src/chain/blocks/utils/chainSegment.ts +106 -17
  193. package/src/chain/blocks/verifyBlock.ts +35 -6
  194. package/src/chain/blocks/verifyBlocksSanityChecks.ts +16 -7
  195. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
  196. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  197. package/src/chain/chain.ts +33 -19
  198. package/src/chain/emitter.ts +3 -3
  199. package/src/chain/errors/blockError.ts +4 -1
  200. package/src/chain/errors/executionPayloadBid.ts +6 -0
  201. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  202. package/src/chain/forkChoice/index.ts +2 -22
  203. package/src/chain/interface.ts +9 -3
  204. package/src/chain/prepareNextSlot.ts +42 -12
  205. package/src/chain/produceBlock/produceBlockBody.ts +43 -11
  206. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +22 -20
  207. package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
  208. package/src/chain/validation/block.ts +1 -0
  209. package/src/chain/validation/executionPayloadBid.ts +14 -0
  210. package/src/chain/validation/executionPayloadEnvelope.ts +20 -10
  211. package/src/chain/validation/payloadAttestationMessage.ts +5 -3
  212. package/src/db/repositories/executionPayloadEnvelopeArchive.ts +1 -1
  213. package/src/execution/engine/http.ts +21 -14
  214. package/src/execution/engine/interface.ts +1 -0
  215. package/src/execution/engine/mock.ts +8 -1
  216. package/src/execution/engine/types.ts +41 -0
  217. package/src/metrics/metrics/lodestar.ts +4 -0
  218. package/src/network/network.ts +1 -1
  219. package/src/network/processor/gossipHandlers.ts +7 -4
  220. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  221. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  222. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  223. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  224. package/src/node/notifier.ts +8 -1
  225. package/src/sync/range/batch.ts +90 -35
  226. package/src/sync/range/chain.ts +13 -5
  227. package/src/sync/range/range.ts +18 -6
  228. package/src/sync/types.ts +72 -0
  229. package/src/sync/unknownBlock.ts +810 -57
  230. package/src/sync/utils/downloadByRange.ts +256 -39
  231. package/src/sync/utils/downloadByRoot.ts +12 -2
  232. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  233. package/src/util/sszBytes.ts +21 -3
@@ -1,12 +1,14 @@
1
1
  import {ExecutionStatus, ProtoBlock} from "@lodestar/fork-choice";
2
- import {ForkName, isForkPostFulu} from "@lodestar/params";
2
+ import {ForkName, ForkSeq, isForkPostFulu} from "@lodestar/params";
3
3
  import {DataAvailabilityStatus, IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
4
- import {IndexedAttestation, deneb} from "@lodestar/types";
4
+ import {IndexedAttestation, Slot, deneb} from "@lodestar/types";
5
+ import {getBlobKzgCommitments} from "../../util/dataColumns.js";
5
6
  import type {BeaconChain} from "../chain.js";
6
7
  import {BlockError, BlockErrorCode} from "../errors/index.js";
7
8
  import {BlockProcessOpts} from "../options.js";
8
9
  import {RegenCaller} from "../regen/index.js";
9
10
  import {DAType, IBlockInput} from "./blockInput/index.js";
11
+ import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
10
12
  import {ImportBlockOpts} from "./types.js";
11
13
  import {DENEB_BLOWFISH_BANNER} from "./utils/blowfishBanner.js";
12
14
  import {ELECTRA_GIRAFFE_BANNER} from "./utils/giraffeBanner.js";
@@ -16,6 +18,7 @@ import {verifyBlocksDataAvailability} from "./verifyBlocksDataAvailability.js";
16
18
  import {SegmentExecStatus, verifyBlocksExecutionPayload} from "./verifyBlocksExecutionPayloads.js";
17
19
  import {verifyBlocksSignatures} from "./verifyBlocksSignatures.js";
18
20
  import {verifyBlocksStateTransitionOnly} from "./verifyBlocksStateTransitionOnly.js";
21
+ import {verifyPayloadsDataAvailability} from "./verifyPayloadsDataAvailability.js";
19
22
 
20
23
  /**
21
24
  * Verifies 1 or more blocks are fully valid; from a linear sequence of blocks.
@@ -32,6 +35,7 @@ export async function verifyBlocksInEpoch(
32
35
  this: BeaconChain,
33
36
  parentBlock: ProtoBlock,
34
37
  blockInputs: IBlockInput[],
38
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
35
39
  opts: BlockProcessOpts & ImportBlockOpts
36
40
  ): Promise<{
37
41
  postStates: IBeaconStateView[];
@@ -110,6 +114,26 @@ export async function verifyBlocksInEpoch(
110
114
  });
111
115
  }
112
116
 
117
+ // Pick the data-availability source by fork:
118
+ // - Pre-Gloas: blob/Fulu-column data lives in IBlockInput → verifyBlocksDataAvailability.
119
+ // - Post-Gloas: verifyPayloadsDataAvailability
120
+ const daAvailabilityPromise =
121
+ fork >= ForkSeq.gloas
122
+ ? (async () => {
123
+ const payloadInputsForDa: PayloadEnvelopeInput[] = [];
124
+ for (const input of blockInputs) {
125
+ const pi = payloadEnvelopes?.get(input.slot);
126
+ if (pi !== undefined) payloadInputsForDa.push(pi);
127
+ }
128
+ await verifyPayloadsDataAvailability(payloadInputsForDa, abortController.signal);
129
+ return {
130
+ // post-gloas, DataAvailabilityStatus is NotRequired for forkChoice.onBlock() ProtoBlock
131
+ dataAvailabilityStatuses: blockInputs.map(() => DataAvailabilityStatus.NotRequired),
132
+ availableTime: Date.now(),
133
+ };
134
+ })()
135
+ : verifyBlocksDataAvailability(blockInputs, abortController.signal);
136
+
113
137
  // batch all I/O operations to reduce overhead
114
138
  const [
115
139
  segmentExecStatus,
@@ -119,8 +143,8 @@ export async function verifyBlocksInEpoch(
119
143
  ] = await Promise.all([
120
144
  verifyExecutionPayloadsPromise,
121
145
 
122
- // data availability for the blobs
123
- verifyBlocksDataAvailability(blockInputs, abortController.signal),
146
+ // data availability (fork-specific; see daAvailabilityPromise above)
147
+ daAvailabilityPromise,
124
148
 
125
149
  // Run state transition only
126
150
  // TODO: Ensure it yields to allow flushing to workers and engine API
@@ -149,6 +173,9 @@ export async function verifyBlocksInEpoch(
149
173
  opts
150
174
  )
151
175
  : Promise.resolve({verifySignaturesTime: Date.now()}),
176
+
177
+ // TODO GLOAS: can verify payload signatures in batch too
178
+ // maybe chain with the above verifyBlocksSignatures()
152
179
  ]);
153
180
 
154
181
  if (opts.verifyOnly !== true) {
@@ -200,7 +227,9 @@ export async function verifyBlocksInEpoch(
200
227
  blockInputs.length === 1 &&
201
228
  // gossip blocks have seenTimestampSec
202
229
  opts.seenTimestampSec !== undefined &&
230
+ // PreData (pre-deneb) and NoData (gloas) carry no blob data on the block — skip metric
203
231
  blockInputs[0].type !== DAType.PreData &&
232
+ blockInputs[0].type !== DAType.NoData &&
204
233
  executionStatuses[0] === ExecutionStatus.Valid
205
234
  ) {
206
235
  // Find the max time when the block was actually verified
@@ -209,8 +238,8 @@ export async function verifyBlocksInEpoch(
209
238
  this.metrics?.gossipBlock.receivedToFullyVerifiedTime.observe(recvTofullyVerifedTime);
210
239
 
211
240
  const verifiedToBlobsAvailabiltyTime = Math.max(availableTime - fullyVerifiedTime, 0) / 1000;
212
- const block = blockInputs[0].getBlock() as deneb.SignedBeaconBlock;
213
- const numBlobs = block.message.body.blobKzgCommitments.length;
241
+ const block = blockInputs[0].getBlock();
242
+ const numBlobs = getBlobKzgCommitments(blockInputs[0].forkName, block as deneb.SignedBeaconBlock).length;
214
243
 
215
244
  this.metrics?.gossipBlock.verifiedToBlobsAvailabiltyTime.observe({numBlobs}, verifiedToBlobsAvailabiltyTime);
216
245
  this.logger.verbose("Verified blockInput fully with blobs availability", {
@@ -90,15 +90,24 @@ export function verifyBlocksSanityChecks(
90
90
  } else {
91
91
  // When importing a block segment, only the first NON-IGNORED block must be known to the fork-choice.
92
92
  const parentRoot = toRootHex(block.message.parentRoot);
93
- parentBlock = isGloasBeaconBlock(block.message)
94
- ? chain.forkChoice.getBlockHexAndBlockHash(
95
- parentRoot,
96
- toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash)
97
- )
98
- : chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
99
- if (!parentBlock) {
93
+ const parentBlockDefaultStatus = chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
94
+ if (!parentBlockDefaultStatus) {
100
95
  throw new BlockError(block, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot});
101
96
  }
97
+
98
+ parentBlock = parentBlockDefaultStatus;
99
+ if (isGloasBeaconBlock(block.message)) {
100
+ const parentBlockHash = toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash);
101
+ const parentBlockWithPayload = chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHash);
102
+ if (!parentBlockWithPayload) {
103
+ throw new BlockError(block, {
104
+ code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN,
105
+ parentRoot,
106
+ parentBlockHash,
107
+ });
108
+ }
109
+ parentBlock = parentBlockWithPayload;
110
+ }
102
111
  // Parent is known to the fork-choice
103
112
  parentBlockSlot = parentBlock.slot;
104
113
  }
@@ -0,0 +1,129 @@
1
+ import {BeaconConfig} from "@lodestar/config";
2
+ import {
3
+ type IBeaconStateViewGloas,
4
+ type PubkeyCache,
5
+ computeTimeAtSlot,
6
+ getExecutionPayloadEnvelopeSignatureSet,
7
+ } from "@lodestar/state-transition";
8
+ import {gloas, ssz} from "@lodestar/types";
9
+ import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
10
+ import {IBlsVerifier} from "../bls/index.js";
11
+
12
+ export type VerifyExecutionPayloadEnvelopeOpts = {
13
+ verifyExecutionRequestsRoot?: boolean;
14
+ };
15
+
16
+ /**
17
+ * Verify execution payload envelope fields against the post-block state.
18
+ *
19
+ * Signature verification and the execution engine call (`verify_and_notify_new_payload`) are
20
+ * performed outside this function, see `verifyExecutionPayloadEnvelopeSignature` and
21
+ * `importExecutionPayload` which run both in parallel with this check.
22
+ *
23
+ * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.5/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope
24
+ */
25
+ export function verifyExecutionPayloadEnvelope(
26
+ config: BeaconConfig,
27
+ state: IBeaconStateViewGloas,
28
+ envelope: gloas.ExecutionPayloadEnvelope,
29
+ opts?: VerifyExecutionPayloadEnvelopeOpts
30
+ ): void {
31
+ const {verifyExecutionRequestsRoot = true} = opts ?? {};
32
+ const payload = envelope.payload;
33
+
34
+ // Verify consistency with the beacon block.
35
+ // Compute header root on a copy of latestBlockHeader to avoid mutating state.
36
+ const headerValue = {...state.latestBlockHeader};
37
+ if (byteArrayEquals(headerValue.stateRoot, ssz.Root.defaultValue())) {
38
+ headerValue.stateRoot = state.hashTreeRoot();
39
+ }
40
+ const headerRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(headerValue);
41
+ if (!byteArrayEquals(envelope.beaconBlockRoot, headerRoot)) {
42
+ throw new Error(
43
+ `Envelope's block is not the latest block header envelope=${toRootHex(envelope.beaconBlockRoot)} latestBlockHeader=${toRootHex(headerRoot)}`
44
+ );
45
+ }
46
+
47
+ // Verify consistency with the committed bid
48
+ const bid = state.latestExecutionPayloadBid;
49
+ if (envelope.builderIndex !== bid.builderIndex) {
50
+ throw new Error(
51
+ `Builder index mismatch between envelope and committed bid envelope=${envelope.builderIndex} bid=${bid.builderIndex}`
52
+ );
53
+ }
54
+ if (!byteArrayEquals(bid.prevRandao, payload.prevRandao)) {
55
+ throw new Error(
56
+ `Prev randao mismatch between bid and payload bid=${toHex(bid.prevRandao)} payload=${toHex(payload.prevRandao)}`
57
+ );
58
+ }
59
+ if (Number(bid.gasLimit) !== payload.gasLimit) {
60
+ throw new Error(
61
+ `Gas limit mismatch between payload and bid payload=${payload.gasLimit} bid=${Number(bid.gasLimit)}`
62
+ );
63
+ }
64
+ if (!byteArrayEquals(bid.blockHash, payload.blockHash)) {
65
+ throw new Error(
66
+ `Block hash mismatch between payload and bid payload=${toRootHex(payload.blockHash)} bid=${toRootHex(bid.blockHash)}`
67
+ );
68
+ }
69
+ // Verify execution_requests_root matches bid commitment.
70
+ // Can be skipped if already verified during gossip validation.
71
+ if (verifyExecutionRequestsRoot) {
72
+ const requestsRoot = ssz.electra.ExecutionRequests.hashTreeRoot(envelope.executionRequests);
73
+ if (!byteArrayEquals(requestsRoot, bid.executionRequestsRoot)) {
74
+ throw new Error(
75
+ `Execution requests root mismatch envelope=${toRootHex(requestsRoot)} bid=${toRootHex(bid.executionRequestsRoot)}`
76
+ );
77
+ }
78
+ }
79
+
80
+ // Verify the execution payload is valid
81
+ if (payload.slotNumber !== state.slot) {
82
+ throw new Error(`Slot mismatch between payload and state payload=${payload.slotNumber} state=${state.slot}`);
83
+ }
84
+ if (!byteArrayEquals(payload.parentHash, state.latestBlockHash)) {
85
+ throw new Error(
86
+ `Parent hash mismatch between payload and state payload=${toRootHex(payload.parentHash)} state=${toRootHex(state.latestBlockHash)}`
87
+ );
88
+ }
89
+ const expectedTimestamp = computeTimeAtSlot(config, state.slot, state.genesisTime);
90
+ if (payload.timestamp !== expectedTimestamp) {
91
+ throw new Error(
92
+ `Timestamp mismatch between payload and state payload=${payload.timestamp} state=${expectedTimestamp}`
93
+ );
94
+ }
95
+
96
+ // Verify consistency with expected withdrawals
97
+ const payloadWithdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot(payload.withdrawals);
98
+ const expectedWithdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot(state.payloadExpectedWithdrawals);
99
+ if (!byteArrayEquals(payloadWithdrawalsRoot, expectedWithdrawalsRoot)) {
100
+ throw new Error(
101
+ `Withdrawals mismatch between payload and expected payload=${toRootHex(payloadWithdrawalsRoot)} expected=${toRootHex(expectedWithdrawalsRoot)}`
102
+ );
103
+ }
104
+
105
+ // Execution engine verification (verify_and_notify_new_payload) is done externally by the caller
106
+ }
107
+
108
+ /**
109
+ * Verify the BLS signature of an execution payload envelope.
110
+ *
111
+ * Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.5/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope_signature
112
+ */
113
+ export async function verifyExecutionPayloadEnvelopeSignature(
114
+ config: BeaconConfig,
115
+ state: IBeaconStateViewGloas,
116
+ pubkeyCache: PubkeyCache,
117
+ signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
118
+ proposerIndex: number,
119
+ bls: IBlsVerifier
120
+ ): Promise<boolean> {
121
+ const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
122
+ config,
123
+ pubkeyCache,
124
+ state,
125
+ signedEnvelope,
126
+ proposerIndex
127
+ );
128
+ return bls.verifySignatureSets([signatureSet]);
129
+ }
@@ -5,7 +5,7 @@ import {writeDataColumnsToDb} from "./writeBlockInputToDb.js";
5
5
  /**
6
6
  * Persists payload envelope data to DB. This operation must be eventually completed if a payload is imported.
7
7
  *
8
- * TODO GLOAS: Persist envelope metadata (stateRoot, executionRequests, builderIndex, etc.) without the full
8
+ * TODO GLOAS: Persist envelope metadata (executionRequests, builderIndex, etc.) without the full
9
9
  * execution payload body — only keep the blockHash reference. The EL already stores the payload.
10
10
  * See https://github.com/ChainSafe/lodestar/issues/5671
11
11
  */
@@ -33,23 +33,14 @@ export async function persistPayloadEnvelopeInput(
33
33
  this: BeaconChain,
34
34
  payloadInput: PayloadEnvelopeInput
35
35
  ): Promise<void> {
36
- await writePayloadEnvelopeInputToDb
37
- .call(this, payloadInput)
38
- .catch((e) => {
39
- this.logger.error(
40
- "Error persisting payload envelope in hot db",
41
- {
42
- slot: payloadInput.slot,
43
- root: payloadInput.blockRootHex,
44
- },
45
- e
46
- );
47
- })
48
- .finally(() => {
49
- this.seenPayloadEnvelopeInputCache.prune(payloadInput.blockRootHex);
50
- this.logger.debug("Pruned payload envelope input", {
36
+ await writePayloadEnvelopeInputToDb.call(this, payloadInput).catch((e) => {
37
+ this.logger.error(
38
+ "Error persisting payload envelope in hot db",
39
+ {
51
40
  slot: payloadInput.slot,
52
41
  root: payloadInput.blockRootHex,
53
- });
54
- });
42
+ },
43
+ e
44
+ );
45
+ });
55
46
  }
@@ -2,7 +2,7 @@ import path from "node:path";
2
2
  import {PrivateKey} from "@libp2p/interface";
3
3
  import {Type} from "@chainsafe/ssz";
4
4
  import {BeaconConfig} from "@lodestar/config";
5
- import {CheckpointWithPayloadStatus, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
5
+ import {CheckpointWithHex, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
6
6
  import {LoggerNode} from "@lodestar/logger/node";
7
7
  import {
8
8
  EFFECTIVE_BALANCE_INCREMENT,
@@ -39,6 +39,7 @@ import {
39
39
  ValidatorIndex,
40
40
  Wei,
41
41
  deneb,
42
+ electra,
42
43
  gloas,
43
44
  isBlindedBeaconBlock,
44
45
  phase0,
@@ -680,7 +681,7 @@ export class BeaconChain implements IBeaconChain {
680
681
  }
681
682
 
682
683
  getStateByCheckpoint(
683
- checkpoint: CheckpointWithPayloadStatus
684
+ checkpoint: CheckpointWithHex
684
685
  ): {state: IBeaconStateView; executionOptimistic: boolean; finalized: boolean} | null {
685
686
  // finalized or justified checkpoint states maynot be available with PersistentCheckpointStateCache, use getCheckpointStateOrBytes() api to get Uint8Array
686
687
  const checkpointHex = {epoch: checkpoint.epoch, rootHex: checkpoint.rootHex};
@@ -701,7 +702,7 @@ export class BeaconChain implements IBeaconChain {
701
702
  }
702
703
 
703
704
  async getStateOrBytesByCheckpoint(
704
- checkpoint: CheckpointWithPayloadStatus
705
+ checkpoint: CheckpointWithHex
705
706
  ): Promise<{state: IBeaconStateView | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null> {
706
707
  const checkpointHex = {epoch: checkpoint.epoch, rootHex: checkpoint.rootHex};
707
708
  const cachedStateCtx = await this.regen.getCheckpointStateOrBytes(checkpointHex);
@@ -886,6 +887,21 @@ export class BeaconChain implements IBeaconChain {
886
887
  );
887
888
  }
888
889
 
890
+ async getParentExecutionRequests(
891
+ parentBlockSlot: Slot,
892
+ parentBlockRootHex: RootHex
893
+ ): Promise<electra.ExecutionRequests> {
894
+ // at the fork boundary, parent is pre-gloas
895
+ if (!isForkPostGloas(this.config.getForkName(parentBlockSlot))) {
896
+ return ssz.electra.ExecutionRequests.defaultValue();
897
+ }
898
+ const envelope = await this.getExecutionPayloadEnvelope(parentBlockSlot, parentBlockRootHex);
899
+ if (envelope === null) {
900
+ throw Error(`Parent execution payload envelope not found slot=${parentBlockSlot}, root=${parentBlockRootHex}`);
901
+ }
902
+ return envelope.message.executionRequests;
903
+ }
904
+
889
905
  async getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<DataColumnSidecar[]> {
890
906
  const fork = this.config.getForkName(blockSlot);
891
907
 
@@ -1082,11 +1098,15 @@ export class BeaconChain implements IBeaconChain {
1082
1098
  }
1083
1099
 
1084
1100
  async processBlock(block: IBlockInput, opts?: ImportBlockOpts): Promise<void> {
1085
- return this.blockProcessor.processBlocksJob([block], opts);
1101
+ return this.blockProcessor.processBlocksJob([block], null, opts);
1086
1102
  }
1087
1103
 
1088
- async processChainSegment(blocks: IBlockInput[], opts?: ImportBlockOpts): Promise<void> {
1089
- return this.blockProcessor.processBlocksJob(blocks, opts);
1104
+ async processChainSegment(
1105
+ blocks: IBlockInput[],
1106
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
1107
+ opts?: ImportBlockOpts
1108
+ ): Promise<void> {
1109
+ await this.blockProcessor.processBlocksJob(blocks, payloadEnvelopes, opts);
1090
1110
  }
1091
1111
 
1092
1112
  async processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void> {
@@ -1277,7 +1297,7 @@ export class BeaconChain implements IBeaconChain {
1277
1297
  * @param blockState state that declares justified checkpoint `checkpoint`
1278
1298
  */
1279
1299
  private justifiedBalancesGetter(
1280
- checkpoint: CheckpointWithPayloadStatus,
1300
+ checkpoint: CheckpointWithHex,
1281
1301
  blockState: IBeaconStateView
1282
1302
  ): EffectiveBalanceIncrements {
1283
1303
  this.metrics?.balancesCache.requests.inc();
@@ -1316,7 +1336,7 @@ export class BeaconChain implements IBeaconChain {
1316
1336
  * @param blockState state that declares justified checkpoint `checkpoint`
1317
1337
  */
1318
1338
  private closestJustifiedBalancesStateToCheckpoint(
1319
- checkpoint: CheckpointWithPayloadStatus,
1339
+ checkpoint: CheckpointWithHex,
1320
1340
  blockState: IBeaconStateView
1321
1341
  ): {state: IBeaconStateView; stateId: string; shouldWarn: boolean} {
1322
1342
  const checkpointHex = {epoch: checkpoint.epoch, rootHex: checkpoint.rootHex};
@@ -1331,10 +1351,7 @@ export class BeaconChain implements IBeaconChain {
1331
1351
  }
1332
1352
 
1333
1353
  // Find a state in the same branch of checkpoint at same epoch. Balances should exactly the same
1334
- for (const descendantBlock of this.forkChoice.forwardIterateDescendants(
1335
- checkpoint.rootHex,
1336
- checkpoint.payloadStatus
1337
- )) {
1354
+ for (const descendantBlock of this.forkChoice.forwardIterateDescendantsDefaultStatus(checkpoint.rootHex)) {
1338
1355
  if (computeEpochAtSlot(descendantBlock.slot) === checkpoint.epoch) {
1339
1356
  const descendantBlockState = this.regen.getStateSync(descendantBlock.stateRoot);
1340
1357
  if (descendantBlockState) {
@@ -1350,10 +1367,7 @@ export class BeaconChain implements IBeaconChain {
1350
1367
 
1351
1368
  // Find a state in the same branch of checkpoint at a latter epoch. Balances are not the same, but should be close
1352
1369
  // Note: must call .forwardIterateDescendants() again since nodes are not sorted
1353
- for (const descendantBlock of this.forkChoice.forwardIterateDescendants(
1354
- checkpoint.rootHex,
1355
- checkpoint.payloadStatus
1356
- )) {
1370
+ for (const descendantBlock of this.forkChoice.forwardIterateDescendantsDefaultStatus(checkpoint.rootHex)) {
1357
1371
  if (computeEpochAtSlot(descendantBlock.slot) > checkpoint.epoch) {
1358
1372
  const descendantBlockState = this.regen.getStateSync(descendantBlock.stateRoot);
1359
1373
  if (descendantBlockState) {
@@ -1457,7 +1471,7 @@ export class BeaconChain implements IBeaconChain {
1457
1471
  this.seenContributionAndProof.prune(head.slot);
1458
1472
  }
1459
1473
 
1460
- private onForkChoiceJustified(this: BeaconChain, cp: CheckpointWithPayloadStatus): void {
1474
+ private onForkChoiceJustified(this: BeaconChain, cp: CheckpointWithHex): void {
1461
1475
  this.logger.verbose("Fork choice justified", {epoch: cp.epoch, root: cp.rootHex});
1462
1476
  }
1463
1477
 
@@ -1468,7 +1482,7 @@ export class BeaconChain implements IBeaconChain {
1468
1482
  });
1469
1483
  }
1470
1484
 
1471
- private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithPayloadStatus): Promise<void> {
1485
+ private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise<void> {
1472
1486
  this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
1473
1487
  const finalizedSlot = computeStartSlotAtEpoch(cp.epoch);
1474
1488
  this.seenBlockProposers.prune(finalizedSlot);
@@ -1509,7 +1523,7 @@ export class BeaconChain implements IBeaconChain {
1509
1523
  }
1510
1524
  }
1511
1525
 
1512
- private async updateValidatorsCustodyRequirement(finalizedCheckpoint: CheckpointWithPayloadStatus): Promise<void> {
1526
+ private async updateValidatorsCustodyRequirement(finalizedCheckpoint: CheckpointWithHex): Promise<void> {
1513
1527
  if (this.custodyConfig.targetCustodyGroupCount === this.config.NUMBER_OF_CUSTODY_GROUPS) {
1514
1528
  // Custody requirements can only be increased, we can disable dynamic custody updates
1515
1529
  // if the node already maintains custody of all custody groups in case it is configured
@@ -1,7 +1,7 @@
1
1
  import {EventEmitter} from "node:events";
2
2
  import {StrictEventEmitter} from "strict-event-emitter-types";
3
3
  import {routes} from "@lodestar/api";
4
- import {CheckpointWithPayloadStatus} from "@lodestar/fork-choice";
4
+ import {CheckpointWithHex} from "@lodestar/fork-choice";
5
5
  import {IBeaconStateView} from "@lodestar/state-transition";
6
6
  import {DataColumnSidecar, RootHex, deneb, phase0} from "@lodestar/types";
7
7
  import {SignedExecutionPayloadEnvelope} from "@lodestar/types/gloas";
@@ -110,8 +110,8 @@ export type ChainEventData = {
110
110
  export type IChainEvents = ApiEvents & {
111
111
  [ChainEvent.checkpoint]: (checkpoint: phase0.Checkpoint, state: IBeaconStateView) => void;
112
112
 
113
- [ChainEvent.forkChoiceJustified]: (checkpoint: CheckpointWithPayloadStatus) => void;
114
- [ChainEvent.forkChoiceFinalized]: (checkpoint: CheckpointWithPayloadStatus) => void;
113
+ [ChainEvent.forkChoiceJustified]: (checkpoint: CheckpointWithHex) => void;
114
+ [ChainEvent.forkChoiceFinalized]: (checkpoint: CheckpointWithHex) => void;
115
115
 
116
116
  [ChainEvent.updateTargetCustodyGroupCount]: (targetGroupCount: number) => void;
117
117
 
@@ -74,6 +74,8 @@ export enum BlockErrorCode {
74
74
  PARENT_EXECUTION_INVALID = "BLOCK_ERROR_PARENT_EXECUTION_INVALID",
75
75
  /** The block's parent execution payload (defined by bid.parent_block_hash) has not been seen */
76
76
  PARENT_PAYLOAD_UNKNOWN = "BLOCK_ERROR_PARENT_PAYLOAD_UNKNOWN",
77
+ /** An execution payload envelope in the chain segment references a block root that does not match its slot's block */
78
+ ENVELOPE_BLOCK_ROOT_MISMATCH = "BLOCK_ERROR_ENVELOPE_BLOCK_ROOT_MISMATCH",
77
79
  }
78
80
 
79
81
  type ExecutionErrorStatus = Exclude<
@@ -107,6 +109,7 @@ export type BlockErrorType =
107
109
  | {code: BlockErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot}
108
110
  | {code: BlockErrorCode.NON_LINEAR_PARENT_ROOTS}
109
111
  | {code: BlockErrorCode.NON_LINEAR_SLOTS}
112
+ | {code: BlockErrorCode.ENVELOPE_BLOCK_ROOT_MISMATCH; envelopeBlockRoot: RootHex; blockRoot: RootHex}
110
113
  | {code: BlockErrorCode.PER_BLOCK_PROCESSING_ERROR; error: Error}
111
114
  | {code: BlockErrorCode.BEACON_CHAIN_ERROR; error: Error}
112
115
  | {code: BlockErrorCode.KNOWN_BAD_BLOCK}
@@ -120,7 +123,7 @@ export type BlockErrorType =
120
123
  | {code: BlockErrorCode.TOO_MANY_KZG_COMMITMENTS; blobKzgCommitmentsLen: number; commitmentLimit: number}
121
124
  | {code: BlockErrorCode.BID_PARENT_ROOT_MISMATCH; bidParentRoot: RootHex; blockParentRoot: RootHex}
122
125
  | {code: BlockErrorCode.PARENT_EXECUTION_INVALID; parentRoot: RootHex}
123
- | {code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN; parentBlockHash: RootHex};
126
+ | {code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN; parentRoot: RootHex; parentBlockHash: RootHex};
124
127
 
125
128
  export class BlockGossipError extends GossipActionError<BlockErrorType> {}
126
129
 
@@ -7,6 +7,7 @@ export enum ExecutionPayloadBidErrorCode {
7
7
  BID_ALREADY_KNOWN = "EXECUTION_PAYLOAD_BID_ERROR_BID_ALREADY_KNOWN",
8
8
  BID_TOO_LOW = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_LOW",
9
9
  BID_TOO_HIGH = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_HIGH",
10
+ TOO_MANY_KZG_COMMITMENTS = "EXECUTION_PAYLOAD_BID_ERROR_TOO_MANY_KZG_COMMITMENTS",
10
11
  UNKNOWN_BLOCK_ROOT = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_BLOCK_ROOT",
11
12
  INVALID_SLOT = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SLOT",
12
13
  INVALID_SIGNATURE = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SIGNATURE",
@@ -28,6 +29,11 @@ export type ExecutionPayloadBidErrorType =
28
29
  }
29
30
  | {code: ExecutionPayloadBidErrorCode.BID_TOO_LOW; bidValue: number; currentHighestBid: number}
30
31
  | {code: ExecutionPayloadBidErrorCode.BID_TOO_HIGH; bidValue: number; builderBalance: number}
32
+ | {
33
+ code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS;
34
+ blobKzgCommitmentsLen: number;
35
+ commitmentLimit: number;
36
+ }
31
37
  | {code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT; parentBlockRoot: RootHex}
32
38
  | {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
33
39
  | {code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE; builderIndex: BuilderIndex; slot: Slot};
@@ -11,6 +11,7 @@ export enum ExecutionPayloadEnvelopeErrorCode {
11
11
  SLOT_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_SLOT_MISMATCH",
12
12
  BUILDER_INDEX_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BUILDER_INDEX_MISMATCH",
13
13
  BLOCK_HASH_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BLOCK_HASH_MISMATCH",
14
+ EXECUTION_REQUESTS_ROOT_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_EXECUTION_REQUESTS_ROOT_MISMATCH",
14
15
  INVALID_SIGNATURE = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_INVALID_SIGNATURE",
15
16
  PAYLOAD_ENVELOPE_INPUT_MISSING = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_PAYLOAD_ENVELOPE_INPUT_MISSING",
16
17
  }
@@ -36,6 +37,11 @@ export type ExecutionPayloadEnvelopeErrorType =
36
37
  envelopeBlockHash: RootHex;
37
38
  bidBlockHash: RootHex | null;
38
39
  }
40
+ | {
41
+ code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_ROOT_MISMATCH;
42
+ envelopeRequestsRoot: RootHex;
43
+ bidRequestsRoot: RootHex;
44
+ }
39
45
  | {code: ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE}
40
46
  | {code: ExecutionPayloadEnvelopeErrorCode.PAYLOAD_ENVELOPE_INPUT_MISSING; blockRoot: RootHex};
41
47
 
@@ -8,7 +8,6 @@ import {
8
8
  ProtoArray,
9
9
  ProtoBlock,
10
10
  ForkChoiceOpts as RawForkChoiceOpts,
11
- getCheckpointPayloadStatus,
12
11
  } from "@lodestar/fork-choice";
13
12
  import {ZERO_HASH_HEX} from "@lodestar/params";
14
13
  import {
@@ -104,16 +103,6 @@ export function initializeForkChoiceFromFinalizedState(
104
103
 
105
104
  const isForkPostGloas = computeEpochAtSlot(state.slot) >= config.GLOAS_FORK_EPOCH;
106
105
 
107
- // Determine justified checkpoint payload status
108
- const justifiedPayloadStatus = isForkPostGloas
109
- ? PayloadStatus.PENDING
110
- : getCheckpointPayloadStatus(config, state, justifiedCheckpoint.epoch);
111
-
112
- // Determine finalized checkpoint payload status
113
- const finalizedPayloadStatus = isForkPostGloas
114
- ? PayloadStatus.PENDING
115
- : getCheckpointPayloadStatus(config, state, finalizedCheckpoint.epoch);
116
-
117
106
  return new forkchoiceConstructor(
118
107
  config,
119
108
 
@@ -123,8 +112,6 @@ export function initializeForkChoiceFromFinalizedState(
123
112
  finalizedCheckpoint,
124
113
  justifiedBalances,
125
114
  justifiedBalancesGetter,
126
- justifiedPayloadStatus,
127
- finalizedPayloadStatus,
128
115
  {
129
116
  onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
130
117
  onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
@@ -161,7 +148,7 @@ export function initializeForkChoiceFromFinalizedState(
161
148
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
162
149
 
163
150
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
164
- payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
151
+ payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
165
152
  parentBlockHash: isStatePostGloas(state) ? toRootHex(state.latestBlockHash) : null,
166
153
  },
167
154
  currentSlot
@@ -208,19 +195,12 @@ export function initializeForkChoiceFromUnfinalizedState(
208
195
 
209
196
  const isForkPostGloas = computeEpochAtSlot(unfinalizedState.slot) >= config.GLOAS_FORK_EPOCH;
210
197
 
211
- // For unfinalized state, use getCheckpointPayloadStatus to determine the correct status.
212
- // It checks state.execution_payload_availability to determine EMPTY vs FULL.
213
- const justifiedPayloadStatus = getCheckpointPayloadStatus(config, unfinalizedState, justifiedCheckpoint.epoch);
214
- const finalizedPayloadStatus = getCheckpointPayloadStatus(config, unfinalizedState, finalizedCheckpoint.epoch);
215
-
216
198
  const store = new ForkChoiceStore(
217
199
  currentSlot,
218
200
  justifiedCheckpoint,
219
201
  finalizedCheckpoint,
220
202
  justifiedBalances,
221
203
  justifiedBalancesGetter,
222
- justifiedPayloadStatus,
223
- finalizedPayloadStatus,
224
204
  {
225
205
  onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
226
206
  onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
@@ -260,7 +240,7 @@ export function initializeForkChoiceFromUnfinalizedState(
260
240
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
261
241
 
262
242
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
263
- payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
243
+ payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
264
244
  parentBlockHash: isStatePostGloas(unfinalizedState) ? toRootHex(unfinalizedState.latestBlockHash) : null,
265
245
  };
266
246
 
@@ -1,6 +1,6 @@
1
1
  import {Type} from "@chainsafe/ssz";
2
2
  import {BeaconConfig} from "@lodestar/config";
3
- import {CheckpointWithHex, CheckpointWithPayloadStatus, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
3
+ import {CheckpointWithHex, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
4
4
  import {EpochShuffling, IBeaconStateView, PubkeyCache} from "@lodestar/state-transition";
5
5
  import {
6
6
  BeaconBlock,
@@ -18,6 +18,7 @@ import {
18
18
  altair,
19
19
  capella,
20
20
  deneb,
21
+ electra,
21
22
  gloas,
22
23
  phase0,
23
24
  rewards,
@@ -195,7 +196,7 @@ export interface IBeaconChain {
195
196
  ): {state: IBeaconStateView; executionOptimistic: boolean; finalized: boolean} | null;
196
197
  /** Return state bytes by checkpoint */
197
198
  getStateOrBytesByCheckpoint(
198
- checkpoint: CheckpointWithPayloadStatus
199
+ checkpoint: CheckpointWithHex
199
200
  ): Promise<{state: IBeaconStateView | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null>;
200
201
 
201
202
  /**
@@ -231,6 +232,7 @@ export interface IBeaconChain {
231
232
  blockSlot: Slot,
232
233
  blockRootHex: string
233
234
  ): Promise<gloas.SignedExecutionPayloadEnvelope | null>;
235
+ getParentExecutionRequests(parentBlockSlot: Slot, parentBlockRootHex: RootHex): Promise<electra.ExecutionRequests>;
234
236
 
235
237
  produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody>;
236
238
  produceBlock(blockAttributes: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}): Promise<{
@@ -248,7 +250,11 @@ export interface IBeaconChain {
248
250
  /** Process a block until complete */
249
251
  processBlock(block: IBlockInput, opts?: ImportBlockOpts): Promise<void>;
250
252
  /** Process a chain of blocks until complete */
251
- processChainSegment(blocks: IBlockInput[], opts?: ImportBlockOpts): Promise<void>;
253
+ processChainSegment(
254
+ blocks: IBlockInput[],
255
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
256
+ opts?: ImportBlockOpts
257
+ ): Promise<void>;
252
258
 
253
259
  /** Process execution payload envelope: verify, import to fork choice, and persist to DB */
254
260
  processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void>;