@lodestar/beacon-node 1.43.0-dev.433e692fd9 → 1.43.0-dev.4358217e12

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 (311) hide show
  1. package/lib/api/impl/beacon/blocks/index.js +7 -9
  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/GetBlobsTracker.d.ts +1 -1
  12. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  13. package/lib/chain/GetBlobsTracker.js +1 -2
  14. package/lib/chain/GetBlobsTracker.js.map +1 -1
  15. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  16. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  17. package/lib/chain/archiveStore/interface.d.ts +4 -4
  18. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  19. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
  20. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
  21. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
  22. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +2 -2
  23. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  24. package/lib/chain/archiveStore/utils/archiveBlocks.js +110 -58
  25. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  26. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  27. package/lib/chain/blocks/importBlock.js +9 -10
  28. package/lib/chain/blocks/importBlock.js.map +1 -1
  29. package/lib/chain/blocks/importExecutionPayload.d.ts +26 -13
  30. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  31. package/lib/chain/blocks/importExecutionPayload.js +86 -84
  32. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  33. package/lib/chain/blocks/index.d.ts +5 -3
  34. package/lib/chain/blocks/index.d.ts.map +1 -1
  35. package/lib/chain/blocks/index.js +28 -10
  36. package/lib/chain/blocks/index.js.map +1 -1
  37. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +3 -0
  38. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  39. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +20 -0
  40. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  41. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -0
  42. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  43. package/lib/chain/blocks/payloadEnvelopeProcessor.js +7 -5
  44. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  45. package/lib/chain/blocks/types.d.ts +14 -20
  46. package/lib/chain/blocks/types.d.ts.map +1 -1
  47. package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
  48. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  49. package/lib/chain/blocks/utils/chainSegment.js +81 -12
  50. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  51. package/lib/chain/blocks/verifyBlock.d.ts +3 -2
  52. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  53. package/lib/chain/blocks/verifyBlock.js +30 -5
  54. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  55. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  56. package/lib/chain/blocks/verifyBlocksSanityChecks.js +15 -4
  57. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  58. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
  59. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
  60. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +76 -0
  61. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
  62. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +14 -0
  63. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -0
  64. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +25 -0
  65. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -0
  66. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
  67. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
  68. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
  69. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  70. package/lib/chain/chain.d.ts +8 -6
  71. package/lib/chain/chain.d.ts.map +1 -1
  72. package/lib/chain/chain.js +19 -6
  73. package/lib/chain/chain.js.map +1 -1
  74. package/lib/chain/emitter.d.ts +16 -4
  75. package/lib/chain/emitter.d.ts.map +1 -1
  76. package/lib/chain/emitter.js +5 -0
  77. package/lib/chain/emitter.js.map +1 -1
  78. package/lib/chain/errors/blockError.d.ts +8 -1
  79. package/lib/chain/errors/blockError.d.ts.map +1 -1
  80. package/lib/chain/errors/blockError.js +2 -0
  81. package/lib/chain/errors/blockError.js.map +1 -1
  82. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  83. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  84. package/lib/chain/errors/executionPayloadBid.js +1 -0
  85. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  86. package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
  87. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  88. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  89. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  90. package/lib/chain/errors/index.d.ts +1 -0
  91. package/lib/chain/errors/index.d.ts.map +1 -1
  92. package/lib/chain/errors/index.js +1 -0
  93. package/lib/chain/errors/index.js.map +1 -1
  94. package/lib/chain/errors/proposerPreferences.d.ts +33 -0
  95. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  96. package/lib/chain/errors/proposerPreferences.js +13 -0
  97. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  98. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  99. package/lib/chain/forkChoice/index.js +11 -19
  100. package/lib/chain/forkChoice/index.js.map +1 -1
  101. package/lib/chain/interface.d.ts +7 -5
  102. package/lib/chain/interface.d.ts.map +1 -1
  103. package/lib/chain/interface.js.map +1 -1
  104. package/lib/chain/opPools/payloadAttestationPool.d.ts +2 -2
  105. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  106. package/lib/chain/opPools/payloadAttestationPool.js +4 -4
  107. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  108. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  109. package/lib/chain/prepareNextSlot.js +46 -16
  110. package/lib/chain/prepareNextSlot.js.map +1 -1
  111. package/lib/chain/produceBlock/produceBlockBody.d.ts +4 -2
  112. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  113. package/lib/chain/produceBlock/produceBlockBody.js +56 -26
  114. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  115. package/lib/chain/regen/interface.d.ts +1 -0
  116. package/lib/chain/regen/interface.d.ts.map +1 -1
  117. package/lib/chain/regen/interface.js +1 -0
  118. package/lib/chain/regen/interface.js.map +1 -1
  119. package/lib/chain/seenCache/index.d.ts +1 -0
  120. package/lib/chain/seenCache/index.d.ts.map +1 -1
  121. package/lib/chain/seenCache/index.js +1 -0
  122. package/lib/chain/seenCache/index.js.map +1 -1
  123. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +11 -4
  124. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  125. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +20 -18
  126. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  127. package/lib/chain/seenCache/seenProposerPreferences.d.ts +15 -0
  128. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  129. package/lib/chain/seenCache/seenProposerPreferences.js +25 -0
  130. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  131. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  132. package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -1
  133. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  134. package/lib/chain/validation/block.d.ts.map +1 -1
  135. package/lib/chain/validation/block.js +1 -0
  136. package/lib/chain/validation/block.js.map +1 -1
  137. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  138. package/lib/chain/validation/executionPayloadBid.js +13 -1
  139. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  140. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  141. package/lib/chain/validation/executionPayloadEnvelope.js +19 -9
  142. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  143. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  144. package/lib/chain/validation/payloadAttestationMessage.js +4 -3
  145. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  146. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  147. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  148. package/lib/chain/validation/proposerPreferences.js +69 -0
  149. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  150. package/lib/db/repositories/executionPayloadEnvelopeArchive.js +1 -1
  151. package/lib/db/repositories/executionPayloadEnvelopeArchive.js.map +1 -1
  152. package/lib/execution/engine/http.d.ts.map +1 -1
  153. package/lib/execution/engine/http.js +21 -14
  154. package/lib/execution/engine/http.js.map +1 -1
  155. package/lib/execution/engine/interface.d.ts +1 -0
  156. package/lib/execution/engine/interface.d.ts.map +1 -1
  157. package/lib/execution/engine/mock.d.ts.map +1 -1
  158. package/lib/execution/engine/mock.js +6 -0
  159. package/lib/execution/engine/mock.js.map +1 -1
  160. package/lib/execution/engine/types.d.ts +20 -0
  161. package/lib/execution/engine/types.d.ts.map +1 -1
  162. package/lib/execution/engine/types.js +18 -0
  163. package/lib/execution/engine/types.js.map +1 -1
  164. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  165. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  166. package/lib/metrics/metrics/lodestar.js +4 -0
  167. package/lib/metrics/metrics/lodestar.js.map +1 -1
  168. package/lib/network/gossip/interface.d.ts +7 -1
  169. package/lib/network/gossip/interface.d.ts.map +1 -1
  170. package/lib/network/gossip/interface.js +1 -0
  171. package/lib/network/gossip/interface.js.map +1 -1
  172. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  173. package/lib/network/gossip/scoringParameters.js +12 -1
  174. package/lib/network/gossip/scoringParameters.js.map +1 -1
  175. package/lib/network/gossip/topic.d.ts +11 -2
  176. package/lib/network/gossip/topic.d.ts.map +1 -1
  177. package/lib/network/gossip/topic.js +6 -0
  178. package/lib/network/gossip/topic.js.map +1 -1
  179. package/lib/network/network.js +1 -1
  180. package/lib/network/network.js.map +1 -1
  181. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  182. package/lib/network/processor/gossipHandlers.js +32 -12
  183. package/lib/network/processor/gossipHandlers.js.map +1 -1
  184. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  185. package/lib/network/processor/gossipQueues/index.js +5 -0
  186. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  187. package/lib/network/processor/index.d.ts.map +1 -1
  188. package/lib/network/processor/index.js +1 -0
  189. package/lib/network/processor/index.js.map +1 -1
  190. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  191. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  192. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  193. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  194. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  195. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  196. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  197. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  198. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  199. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  200. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  201. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  202. package/lib/node/nodejs.d.ts.map +1 -1
  203. package/lib/node/nodejs.js +4 -2
  204. package/lib/node/nodejs.js.map +1 -1
  205. package/lib/node/notifier.js +7 -1
  206. package/lib/node/notifier.js.map +1 -1
  207. package/lib/sync/range/batch.d.ts +12 -2
  208. package/lib/sync/range/batch.d.ts.map +1 -1
  209. package/lib/sync/range/batch.js +56 -30
  210. package/lib/sync/range/batch.js.map +1 -1
  211. package/lib/sync/range/chain.d.ts +6 -2
  212. package/lib/sync/range/chain.d.ts.map +1 -1
  213. package/lib/sync/range/chain.js +4 -3
  214. package/lib/sync/range/chain.js.map +1 -1
  215. package/lib/sync/range/range.d.ts.map +1 -1
  216. package/lib/sync/range/range.js +17 -6
  217. package/lib/sync/range/range.js.map +1 -1
  218. package/lib/sync/types.d.ts +34 -0
  219. package/lib/sync/types.d.ts.map +1 -1
  220. package/lib/sync/types.js +34 -0
  221. package/lib/sync/types.js.map +1 -1
  222. package/lib/sync/unknownBlock.d.ts +24 -1
  223. package/lib/sync/unknownBlock.d.ts.map +1 -1
  224. package/lib/sync/unknownBlock.js +649 -53
  225. package/lib/sync/unknownBlock.js.map +1 -1
  226. package/lib/sync/utils/downloadByRange.d.ts +46 -10
  227. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  228. package/lib/sync/utils/downloadByRange.js +147 -24
  229. package/lib/sync/utils/downloadByRange.js.map +1 -1
  230. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  231. package/lib/sync/utils/downloadByRoot.js +6 -2
  232. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  233. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  234. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  235. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  236. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  237. package/lib/util/sszBytes.d.ts.map +1 -1
  238. package/lib/util/sszBytes.js +16 -3
  239. package/lib/util/sszBytes.js.map +1 -1
  240. package/package.json +17 -16
  241. package/src/api/impl/beacon/blocks/index.ts +9 -9
  242. package/src/api/impl/beacon/state/utils.ts +2 -2
  243. package/src/api/impl/lodestar/index.ts +1 -1
  244. package/src/api/impl/validator/index.ts +0 -4
  245. package/src/chain/GetBlobsTracker.ts +1 -2
  246. package/src/chain/archiveStore/archiveStore.ts +5 -5
  247. package/src/chain/archiveStore/interface.ts +4 -4
  248. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +4 -4
  249. package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
  250. package/src/chain/blocks/importBlock.ts +7 -13
  251. package/src/chain/blocks/importExecutionPayload.ts +106 -103
  252. package/src/chain/blocks/index.ts +44 -13
  253. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +27 -0
  254. package/src/chain/blocks/payloadEnvelopeProcessor.ts +7 -6
  255. package/src/chain/blocks/types.ts +14 -25
  256. package/src/chain/blocks/utils/chainSegment.ts +106 -17
  257. package/src/chain/blocks/verifyBlock.ts +35 -6
  258. package/src/chain/blocks/verifyBlocksSanityChecks.ts +16 -7
  259. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
  260. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +38 -0
  261. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  262. package/src/chain/chain.ts +36 -19
  263. package/src/chain/emitter.ts +15 -3
  264. package/src/chain/errors/blockError.ts +4 -1
  265. package/src/chain/errors/executionPayloadBid.ts +6 -0
  266. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  267. package/src/chain/errors/index.ts +1 -0
  268. package/src/chain/errors/proposerPreferences.ts +39 -0
  269. package/src/chain/forkChoice/index.ts +8 -24
  270. package/src/chain/interface.ts +11 -3
  271. package/src/chain/opPools/payloadAttestationPool.ts +4 -8
  272. package/src/chain/prepareNextSlot.ts +60 -17
  273. package/src/chain/produceBlock/produceBlockBody.ts +77 -23
  274. package/src/chain/regen/interface.ts +1 -0
  275. package/src/chain/seenCache/index.ts +1 -0
  276. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +22 -20
  277. package/src/chain/seenCache/seenProposerPreferences.ts +29 -0
  278. package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
  279. package/src/chain/validation/block.ts +1 -0
  280. package/src/chain/validation/executionPayloadBid.ts +14 -0
  281. package/src/chain/validation/executionPayloadEnvelope.ts +20 -10
  282. package/src/chain/validation/payloadAttestationMessage.ts +5 -3
  283. package/src/chain/validation/proposerPreferences.ts +91 -0
  284. package/src/db/repositories/executionPayloadEnvelopeArchive.ts +1 -1
  285. package/src/execution/engine/http.ts +21 -14
  286. package/src/execution/engine/interface.ts +1 -0
  287. package/src/execution/engine/mock.ts +8 -1
  288. package/src/execution/engine/types.ts +41 -0
  289. package/src/metrics/metrics/lodestar.ts +4 -0
  290. package/src/network/gossip/interface.ts +6 -0
  291. package/src/network/gossip/scoringParameters.ts +14 -1
  292. package/src/network/gossip/topic.ts +6 -0
  293. package/src/network/network.ts +1 -1
  294. package/src/network/processor/gossipHandlers.ts +41 -16
  295. package/src/network/processor/gossipQueues/index.ts +5 -0
  296. package/src/network/processor/index.ts +1 -0
  297. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  298. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  299. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  300. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  301. package/src/node/nodejs.ts +4 -2
  302. package/src/node/notifier.ts +8 -1
  303. package/src/sync/range/batch.ts +90 -35
  304. package/src/sync/range/chain.ts +13 -5
  305. package/src/sync/range/range.ts +18 -6
  306. package/src/sync/types.ts +72 -0
  307. package/src/sync/unknownBlock.ts +810 -57
  308. package/src/sync/utils/downloadByRange.ts +256 -39
  309. package/src/sync/utils/downloadByRoot.ts +12 -2
  310. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  311. package/src/util/sszBytes.ts +21 -3
@@ -1,14 +1,19 @@
1
1
  import {routes} from "@lodestar/api";
2
- import {ExecutionStatus, PayloadExecutionStatus} from "@lodestar/fork-choice";
3
- import {SLOTS_PER_EPOCH} from "@lodestar/params";
4
- import {getExecutionPayloadEnvelopeSignatureSet, isStatePostGloas} from "@lodestar/state-transition";
5
- import {byteArrayEquals, fromHex, toRootHex} from "@lodestar/utils";
2
+ import {ExecutionStatus, PayloadExecutionStatus, getSafeExecutionBlockHash} from "@lodestar/fork-choice";
3
+ import {isStatePostGloas} from "@lodestar/state-transition";
4
+ import {fromHex, isErrorAborted} from "@lodestar/utils";
5
+ import {ZERO_HASH_HEX} from "../../constants/index.js";
6
6
  import {ExecutionPayloadStatus} from "../../execution/index.js";
7
7
  import {isQueueErrorAborted} from "../../util/queue/index.js";
8
8
  import {BeaconChain} from "../chain.js";
9
9
  import {RegenCaller} from "../regen/interface.js";
10
10
  import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
11
11
  import {ImportPayloadOpts} from "./types.js";
12
+ import {
13
+ verifyExecutionPayloadEnvelope,
14
+ verifyExecutionPayloadEnvelopeSignature,
15
+ } from "./verifyExecutionPayloadEnvelope.js";
16
+ import {verifyPayloadsDataAvailability} from "./verifyPayloadsDataAvailability.js";
12
17
 
13
18
  const EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS = 64;
14
19
 
@@ -16,7 +21,7 @@ export enum PayloadErrorCode {
16
21
  EXECUTION_ENGINE_INVALID = "PAYLOAD_ERROR_EXECUTION_ENGINE_INVALID",
17
22
  EXECUTION_ENGINE_ERROR = "PAYLOAD_ERROR_EXECUTION_ENGINE_ERROR",
18
23
  BLOCK_NOT_IN_FORK_CHOICE = "PAYLOAD_ERROR_BLOCK_NOT_IN_FORK_CHOICE",
19
- STATE_TRANSITION_ERROR = "PAYLOAD_ERROR_STATE_TRANSITION_ERROR",
24
+ ENVELOPE_VERIFICATION_ERROR = "PAYLOAD_ERROR_ENVELOPE_VERIFICATION_ERROR",
20
25
  INVALID_SIGNATURE = "PAYLOAD_ERROR_INVALID_SIGNATURE",
21
26
  }
22
27
 
@@ -36,7 +41,7 @@ export type PayloadErrorType =
36
41
  blockRootHex: string;
37
42
  }
38
43
  | {
39
- code: PayloadErrorCode.STATE_TRANSITION_ERROR;
44
+ code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR;
40
45
  message: string;
41
46
  }
42
47
  | {
@@ -68,18 +73,22 @@ function toForkChoiceExecutionStatus(status: ExecutionPayloadStatus): PayloadExe
68
73
  /**
69
74
  * Import an execution payload envelope after all data is available.
70
75
  *
71
- * This function:
72
- * 1. Emits `execution_payload_available` if payload is for current slot
73
- * 2. Gets the ProtoBlock from fork choice
74
- * 3. Applies write-queue backpressure (waitForSpace) early, before verification
75
- * 4. Regenerates the block state
76
- * 5. Runs EL verification (notifyNewPayload) in parallel with signature verification and processExecutionPayloadEnvelope
77
- * 6. Persists verified payload envelope to hot DB
78
- * 7. Updates fork choice
79
- * 8. Caches the post-execution payload state
80
- * 9. Records metrics for column sources
81
- * 10. Emits `execution_payload` for recent enough payloads after successful import
76
+ * The envelope is only verified here, no state mutation. State effects from the payload
77
+ * are applied on the next block via processParentExecutionPayload.
82
78
  *
79
+ * The DA wait must have run upstream (range sync awaits DA in `verifyBlocksInEpoch` for the
80
+ * whole segment; gossip / API path uses the `processExecutionPayload` wrapper below).
81
+ *
82
+ * Steps:
83
+ * 1. Emit `execution_payload_available` event for payload attestation
84
+ * 2. Get the ProtoBlock from fork choice
85
+ * 3. Regenerate state for envelope verification
86
+ * 4. Verify envelope (fields against state, signature, and EL in parallel where possible)
87
+ * 5. Persist verified payload envelope to hot DB (waits for write-queue space for backpressure)
88
+ * 6. Update fork choice (transitions the block's PENDING variant to FULL)
89
+ * 7. Queue notifyForkchoiceUpdate to engine api
90
+ * 8. Record metrics for payload envelope and column sources
91
+ * 9. Emit `execution_payload` event
83
92
  */
84
93
  export async function importExecutionPayload(
85
94
  this: BeaconChain,
@@ -88,17 +97,18 @@ export async function importExecutionPayload(
88
97
  ): Promise<void> {
89
98
  const signedEnvelope = payloadInput.getPayloadEnvelope();
90
99
  const envelope = signedEnvelope.message;
100
+ const slot = envelope.payload.slotNumber;
91
101
  const blockRootHex = payloadInput.blockRootHex;
92
102
  const blockHashHex = payloadInput.getBlockHashHex();
93
- const fork = this.config.getForkName(envelope.slot);
103
+ const fork = this.config.getForkName(slot);
94
104
 
95
- // 1. Emit `execution_payload_available` event at the start of import. At this point the payload input
96
- // is already complete, so the payload and required data are available for payload attestation.
97
- // This event is only about availability, not validity of the execution payload, hence we can emit
98
- // it before getting a response from the execution client on whether the payload is valid or not.
99
- if (this.clock.currentSlot - envelope.slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
105
+ // 1. Emit `execution_payload_available` event at the start of import. At this point the
106
+ // payload input is already complete, so the payload and required data are available for
107
+ // payload attestation. This event only signals availability (not validity), so we can emit
108
+ // it before getting a response from the EL on whether the payload is valid or not.
109
+ if (this.clock.currentSlot - slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
100
110
  this.emitter.emit(routes.events.EventType.executionPayloadAvailable, {
101
- slot: envelope.slot,
111
+ slot,
102
112
  blockRoot: blockRootHex,
103
113
  });
104
114
  }
@@ -112,12 +122,7 @@ export async function importExecutionPayload(
112
122
  });
113
123
  }
114
124
 
115
- // 3. Apply backpressure from the write queue early, before doing verification work.
116
- // The actual DB write is deferred until after verification succeeds.
117
- await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
118
-
119
- // 4. Get pre-state for processExecutionPayloadEnvelope
120
- // We need the block state (post-block, pre-payload) to process the envelope
125
+ // 3. Regenerate state for envelope verification
121
126
  const blockState = await this.regen.getBlockSlotState(
122
127
  protoBlock,
123
128
  protoBlock.slot,
@@ -126,15 +131,30 @@ export async function importExecutionPayload(
126
131
  );
127
132
  if (!isStatePostGloas(blockState)) {
128
133
  throw new PayloadError({
129
- code: PayloadErrorCode.STATE_TRANSITION_ERROR,
130
- message: `Expected gloas+ block state for payload import, got fork=${blockState.forkName}`,
134
+ code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
135
+ message: `Expected gloas+ state for payload import, got fork=${blockState.forkName}`,
131
136
  });
132
137
  }
133
138
 
134
- // 5. Run verification steps in parallel
135
- // Note: No data availability check needed here - importExecutionPayload is only
136
- // called when payloadInput.isComplete() is true, so all data is already available.
137
- const [execResult, signatureValid, postPayloadResult] = await Promise.all([
139
+ // 4. Verify envelope fields against state first to fail fast before the EL + BLS work.
140
+ // When validSignature is true, gossip/API has already verified both the signature and the
141
+ // executionRequestsRoot, so we skip those checks here.
142
+ try {
143
+ verifyExecutionPayloadEnvelope(this.config, blockState, envelope, {
144
+ verifyExecutionRequestsRoot: !opts.validSignature,
145
+ });
146
+ } catch (e) {
147
+ throw new PayloadError(
148
+ {
149
+ code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
150
+ message: (e as Error).message,
151
+ },
152
+ `Envelope verification error: ${(e as Error).message}`
153
+ );
154
+ }
155
+
156
+ // 4a. Run EL and signature verification in parallel
157
+ const [execResult, signatureValid] = await Promise.all([
138
158
  this.executionEngine.notifyNewPayload(
139
159
  fork,
140
160
  envelope.payload,
@@ -145,45 +165,22 @@ export async function importExecutionPayload(
145
165
 
146
166
  opts.validSignature === true
147
167
  ? Promise.resolve(true)
148
- : (async () => {
149
- const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
150
- this.config,
151
- this.pubkeyCache,
152
- blockState,
153
- signedEnvelope,
154
- payloadInput.proposerIndex
155
- );
156
- return this.bls.verifySignatureSets([signatureSet]);
157
- })(),
158
-
159
- // Signature verified separately above.
160
- // State root check is done separately below with better error typing (matching block pipeline pattern).
161
- (async () => {
162
- try {
163
- return {
164
- postPayloadState: blockState.processExecutionPayloadEnvelope(signedEnvelope, {
165
- verifySignature: false,
166
- verifyStateRoot: false,
167
- }),
168
- };
169
- } catch (e) {
170
- throw new PayloadError(
171
- {
172
- code: PayloadErrorCode.STATE_TRANSITION_ERROR,
173
- message: (e as Error).message,
174
- },
175
- `State transition error: ${(e as Error).message}`
176
- );
177
- }
178
- })(),
168
+ : verifyExecutionPayloadEnvelopeSignature(
169
+ this.config,
170
+ blockState,
171
+ this.pubkeyCache,
172
+ signedEnvelope,
173
+ payloadInput.proposerIndex,
174
+ this.bls
175
+ ),
179
176
  ]);
180
177
 
181
- // 5a. Check signature verification result
178
+ // 4b. Check signature verification result
182
179
  if (!signatureValid) {
183
180
  throw new PayloadError({code: PayloadErrorCode.INVALID_SIGNATURE});
184
181
  }
185
182
 
186
- // 5b. Handle EL response
183
+ // 4c. Handle EL response
187
184
  switch (execResult.status) {
188
185
  case ExecutionPayloadStatus.VALID:
189
186
  break;
@@ -209,69 +206,75 @@ export async function importExecutionPayload(
209
206
  });
210
207
  }
211
208
 
212
- // 5c. Verify envelope state root matches post-state
213
- const postPayloadState = postPayloadResult.postPayloadState;
214
- const postPayloadStateRoot = postPayloadState.hashTreeRoot();
215
- if (!byteArrayEquals(envelope.stateRoot, postPayloadStateRoot)) {
216
- throw new PayloadError({
217
- code: PayloadErrorCode.STATE_TRANSITION_ERROR,
218
- message: `Envelope state root mismatch expected=${toRootHex(envelope.stateRoot)} actual=${toRootHex(postPayloadStateRoot)}`,
219
- });
220
- }
221
-
222
- // 6. Persist payload envelope to hot DB (performed asynchronously to avoid blocking)
209
+ // 5. Persist payload envelope to hot DB. Wait for write-queue space here to apply backpressure
210
+ // on the import pipeline during sync, then perform the write asynchronously to avoid blocking.
211
+ await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
223
212
  this.unfinalizedPayloadEnvelopeWrites.push(payloadInput).catch((e) => {
224
213
  if (!isQueueErrorAborted(e)) {
225
214
  this.logger.error(
226
215
  "Error pushing payload envelope to unfinalized write queue",
227
- {slot: envelope.slot, blockRoot: blockRootHex},
216
+ {slot, blockRoot: blockRootHex},
228
217
  e as Error
229
218
  );
230
219
  }
231
220
  });
232
221
 
233
- // 7. Update fork choice
234
- this.forkChoice.onExecutionPayload(
235
- blockRootHex,
236
- blockHashHex,
237
- envelope.payload.blockNumber,
238
- toRootHex(postPayloadStateRoot),
239
- toForkChoiceExecutionStatus(execResult.status)
240
- );
222
+ // 6. Update fork choice, transitions the block's PENDING variant to FULL
223
+ const execStatus = toForkChoiceExecutionStatus(execResult.status);
224
+ this.forkChoice.onExecutionPayload(blockRootHex, blockHashHex, envelope.payload.blockNumber, execStatus);
241
225
 
242
- // 8. Cache payload state
243
- this.regen.processState(blockRootHex, postPayloadState);
244
- if (postPayloadState.slot % SLOTS_PER_EPOCH === 0) {
245
- const {checkpoint} = postPayloadState.computeAnchorCheckpoint();
246
- this.regen.addCheckpointState(checkpoint, postPayloadState);
226
+ // 7. Queue notifyForkchoiceUpdate to engine api
227
+ const head = this.forkChoice.getHead();
228
+ if (!this.opts.disableImportExecutionFcU && blockRootHex === head.blockRoot) {
229
+ const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
230
+ const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
231
+ this.executionEngine.notifyForkchoiceUpdate(fork, blockHashHex, safeBlockHash, finalizedBlockHash).catch((e) => {
232
+ if (!isErrorAborted(e) && !isQueueErrorAborted(e)) {
233
+ this.logger.error("Error pushing notifyForkchoiceUpdate()", {blockHashHex, finalizedBlockHash}, e);
234
+ }
235
+ });
247
236
  }
248
237
 
249
- // 9. Record metrics for payload envelope and column sources
238
+ // 8. Record metrics for payload envelope and column sources
250
239
  this.metrics?.importPayload.bySource.inc({source: payloadInput.getPayloadEnvelopeSource().source});
251
240
  for (const {source} of payloadInput.getSampledColumnsWithSource()) {
252
241
  this.metrics?.importPayload.columnsBySource.inc({source});
253
242
  }
254
243
 
255
- const stateRootHex = toRootHex(envelope.stateRoot);
256
-
257
- // 10. Emit event after payload is fully verified and imported to fork choice, only for recent enough payloads
258
- if (this.clock.currentSlot - envelope.slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
244
+ // 9. Emit event after payload is fully verified and imported to fork choice, only for recent enough payloads
245
+ if (this.clock.currentSlot - slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
259
246
  this.emitter.emit(routes.events.EventType.executionPayload, {
260
- slot: envelope.slot,
247
+ slot,
261
248
  builderIndex: envelope.builderIndex,
262
249
  blockHash: blockHashHex,
263
250
  blockRoot: blockRootHex,
264
- stateRoot: stateRootHex,
265
251
  // TODO GLOAS: revisit once we support optimistic import
266
252
  executionOptimistic: false,
267
253
  });
268
254
  }
269
255
 
270
256
  this.logger.verbose("Execution payload imported", {
271
- slot: envelope.slot,
257
+ slot,
272
258
  builderIndex: envelope.builderIndex,
273
259
  blockRoot: blockRootHex,
274
260
  blockHash: blockHashHex,
275
- stateRoot: stateRootHex,
276
261
  });
277
262
  }
263
+
264
+ /**
265
+ * Process an execution payload envelope end-to-end: wait for DA, then import.
266
+ *
267
+ * Used by the PayloadEnvelopeProcessor queue (gossip / API / unknown-payload sync) — i.e.
268
+ * callers that have NOT already awaited DA themselves. Range sync's inline dispatch in
269
+ * processBlocks skips this wrapper and calls `importExecutionPayload` directly, since
270
+ * `verifyBlocksInEpoch` already awaited DA for the segment.
271
+ */
272
+ export async function processExecutionPayload(
273
+ this: BeaconChain,
274
+ payloadInput: PayloadEnvelopeInput,
275
+ signal: AbortSignal,
276
+ opts: ImportPayloadOpts = {}
277
+ ): Promise<void> {
278
+ await verifyPayloadsDataAvailability([payloadInput], signal);
279
+ await importExecutionPayload.call(this, payloadInput, opts);
280
+ }
@@ -1,4 +1,4 @@
1
- import {SignedBeaconBlock} from "@lodestar/types";
1
+ import {SignedBeaconBlock, Slot} from "@lodestar/types";
2
2
  import {isErrorAborted, toRootHex} from "@lodestar/utils";
3
3
  import {Metrics} from "../../metrics/metrics.js";
4
4
  import {nextEventLoop} from "../../util/eventLoop.js";
@@ -8,6 +8,8 @@ import {BlockError, BlockErrorCode, isBlockErrorAborted} from "../errors/index.j
8
8
  import {BlockProcessOpts} from "../options.js";
9
9
  import {IBlockInput} from "./blockInput/types.js";
10
10
  import {importBlock} from "./importBlock.js";
11
+ import {importExecutionPayload} from "./importExecutionPayload.js";
12
+ import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
11
13
  import {FullyVerifiedBlock, ImportBlockOpts} from "./types.js";
12
14
  import {assertLinearChainSegment} from "./utils/chainSegment.js";
13
15
  import {verifyBlocksInEpoch} from "./verifyBlock.js";
@@ -21,20 +23,24 @@ const QUEUE_MAX_LENGTH = 256;
21
23
  * BlockProcessor processes block jobs in a queued fashion, one after the other.
22
24
  */
23
25
  export class BlockProcessor {
24
- readonly jobQueue: JobItemQueue<[IBlockInput[], ImportBlockOpts], void>;
26
+ readonly jobQueue: JobItemQueue<[IBlockInput[], Map<Slot, PayloadEnvelopeInput> | null, ImportBlockOpts], void>;
25
27
 
26
28
  constructor(chain: BeaconChain, metrics: Metrics | null, opts: BlockProcessOpts, signal: AbortSignal) {
27
- this.jobQueue = new JobItemQueue<[IBlockInput[], ImportBlockOpts], void>(
28
- (job, importOpts) => {
29
- return processBlocks.call(chain, job, {...opts, ...importOpts});
29
+ this.jobQueue = new JobItemQueue<[IBlockInput[], Map<Slot, PayloadEnvelopeInput> | null, ImportBlockOpts], void>(
30
+ (job, payloadEnvelopes, importOpts) => {
31
+ return processBlocks.call(chain, job, payloadEnvelopes, {...opts, ...importOpts});
30
32
  },
31
33
  {maxLength: QUEUE_MAX_LENGTH, noYieldIfOneItem: true, signal},
32
34
  metrics?.blockProcessorQueue ?? undefined
33
35
  );
34
36
  }
35
37
 
36
- async processBlocksJob(job: IBlockInput[], opts: ImportBlockOpts = {}): Promise<void> {
37
- await this.jobQueue.push(job, opts);
38
+ async processBlocksJob(
39
+ job: IBlockInput[],
40
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
41
+ opts: ImportBlockOpts = {}
42
+ ): Promise<void> {
43
+ await this.jobQueue.push(job, payloadEnvelopes, opts);
38
44
  }
39
45
  }
40
46
 
@@ -51,16 +57,13 @@ export class BlockProcessor {
51
57
  export async function processBlocks(
52
58
  this: BeaconChain,
53
59
  blocks: IBlockInput[],
60
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
54
61
  opts: BlockProcessOpts & ImportBlockOpts
55
62
  ): Promise<void> {
56
63
  if (blocks.length === 0) {
57
64
  return; // TODO: or throw?
58
65
  }
59
66
 
60
- if (blocks.length > 1) {
61
- assertLinearChainSegment(this.config, blocks);
62
- }
63
-
64
67
  try {
65
68
  const {relevantBlocks, parentSlots, parentBlock} = verifyBlocksSanityChecks(this, blocks, opts);
66
69
 
@@ -70,10 +73,25 @@ export async function processBlocks(
70
73
  return;
71
74
  }
72
75
 
76
+ const {warnings: orphanedPayloads} = assertLinearChainSegment(
77
+ this.config,
78
+ relevantBlocks,
79
+ payloadEnvelopes,
80
+ parentBlock
81
+ );
82
+ if (orphanedPayloads != null) {
83
+ for (const orphaned of orphanedPayloads) {
84
+ this.logger.debug("Orphaned payload envelope in chain segment", {
85
+ slot: orphaned.slot,
86
+ blockRoot: orphaned.payloadEnvelopeInput.blockRootHex,
87
+ });
88
+ }
89
+ }
90
+
73
91
  // Fully verify a block to be imported immediately after. Does not produce any side-effects besides adding intermediate
74
92
  // states in the state cache through regen.
75
93
  const {postStates, dataAvailabilityStatuses, proposerBalanceDeltas, segmentExecStatus, indexedAttestationsByBlock} =
76
- await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, opts);
94
+ await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, payloadEnvelopes, opts);
77
95
 
78
96
  // If segmentExecStatus has lvhForkchoice then, the entire segment should be invalid
79
97
  // and we need to further propagate
@@ -89,7 +107,6 @@ export async function processBlocks(
89
107
  (block, i): FullyVerifiedBlock => ({
90
108
  blockInput: block,
91
109
  postState: postStates[i],
92
- postPayloadState: null,
93
110
  parentBlockSlot: parentSlots[i],
94
111
  executionStatus: executionStatuses[i],
95
112
  // start supporting optimistic syncing/processing
@@ -104,6 +121,20 @@ export async function processBlocks(
104
121
  for (const fullyVerifiedBlock of fullyVerifiedBlocks) {
105
122
  // TODO: Consider batching importBlock too if it takes significant time
106
123
  await importBlock.call(this, fullyVerifiedBlock, opts);
124
+
125
+ const slot = fullyVerifiedBlock.blockInput.getBlock().message.slot;
126
+ const payloadInput = payloadEnvelopes?.get(slot);
127
+ if (payloadInput?.hasPayloadEnvelope()) {
128
+ if (!payloadInput.isComplete()) {
129
+ // we validated DA before reaching this
130
+ throw new Error(`Payload envelope for slot ${slot} not complete after DA verification`);
131
+ }
132
+ // we already awaited DA in verifyBlocksInEpoch for this segment
133
+ // TODO GLOAS: may need FullyVerifiedPayload here with DatAvailabilityStatus added from here
134
+ // the current flow use that data from the forkchoice pending node which is not correct
135
+ await importExecutionPayload.call(this, payloadInput, {validSignature: false});
136
+ }
137
+
107
138
  await nextEventLoop();
108
139
  }
109
140
  } catch (e) {
@@ -73,6 +73,7 @@ export class PayloadEnvelopeInput {
73
73
  private timeCreatedSec: number;
74
74
 
75
75
  private readonly payloadEnvelopeDataPromise: PromiseParts<gloas.SignedExecutionPayloadEnvelope>;
76
+ private readonly allDataPromise: PromiseParts<gloas.DataColumnSidecar[]>;
76
77
  private readonly columnsDataPromise: PromiseParts<gloas.DataColumnSidecar[]>;
77
78
 
78
79
  state: PayloadEnvelopeInputState;
@@ -97,6 +98,7 @@ export class PayloadEnvelopeInput {
97
98
  this.custodyColumns = props.custodyColumns;
98
99
  this.timeCreatedSec = props.timeCreatedSec;
99
100
  this.payloadEnvelopeDataPromise = createPromise();
101
+ this.allDataPromise = createPromise();
100
102
  this.columnsDataPromise = createPromise();
101
103
 
102
104
  const noBlobs = props.bid.blobKzgCommitments.length === 0;
@@ -105,6 +107,7 @@ export class PayloadEnvelopeInput {
105
107
 
106
108
  if (hasAllData) {
107
109
  this.state = {hasPayload: false, hasAllData: true, hasComputedAllData: true};
110
+ this.allDataPromise.resolve(this.getSampledColumns());
108
111
  this.columnsDataPromise.resolve(this.getSampledColumns());
109
112
  } else {
110
113
  this.state = {hasPayload: false, hasAllData: false, hasComputedAllData: false};
@@ -203,6 +206,12 @@ export class PayloadEnvelopeInput {
203
206
  return true;
204
207
  }
205
208
 
209
+ // Resolve allDataPromise on the first transition to hasAllData (either sampled-complete or
210
+ // reconstruction-threshold branch). Guarded so it fires exactly once.
211
+ if (!this.state.hasAllData && hasAllData) {
212
+ this.allDataPromise.resolve(sampledColumns);
213
+ }
214
+
206
215
  if (hasComputedAllData) {
207
216
  this.columnsDataPromise.resolve(sampledColumns);
208
217
  }
@@ -315,6 +324,24 @@ export class PayloadEnvelopeInput {
315
324
  return this.state.hasComputedAllData;
316
325
  }
317
326
 
327
+ waitForAllData(timeout: number, signal?: AbortSignal): Promise<gloas.DataColumnSidecar[]> {
328
+ if (this.state.hasAllData) {
329
+ return Promise.resolve(this.getSampledColumns());
330
+ }
331
+ return withTimeout(() => this.allDataPromise.promise, timeout, signal);
332
+ }
333
+
334
+ async waitForEnvelopeAndAllData(timeout: number, signal?: AbortSignal): Promise<this> {
335
+ if (!this.state.hasPayload || !this.state.hasAllData) {
336
+ await withTimeout(
337
+ () => Promise.all([this.payloadEnvelopeDataPromise.promise, this.allDataPromise.promise]),
338
+ timeout,
339
+ signal
340
+ );
341
+ }
342
+ return this;
343
+ }
344
+
318
345
  waitForComputedAllData(timeout: number, signal?: AbortSignal): Promise<gloas.DataColumnSidecar[]> {
319
346
  if (this.state.hasComputedAllData) {
320
347
  return Promise.resolve(this.getSampledColumns());
@@ -2,7 +2,7 @@ import {Metrics} from "../../metrics/metrics.js";
2
2
  import {JobItemQueue} from "../../util/queue/index.js";
3
3
  import type {BeaconChain} from "../chain.js";
4
4
  import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
5
- import {importExecutionPayload} from "./importExecutionPayload.js";
5
+ import {processExecutionPayload} from "./importExecutionPayload.js";
6
6
  import {ImportPayloadOpts} from "./types.js";
7
7
 
8
8
  // TODO GLOAS: Set to be equal to DEFAULT_MAX_PENDING_UNFINALIZED_PAYLOAD_ENVELOPE_WRITES for now
@@ -16,6 +16,11 @@ enum PayloadEnvelopeImportStatus {
16
16
 
17
17
  /**
18
18
  * PayloadEnvelopeProcessor processes payload envelope jobs in a queued fashion, one after the other.
19
+ *
20
+ * Jobs are enqueued only on envelope arrival (gossip or API). The envelope may reach us before
21
+ * the sampled data columns; importExecutionPayload awaits `verifyPayloadsDataAvailability`
22
+ * internally, so a queued job can pend for up to `PAYLOAD_DATA_AVAILABILITY_TIMEOUT` while
23
+ * waiting for columns. Duplicate triggers for the same payloadInput are deduped via `importStatus`.
19
24
  */
20
25
  export class PayloadEnvelopeProcessor {
21
26
  readonly jobQueue: JobItemQueue<[PayloadEnvelopeInput, ImportPayloadOpts], void>;
@@ -25,7 +30,7 @@ export class PayloadEnvelopeProcessor {
25
30
  this.jobQueue = new JobItemQueue<[PayloadEnvelopeInput, ImportPayloadOpts], void>(
26
31
  (payloadInput, opts) => {
27
32
  this.importStatus.set(payloadInput, PayloadEnvelopeImportStatus.importing);
28
- return importExecutionPayload.call(chain, payloadInput, opts);
33
+ return processExecutionPayload.call(chain, payloadInput, signal, opts);
29
34
  },
30
35
  {maxLength: QUEUE_MAX_LENGTH, noYieldIfOneItem: true, signal},
31
36
  metrics?.payloadEnvelopeProcessorQueue ?? undefined
@@ -33,10 +38,6 @@ export class PayloadEnvelopeProcessor {
33
38
  }
34
39
 
35
40
  async processPayloadEnvelopeJob(payloadInput: PayloadEnvelopeInput, opts: ImportPayloadOpts = {}): Promise<void> {
36
- if (!payloadInput.isComplete()) {
37
- return;
38
- }
39
-
40
41
  if (this.importStatus.get(payloadInput) !== undefined) {
41
42
  return;
42
43
  }
@@ -1,5 +1,5 @@
1
1
  import type {ChainForkConfig} from "@lodestar/config";
2
- import {BlockExecutionStatus, PayloadExecutionStatus} from "@lodestar/fork-choice";
2
+ import type {BlockExecutionStatus, PayloadExecutionStatus} from "@lodestar/fork-choice";
3
3
  import {ForkSeq} from "@lodestar/params";
4
4
  import {DataAvailabilityStatus, IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
5
5
  import type {IndexedAttestation, Slot, fulu} from "@lodestar/types";
@@ -43,8 +43,9 @@ export enum BlobSidecarValidation {
43
43
 
44
44
  export type ImportPayloadOpts = {
45
45
  /**
46
- * Set to true if envelope signature was already verified (e.g., during gossip/API validation).
47
- * When false/undefined, signature will be verified during import.
46
+ * Set to true when the envelope was already validated upstream (e.g., gossip/API validation):
47
+ * signature is trusted and execution_requests_root was already verified against the bid.
48
+ * When false/undefined, both are verified during import.
48
49
  */
49
50
  validSignature?: boolean;
50
51
  };
@@ -88,7 +89,14 @@ export type ImportBlockOpts = {
88
89
  seenTimestampSec?: number;
89
90
  };
90
91
 
91
- type FullyVerifiedBlockBase = {
92
+ /**
93
+ * A wrapper around a `SignedBeaconBlock` that indicates that this block is fully verified and ready to import.
94
+ *
95
+ * `executionStatus` reflects the outcome of execution payload verification at block-import time:
96
+ * - pre-gloas: Valid | Syncing | PreMerge (from EL notifyNewPayload against the in-block payload)
97
+ * - post-gloas: PayloadSeparated (payload arrives separately as an envelope and is imported later)
98
+ */
99
+ export type FullyVerifiedBlock = {
92
100
  blockInput: IBlockInput;
93
101
  postState: IBeaconStateView;
94
102
  parentBlockSlot: Slot;
@@ -98,25 +106,6 @@ type FullyVerifiedBlockBase = {
98
106
  indexedAttestations: IndexedAttestation[];
99
107
  /** Seen timestamp seconds */
100
108
  seenTimestampSec: number;
109
+ /** If the execution payload couldn't be verified because of EL syncing status, used in optimistic sync */
110
+ executionStatus: BlockExecutionStatus | PayloadExecutionStatus;
101
111
  };
102
-
103
- /**
104
- * A wrapper around a `SignedBeaconBlock` that indicates that this block is fully verified and ready to import.
105
- *
106
- * Discriminated union on `postPayloadState`:
107
- * - `null` → block has no pre-verified envelope; `executionStatus` is any `BlockExecutionStatus`
108
- * - non-null → envelope was pre-verified during state transition; `executionStatus` is narrowed to
109
- * `Valid | Syncing` (matching what `forkChoice.onExecutionPayload` expects)
110
- */
111
- export type FullyVerifiedBlock = FullyVerifiedBlockBase &
112
- (
113
- | {
114
- postPayloadState: null;
115
- /** If the execution payload couldn't be verified because of EL syncing status, used in optimistic sync or for merge block */
116
- executionStatus: BlockExecutionStatus;
117
- }
118
- | {
119
- postPayloadState: IBeaconStateView;
120
- executionStatus: PayloadExecutionStatus;
121
- }
122
- );