@lodestar/beacon-node 1.43.0-dev.433e692fd9 → 1.43.0-dev.4451fec75a

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 (406) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +17 -9
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +45 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +2 -2
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  10. package/lib/api/impl/debug/index.d.ts.map +1 -1
  11. package/lib/api/impl/debug/index.js +0 -1
  12. package/lib/api/impl/debug/index.js.map +1 -1
  13. package/lib/api/impl/lodestar/index.js +1 -1
  14. package/lib/api/impl/lodestar/index.js.map +1 -1
  15. package/lib/api/impl/validator/index.d.ts.map +1 -1
  16. package/lib/api/impl/validator/index.js +68 -6
  17. package/lib/api/impl/validator/index.js.map +1 -1
  18. package/lib/chain/GetBlobsTracker.d.ts +1 -1
  19. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  20. package/lib/chain/GetBlobsTracker.js +1 -2
  21. package/lib/chain/GetBlobsTracker.js.map +1 -1
  22. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  23. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  24. package/lib/chain/archiveStore/interface.d.ts +4 -4
  25. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  26. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
  27. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
  28. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
  29. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +2 -2
  30. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  31. package/lib/chain/archiveStore/utils/archiveBlocks.js +110 -58
  32. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  33. package/lib/chain/blocks/blockInput/blockInput.d.ts +3 -0
  34. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  35. package/lib/chain/blocks/blockInput/blockInput.js +4 -1
  36. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  37. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  38. package/lib/chain/blocks/importBlock.js +16 -32
  39. package/lib/chain/blocks/importBlock.js.map +1 -1
  40. package/lib/chain/blocks/importExecutionPayload.d.ts +32 -14
  41. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  42. package/lib/chain/blocks/importExecutionPayload.js +101 -90
  43. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  44. package/lib/chain/blocks/index.d.ts +5 -3
  45. package/lib/chain/blocks/index.d.ts.map +1 -1
  46. package/lib/chain/blocks/index.js +58 -26
  47. package/lib/chain/blocks/index.js.map +1 -1
  48. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +15 -1
  49. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  50. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +48 -2
  51. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  52. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +17 -0
  53. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  54. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -0
  55. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  56. package/lib/chain/blocks/payloadEnvelopeProcessor.js +7 -5
  57. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  58. package/lib/chain/blocks/types.d.ts +15 -20
  59. package/lib/chain/blocks/types.d.ts.map +1 -1
  60. package/lib/chain/blocks/utils/chainSegment.d.ts +21 -2
  61. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  62. package/lib/chain/blocks/utils/chainSegment.js +92 -12
  63. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  64. package/lib/chain/blocks/verifyBlock.d.ts +5 -3
  65. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  66. package/lib/chain/blocks/verifyBlock.js +50 -7
  67. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  68. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
  69. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  70. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
  71. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  72. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
  73. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  74. package/lib/chain/blocks/verifyBlocksSanityChecks.js +25 -5
  75. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  76. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
  77. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
  78. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +80 -0
  79. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
  80. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +14 -0
  81. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -0
  82. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +30 -0
  83. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -0
  84. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
  85. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
  86. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
  87. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  88. package/lib/chain/chain.d.ts +8 -6
  89. package/lib/chain/chain.d.ts.map +1 -1
  90. package/lib/chain/chain.js +44 -14
  91. package/lib/chain/chain.js.map +1 -1
  92. package/lib/chain/emitter.d.ts +16 -15
  93. package/lib/chain/emitter.d.ts.map +1 -1
  94. package/lib/chain/emitter.js +5 -4
  95. package/lib/chain/emitter.js.map +1 -1
  96. package/lib/chain/errors/blockError.d.ts +8 -1
  97. package/lib/chain/errors/blockError.d.ts.map +1 -1
  98. package/lib/chain/errors/blockError.js +2 -0
  99. package/lib/chain/errors/blockError.js.map +1 -1
  100. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  101. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  102. package/lib/chain/errors/executionPayloadBid.js +1 -0
  103. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  104. package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
  105. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  106. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  107. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  108. package/lib/chain/errors/index.d.ts +1 -0
  109. package/lib/chain/errors/index.d.ts.map +1 -1
  110. package/lib/chain/errors/index.js +1 -0
  111. package/lib/chain/errors/index.js.map +1 -1
  112. package/lib/chain/errors/proposerPreferences.d.ts +40 -0
  113. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  114. package/lib/chain/errors/proposerPreferences.js +14 -0
  115. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  116. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  117. package/lib/chain/forkChoice/index.js +11 -19
  118. package/lib/chain/forkChoice/index.js.map +1 -1
  119. package/lib/chain/initState.d.ts.map +1 -1
  120. package/lib/chain/initState.js +6 -1
  121. package/lib/chain/initState.js.map +1 -1
  122. package/lib/chain/interface.d.ts +7 -5
  123. package/lib/chain/interface.d.ts.map +1 -1
  124. package/lib/chain/interface.js.map +1 -1
  125. package/lib/chain/lightClient/index.d.ts.map +1 -1
  126. package/lib/chain/lightClient/index.js +1 -1
  127. package/lib/chain/lightClient/index.js.map +1 -1
  128. package/lib/chain/opPools/payloadAttestationPool.d.ts +4 -3
  129. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  130. package/lib/chain/opPools/payloadAttestationPool.js +56 -14
  131. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  132. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  133. package/lib/chain/prepareNextSlot.js +45 -17
  134. package/lib/chain/prepareNextSlot.js.map +1 -1
  135. package/lib/chain/produceBlock/produceBlockBody.d.ts +13 -2
  136. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  137. package/lib/chain/produceBlock/produceBlockBody.js +68 -25
  138. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  139. package/lib/chain/regen/interface.d.ts +1 -0
  140. package/lib/chain/regen/interface.d.ts.map +1 -1
  141. package/lib/chain/regen/interface.js +1 -0
  142. package/lib/chain/regen/interface.js.map +1 -1
  143. package/lib/chain/regen/queued.d.ts.map +1 -1
  144. package/lib/chain/regen/queued.js +1 -4
  145. package/lib/chain/regen/queued.js.map +1 -1
  146. package/lib/chain/regen/regen.d.ts.map +1 -1
  147. package/lib/chain/regen/regen.js +1 -4
  148. package/lib/chain/regen/regen.js.map +1 -1
  149. package/lib/chain/seenCache/index.d.ts +1 -0
  150. package/lib/chain/seenCache/index.d.ts.map +1 -1
  151. package/lib/chain/seenCache/index.js +1 -0
  152. package/lib/chain/seenCache/index.js.map +1 -1
  153. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +24 -7
  154. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  155. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +69 -17
  156. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  157. package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
  158. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  159. package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
  160. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  161. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  162. package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -1
  163. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  164. package/lib/chain/validation/block.d.ts.map +1 -1
  165. package/lib/chain/validation/block.js +1 -0
  166. package/lib/chain/validation/block.js.map +1 -1
  167. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  168. package/lib/chain/validation/executionPayloadBid.js +24 -9
  169. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  170. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  171. package/lib/chain/validation/executionPayloadEnvelope.js +19 -9
  172. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  173. package/lib/chain/validation/payloadAttestationMessage.d.ts +1 -1
  174. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  175. package/lib/chain/validation/payloadAttestationMessage.js +9 -6
  176. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  177. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  178. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  179. package/lib/chain/validation/proposerPreferences.js +91 -0
  180. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  181. package/lib/db/repositories/executionPayloadEnvelopeArchive.js +1 -1
  182. package/lib/db/repositories/executionPayloadEnvelopeArchive.js.map +1 -1
  183. package/lib/execution/engine/http.d.ts.map +1 -1
  184. package/lib/execution/engine/http.js +21 -14
  185. package/lib/execution/engine/http.js.map +1 -1
  186. package/lib/execution/engine/interface.d.ts +1 -0
  187. package/lib/execution/engine/interface.d.ts.map +1 -1
  188. package/lib/execution/engine/mock.d.ts.map +1 -1
  189. package/lib/execution/engine/mock.js +6 -0
  190. package/lib/execution/engine/mock.js.map +1 -1
  191. package/lib/execution/engine/types.d.ts +20 -0
  192. package/lib/execution/engine/types.d.ts.map +1 -1
  193. package/lib/execution/engine/types.js +18 -0
  194. package/lib/execution/engine/types.js.map +1 -1
  195. package/lib/metrics/metrics/lodestar.d.ts +5 -0
  196. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  197. package/lib/metrics/metrics/lodestar.js +9 -0
  198. package/lib/metrics/metrics/lodestar.js.map +1 -1
  199. package/lib/network/gossip/interface.d.ts +7 -1
  200. package/lib/network/gossip/interface.d.ts.map +1 -1
  201. package/lib/network/gossip/interface.js +1 -0
  202. package/lib/network/gossip/interface.js.map +1 -1
  203. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  204. package/lib/network/gossip/scoringParameters.js +12 -1
  205. package/lib/network/gossip/scoringParameters.js.map +1 -1
  206. package/lib/network/gossip/topic.d.ts +760 -2
  207. package/lib/network/gossip/topic.d.ts.map +1 -1
  208. package/lib/network/gossip/topic.js +6 -0
  209. package/lib/network/gossip/topic.js.map +1 -1
  210. package/lib/network/interface.d.ts +2 -0
  211. package/lib/network/interface.d.ts.map +1 -1
  212. package/lib/network/network.d.ts +2 -0
  213. package/lib/network/network.d.ts.map +1 -1
  214. package/lib/network/network.js +9 -1
  215. package/lib/network/network.js.map +1 -1
  216. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  217. package/lib/network/processor/gossipHandlers.js +93 -25
  218. package/lib/network/processor/gossipHandlers.js.map +1 -1
  219. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  220. package/lib/network/processor/gossipQueues/index.js +5 -0
  221. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  222. package/lib/network/processor/index.d.ts.map +1 -1
  223. package/lib/network/processor/index.js +6 -5
  224. package/lib/network/processor/index.js.map +1 -1
  225. package/lib/network/reqresp/ReqRespBeaconNode.d.ts.map +1 -1
  226. package/lib/network/reqresp/ReqRespBeaconNode.js +1 -1
  227. package/lib/network/reqresp/ReqRespBeaconNode.js.map +1 -1
  228. package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts +9 -0
  229. package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts.map +1 -0
  230. package/lib/network/reqresp/handlers/beaconBlocksByHead.js +61 -0
  231. package/lib/network/reqresp/handlers/beaconBlocksByHead.js.map +1 -0
  232. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  233. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  234. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  235. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  236. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  237. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  238. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  239. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  240. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  241. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  242. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  243. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  244. package/lib/network/reqresp/handlers/index.d.ts.map +1 -1
  245. package/lib/network/reqresp/handlers/index.js +5 -0
  246. package/lib/network/reqresp/handlers/index.js.map +1 -1
  247. package/lib/network/reqresp/interface.d.ts +1 -1
  248. package/lib/network/reqresp/interface.js +1 -1
  249. package/lib/network/reqresp/protocols.d.ts +1 -0
  250. package/lib/network/reqresp/protocols.d.ts.map +1 -1
  251. package/lib/network/reqresp/protocols.js +5 -0
  252. package/lib/network/reqresp/protocols.js.map +1 -1
  253. package/lib/network/reqresp/rateLimit.d.ts.map +1 -1
  254. package/lib/network/reqresp/rateLimit.js +4 -0
  255. package/lib/network/reqresp/rateLimit.js.map +1 -1
  256. package/lib/network/reqresp/score.d.ts.map +1 -1
  257. package/lib/network/reqresp/score.js +1 -0
  258. package/lib/network/reqresp/score.js.map +1 -1
  259. package/lib/network/reqresp/types.d.ts +3 -0
  260. package/lib/network/reqresp/types.d.ts.map +1 -1
  261. package/lib/network/reqresp/types.js +3 -0
  262. package/lib/network/reqresp/types.js.map +1 -1
  263. package/lib/node/nodejs.d.ts.map +1 -1
  264. package/lib/node/nodejs.js +6 -4
  265. package/lib/node/nodejs.js.map +1 -1
  266. package/lib/sync/constants.d.ts +7 -1
  267. package/lib/sync/constants.d.ts.map +1 -1
  268. package/lib/sync/constants.js +7 -4
  269. package/lib/sync/constants.js.map +1 -1
  270. package/lib/sync/range/batch.d.ts +55 -8
  271. package/lib/sync/range/batch.d.ts.map +1 -1
  272. package/lib/sync/range/batch.js +291 -66
  273. package/lib/sync/range/batch.js.map +1 -1
  274. package/lib/sync/range/chain.d.ts +22 -4
  275. package/lib/sync/range/chain.d.ts.map +1 -1
  276. package/lib/sync/range/chain.js +103 -11
  277. package/lib/sync/range/chain.js.map +1 -1
  278. package/lib/sync/range/range.d.ts.map +1 -1
  279. package/lib/sync/range/range.js +71 -11
  280. package/lib/sync/range/range.js.map +1 -1
  281. package/lib/sync/range/utils/peerBalancer.d.ts +2 -1
  282. package/lib/sync/range/utils/peerBalancer.d.ts.map +1 -1
  283. package/lib/sync/range/utils/peerBalancer.js +8 -4
  284. package/lib/sync/range/utils/peerBalancer.js.map +1 -1
  285. package/lib/sync/sync.d.ts.map +1 -1
  286. package/lib/sync/sync.js +13 -0
  287. package/lib/sync/sync.js.map +1 -1
  288. package/lib/sync/types.d.ts +34 -0
  289. package/lib/sync/types.d.ts.map +1 -1
  290. package/lib/sync/types.js +34 -0
  291. package/lib/sync/types.js.map +1 -1
  292. package/lib/sync/unknownBlock.d.ts +29 -1
  293. package/lib/sync/unknownBlock.d.ts.map +1 -1
  294. package/lib/sync/unknownBlock.js +727 -61
  295. package/lib/sync/unknownBlock.js.map +1 -1
  296. package/lib/sync/utils/downloadByRange.d.ts +73 -10
  297. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  298. package/lib/sync/utils/downloadByRange.js +213 -26
  299. package/lib/sync/utils/downloadByRange.js.map +1 -1
  300. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  301. package/lib/sync/utils/downloadByRoot.js +16 -2
  302. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  303. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  304. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  305. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  306. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  307. package/lib/sync/utils/rateLimit.d.ts +2 -0
  308. package/lib/sync/utils/rateLimit.d.ts.map +1 -0
  309. package/lib/sync/utils/rateLimit.js +15 -0
  310. package/lib/sync/utils/rateLimit.js.map +1 -0
  311. package/lib/util/sszBytes.d.ts.map +1 -1
  312. package/lib/util/sszBytes.js +20 -5
  313. package/lib/util/sszBytes.js.map +1 -1
  314. package/package.json +17 -17
  315. package/src/api/impl/beacon/blocks/index.ts +22 -9
  316. package/src/api/impl/beacon/pool/index.ts +83 -1
  317. package/src/api/impl/beacon/state/utils.ts +2 -2
  318. package/src/api/impl/debug/index.ts +0 -1
  319. package/src/api/impl/lodestar/index.ts +1 -1
  320. package/src/api/impl/validator/index.ts +82 -5
  321. package/src/chain/GetBlobsTracker.ts +1 -2
  322. package/src/chain/archiveStore/archiveStore.ts +5 -5
  323. package/src/chain/archiveStore/interface.ts +4 -4
  324. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +4 -4
  325. package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
  326. package/src/chain/blocks/blockInput/blockInput.ts +4 -1
  327. package/src/chain/blocks/importBlock.ts +16 -56
  328. package/src/chain/blocks/importExecutionPayload.ts +127 -107
  329. package/src/chain/blocks/index.ts +71 -23
  330. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +64 -3
  331. package/src/chain/blocks/payloadEnvelopeInput/types.ts +18 -0
  332. package/src/chain/blocks/payloadEnvelopeProcessor.ts +7 -6
  333. package/src/chain/blocks/types.ts +15 -25
  334. package/src/chain/blocks/utils/chainSegment.ts +117 -17
  335. package/src/chain/blocks/verifyBlock.ts +70 -9
  336. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  337. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  338. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +137 -0
  339. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +41 -0
  340. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  341. package/src/chain/chain.ts +65 -26
  342. package/src/chain/emitter.ts +15 -14
  343. package/src/chain/errors/blockError.ts +4 -1
  344. package/src/chain/errors/executionPayloadBid.ts +6 -0
  345. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  346. package/src/chain/errors/index.ts +1 -0
  347. package/src/chain/errors/proposerPreferences.ts +47 -0
  348. package/src/chain/forkChoice/index.ts +8 -24
  349. package/src/chain/initState.ts +9 -1
  350. package/src/chain/interface.ts +11 -3
  351. package/src/chain/lightClient/index.ts +6 -6
  352. package/src/chain/opPools/payloadAttestationPool.ts +63 -18
  353. package/src/chain/prepareNextSlot.ts +53 -18
  354. package/src/chain/produceBlock/produceBlockBody.ts +91 -21
  355. package/src/chain/regen/interface.ts +1 -0
  356. package/src/chain/regen/queued.ts +2 -7
  357. package/src/chain/regen/regen.ts +2 -7
  358. package/src/chain/seenCache/index.ts +1 -0
  359. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +89 -21
  360. package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
  361. package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
  362. package/src/chain/validation/block.ts +1 -0
  363. package/src/chain/validation/executionPayloadBid.ts +25 -8
  364. package/src/chain/validation/executionPayloadEnvelope.ts +20 -10
  365. package/src/chain/validation/payloadAttestationMessage.ts +11 -7
  366. package/src/chain/validation/proposerPreferences.ts +110 -0
  367. package/src/db/repositories/executionPayloadEnvelopeArchive.ts +1 -1
  368. package/src/execution/engine/http.ts +21 -14
  369. package/src/execution/engine/interface.ts +1 -0
  370. package/src/execution/engine/mock.ts +8 -1
  371. package/src/execution/engine/types.ts +41 -0
  372. package/src/metrics/metrics/lodestar.ts +10 -0
  373. package/src/network/gossip/interface.ts +6 -0
  374. package/src/network/gossip/scoringParameters.ts +14 -1
  375. package/src/network/gossip/topic.ts +6 -0
  376. package/src/network/interface.ts +2 -0
  377. package/src/network/network.ts +24 -1
  378. package/src/network/processor/gossipHandlers.ts +116 -30
  379. package/src/network/processor/gossipQueues/index.ts +5 -0
  380. package/src/network/processor/index.ts +6 -5
  381. package/src/network/reqresp/ReqRespBeaconNode.ts +1 -0
  382. package/src/network/reqresp/handlers/beaconBlocksByHead.ts +91 -0
  383. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  384. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  385. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  386. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  387. package/src/network/reqresp/handlers/index.ts +5 -0
  388. package/src/network/reqresp/interface.ts +1 -1
  389. package/src/network/reqresp/protocols.ts +6 -0
  390. package/src/network/reqresp/rateLimit.ts +4 -0
  391. package/src/network/reqresp/score.ts +1 -0
  392. package/src/network/reqresp/types.ts +5 -0
  393. package/src/node/nodejs.ts +6 -4
  394. package/src/sync/constants.ts +8 -4
  395. package/src/sync/range/batch.ts +388 -75
  396. package/src/sync/range/chain.ts +131 -14
  397. package/src/sync/range/range.ts +86 -11
  398. package/src/sync/range/utils/peerBalancer.ts +9 -3
  399. package/src/sync/sync.ts +13 -1
  400. package/src/sync/types.ts +72 -0
  401. package/src/sync/unknownBlock.ts +915 -65
  402. package/src/sync/utils/downloadByRange.ts +386 -39
  403. package/src/sync/utils/downloadByRoot.ts +24 -2
  404. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  405. package/src/sync/utils/rateLimit.ts +16 -0
  406. package/src/util/sszBytes.ts +25 -5
@@ -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 {DataAvailabilityStatus, isStatePostGloas} from "@lodestar/state-transition";
4
+ import {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,8 @@ 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
+ MISS_BLOCK_STATE = "PAYLOAD_ERROR_MISS_BLOCK_STATE",
25
+ ENVELOPE_VERIFICATION_ERROR = "PAYLOAD_ERROR_ENVELOPE_VERIFICATION_ERROR",
20
26
  INVALID_SIGNATURE = "PAYLOAD_ERROR_INVALID_SIGNATURE",
21
27
  }
22
28
 
@@ -36,7 +42,11 @@ export type PayloadErrorType =
36
42
  blockRootHex: string;
37
43
  }
38
44
  | {
39
- code: PayloadErrorCode.STATE_TRANSITION_ERROR;
45
+ code: PayloadErrorCode.MISS_BLOCK_STATE;
46
+ blockRootHex: string;
47
+ }
48
+ | {
49
+ code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR;
40
50
  message: string;
41
51
  }
42
52
  | {
@@ -56,7 +66,6 @@ function toForkChoiceExecutionStatus(status: ExecutionPayloadStatus): PayloadExe
56
66
  switch (status) {
57
67
  case ExecutionPayloadStatus.VALID:
58
68
  return ExecutionStatus.Valid;
59
- // TODO GLOAS: Handle optimistic import for payload
60
69
  case ExecutionPayloadStatus.SYNCING:
61
70
  case ExecutionPayloadStatus.ACCEPTED:
62
71
  return ExecutionStatus.Syncing;
@@ -68,37 +77,43 @@ function toForkChoiceExecutionStatus(status: ExecutionPayloadStatus): PayloadExe
68
77
  /**
69
78
  * Import an execution payload envelope after all data is available.
70
79
  *
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
80
+ * The envelope is only verified here, no state mutation. State effects from the payload
81
+ * are applied on the next block via processParentExecutionPayload.
82
+ *
83
+ * The DA wait must have run upstream (range sync awaits DA in `verifyBlocksInEpoch` for the
84
+ * whole segment; gossip / API path uses the `processExecutionPayload` wrapper below).
82
85
  *
86
+ * Steps:
87
+ * 1. Emit `execution_payload_available` event for payload attestation
88
+ * 2. Get the ProtoBlock from fork choice
89
+ * 3. Regenerate state for envelope verification
90
+ * 4. Verify envelope (fields against state, signature, and EL in parallel where possible)
91
+ * 5. Persist verified payload envelope to hot DB (waits for write-queue space for backpressure)
92
+ * 6. Update fork choice (transitions the block's PENDING variant to FULL)
93
+ * 7. Queue notifyForkchoiceUpdate to engine api
94
+ * 8. Record metrics for payload envelope and column sources
95
+ * 9. Emit `execution_payload` event
83
96
  */
84
97
  export async function importExecutionPayload(
85
98
  this: BeaconChain,
86
99
  payloadInput: PayloadEnvelopeInput,
100
+ dataAvailabilityStatus: DataAvailabilityStatus,
87
101
  opts: ImportPayloadOpts = {}
88
102
  ): Promise<void> {
89
103
  const signedEnvelope = payloadInput.getPayloadEnvelope();
90
104
  const envelope = signedEnvelope.message;
105
+ const slot = envelope.payload.slotNumber;
91
106
  const blockRootHex = payloadInput.blockRootHex;
92
107
  const blockHashHex = payloadInput.getBlockHashHex();
93
- const fork = this.config.getForkName(envelope.slot);
108
+ const fork = this.config.getForkName(slot);
94
109
 
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) {
110
+ // 1. Emit `execution_payload_available` event at the start of import. At this point the
111
+ // payload input is already complete, so the payload and required data are available for
112
+ // payload attestation. This event only signals availability (not validity), so we can emit
113
+ // it before getting a response from the EL on whether the payload is valid or not.
114
+ if (this.clock.currentSlot - slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
100
115
  this.emitter.emit(routes.events.EventType.executionPayloadAvailable, {
101
- slot: envelope.slot,
116
+ slot,
102
117
  blockRoot: blockRootHex,
103
118
  });
104
119
  }
@@ -112,78 +127,72 @@ export async function importExecutionPayload(
112
127
  });
113
128
  }
114
129
 
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();
130
+ // 3. Regenerate state for envelope verification
131
+ const blockState = await this.regen
132
+ .getBlockSlotState(protoBlock, protoBlock.slot, {dontTransferCache: true}, RegenCaller.processBlock)
133
+ .catch(() =>
134
+ // only happen at the 1st batch of skipped slot checkpoint sync
135
+ this.regen.getClosestHeadState(protoBlock)
136
+ );
118
137
 
119
- // 4. Get pre-state for processExecutionPayloadEnvelope
120
- // We need the block state (post-block, pre-payload) to process the envelope
121
- const blockState = await this.regen.getBlockSlotState(
122
- protoBlock,
123
- protoBlock.slot,
124
- {dontTransferCache: true},
125
- RegenCaller.processBlock
126
- );
138
+ if (blockState == null) {
139
+ throw new PayloadError({
140
+ code: PayloadErrorCode.MISS_BLOCK_STATE,
141
+ blockRootHex: protoBlock.blockRoot,
142
+ });
143
+ }
127
144
  if (!isStatePostGloas(blockState)) {
128
145
  throw new PayloadError({
129
- code: PayloadErrorCode.STATE_TRANSITION_ERROR,
130
- message: `Expected gloas+ block state for payload import, got fork=${blockState.forkName}`,
146
+ code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
147
+ message: `Expected gloas+ state for payload import, got fork=${blockState.forkName}`,
148
+ });
149
+ }
150
+
151
+ // 4. Verify envelope fields against state first to fail fast before the EL + BLS work.
152
+ // When validSignature is true, gossip/API has already verified both the signature and the
153
+ // executionRequestsRoot, so we skip those checks here.
154
+ try {
155
+ verifyExecutionPayloadEnvelope(this.config, blockState, envelope, {
156
+ verifyExecutionRequestsRoot: !opts.validSignature,
131
157
  });
158
+ } catch (e) {
159
+ throw new PayloadError(
160
+ {
161
+ code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
162
+ message: (e as Error).message,
163
+ },
164
+ `Envelope verification error: ${(e as Error).message}`
165
+ );
132
166
  }
133
167
 
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([
168
+ // 4a. Run EL and signature verification in parallel
169
+ const [execResult, signatureValid] = await Promise.all([
138
170
  this.executionEngine.notifyNewPayload(
139
171
  fork,
140
172
  envelope.payload,
141
173
  payloadInput.getVersionedHashes(),
142
- fromHex(protoBlock.parentRoot),
174
+ envelope.parentBeaconBlockRoot,
143
175
  envelope.executionRequests
144
176
  ),
145
177
 
146
178
  opts.validSignature === true
147
179
  ? 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
- })(),
180
+ : verifyExecutionPayloadEnvelopeSignature(
181
+ this.config,
182
+ blockState,
183
+ this.pubkeyCache,
184
+ signedEnvelope,
185
+ payloadInput.proposerIndex,
186
+ this.bls
187
+ ),
179
188
  ]);
180
189
 
181
- // 5a. Check signature verification result
190
+ // 4b. Check signature verification result
182
191
  if (!signatureValid) {
183
192
  throw new PayloadError({code: PayloadErrorCode.INVALID_SIGNATURE});
184
193
  }
185
194
 
186
- // 5b. Handle EL response
195
+ // 4c. Handle EL response
187
196
  switch (execResult.status) {
188
197
  case ExecutionPayloadStatus.VALID:
189
198
  break;
@@ -209,69 +218,80 @@ export async function importExecutionPayload(
209
218
  });
210
219
  }
211
220
 
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)
221
+ // 5. Persist payload envelope to hot DB. Wait for write-queue space here to apply backpressure
222
+ // on the import pipeline during sync, then perform the write asynchronously to avoid blocking.
223
+ await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
223
224
  this.unfinalizedPayloadEnvelopeWrites.push(payloadInput).catch((e) => {
224
225
  if (!isQueueErrorAborted(e)) {
225
226
  this.logger.error(
226
227
  "Error pushing payload envelope to unfinalized write queue",
227
- {slot: envelope.slot, blockRoot: blockRootHex},
228
+ {slot, blockRoot: blockRootHex},
228
229
  e as Error
229
230
  );
230
231
  }
231
232
  });
232
233
 
233
- // 7. Update fork choice
234
+ // 6. Update fork choice, transitions the block's PENDING variant to FULL
235
+ const execStatus = toForkChoiceExecutionStatus(execResult.status);
234
236
  this.forkChoice.onExecutionPayload(
235
237
  blockRootHex,
236
238
  blockHashHex,
237
239
  envelope.payload.blockNumber,
238
- toRootHex(postPayloadStateRoot),
239
- toForkChoiceExecutionStatus(execResult.status)
240
+ execStatus,
241
+ dataAvailabilityStatus
240
242
  );
241
243
 
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);
244
+ // 7. Queue notifyForkchoiceUpdate to engine api
245
+ const head = this.forkChoice.getHead();
246
+ if (!this.opts.disableImportExecutionFcU && blockRootHex === head.blockRoot) {
247
+ const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
248
+ const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
249
+ this.executionEngine.notifyForkchoiceUpdate(fork, blockHashHex, safeBlockHash, finalizedBlockHash).catch((e) => {
250
+ if (!isErrorAborted(e) && !isQueueErrorAborted(e)) {
251
+ this.logger.error("Error pushing notifyForkchoiceUpdate()", {blockHashHex, finalizedBlockHash}, e);
252
+ }
253
+ });
247
254
  }
248
255
 
249
- // 9. Record metrics for payload envelope and column sources
256
+ // 8. Record metrics for payload envelope and column sources
250
257
  this.metrics?.importPayload.bySource.inc({source: payloadInput.getPayloadEnvelopeSource().source});
251
258
  for (const {source} of payloadInput.getSampledColumnsWithSource()) {
252
259
  this.metrics?.importPayload.columnsBySource.inc({source});
253
260
  }
254
261
 
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) {
262
+ // 9. Emit event after payload is fully verified and imported to fork choice, only for recent enough payloads
263
+ if (this.clock.currentSlot - slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
259
264
  this.emitter.emit(routes.events.EventType.executionPayload, {
260
- slot: envelope.slot,
265
+ slot,
261
266
  builderIndex: envelope.builderIndex,
262
267
  blockHash: blockHashHex,
263
268
  blockRoot: blockRootHex,
264
- stateRoot: stateRootHex,
265
- // TODO GLOAS: revisit once we support optimistic import
266
- executionOptimistic: false,
269
+ executionOptimistic: execStatus === ExecutionStatus.Syncing,
267
270
  });
268
271
  }
269
272
 
270
273
  this.logger.verbose("Execution payload imported", {
271
- slot: envelope.slot,
274
+ slot,
272
275
  builderIndex: envelope.builderIndex,
273
276
  blockRoot: blockRootHex,
274
277
  blockHash: blockHashHex,
275
- stateRoot: stateRootHex,
276
278
  });
277
279
  }
280
+
281
+ /**
282
+ * Process an execution payload envelope end-to-end: wait for DA, then import.
283
+ *
284
+ * Used by the PayloadEnvelopeProcessor queue (gossip / API / unknown-payload sync) — i.e.
285
+ * callers that have NOT already awaited DA themselves. Range sync's inline dispatch in
286
+ * processBlocks skips this wrapper and calls `importExecutionPayload` directly, since
287
+ * `verifyBlocksInEpoch` already awaited DA for the segment.
288
+ */
289
+ export async function processExecutionPayload(
290
+ this: BeaconChain,
291
+ payloadInput: PayloadEnvelopeInput,
292
+ signal: AbortSignal,
293
+ opts: ImportPayloadOpts = {}
294
+ ): Promise<void> {
295
+ const {dataAvailabilityStatuses} = await verifyPayloadsDataAvailability([payloadInput], signal);
296
+ await importExecutionPayload.call(this, payloadInput, dataAvailabilityStatuses[0], opts);
297
+ }
@@ -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,18 +57,15 @@ 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
- const {relevantBlocks, parentSlots, parentBlock} = verifyBlocksSanityChecks(this, blocks, opts);
68
+ const {relevantBlocks, parentSlots, parentBlock} = verifyBlocksSanityChecks(this, blocks, payloadEnvelopes, opts);
66
69
 
67
70
  // No relevant blocks, skip verifyBlocksInEpoch()
68
71
  if (relevantBlocks.length === 0 || parentBlock === null) {
@@ -70,10 +73,31 @@ 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
- const {postStates, dataAvailabilityStatuses, proposerBalanceDeltas, segmentExecStatus, indexedAttestationsByBlock} =
76
- await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, opts);
93
+ const {
94
+ postStates,
95
+ blockDAStatuses,
96
+ payloadDAStatuses,
97
+ proposerBalanceDeltas,
98
+ segmentExecStatus,
99
+ indexedAttestationsByBlock,
100
+ } = await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, payloadEnvelopes, opts);
77
101
 
78
102
  // If segmentExecStatus has lvhForkchoice then, the entire segment should be invalid
79
103
  // and we need to further propagate
@@ -85,25 +109,49 @@ export async function processBlocks(
85
109
  }
86
110
 
87
111
  const {executionStatuses} = segmentExecStatus;
88
- const fullyVerifiedBlocks = relevantBlocks.map(
89
- (block, i): FullyVerifiedBlock => ({
112
+ const verifiedBlocksBySlot = new Map<Slot, FullyVerifiedBlock>();
113
+ for (let i = 0; i < relevantBlocks.length; i++) {
114
+ const block = relevantBlocks[i];
115
+ verifiedBlocksBySlot.set(block.getBlock().message.slot, {
90
116
  blockInput: block,
91
117
  postState: postStates[i],
92
- postPayloadState: null,
93
118
  parentBlockSlot: parentSlots[i],
94
119
  executionStatus: executionStatuses[i],
95
120
  // start supporting optimistic syncing/processing
96
- dataAvailabilityStatus: dataAvailabilityStatuses[i],
121
+ dataAvailabilityStatus: blockDAStatuses[i],
97
122
  proposerBalanceDelta: proposerBalanceDeltas[i],
98
123
  indexedAttestations: indexedAttestationsByBlock[i],
99
124
  // TODO: Make this param mandatory and capture in gossip
100
125
  seenTimestampSec: opts.seenTimestampSec ?? Math.floor(Date.now() / 1000),
101
- })
102
- );
126
+ });
127
+ }
128
+
129
+ const slotSet = new Set<Slot>(blocks.map((b) => b.getBlock().message.slot));
130
+ if (payloadEnvelopes) {
131
+ for (const slot of payloadEnvelopes.keys()) slotSet.add(slot);
132
+ }
133
+ const slots = Array.from(slotSet).sort((a, b) => a - b);
134
+ for (const slot of slots) {
135
+ const fullyVerifiedBlock = verifiedBlocksBySlot.get(slot);
136
+ if (fullyVerifiedBlock !== undefined) {
137
+ // TODO: Consider batching importBlock too if it takes significant time
138
+ await importBlock.call(this, fullyVerifiedBlock, opts);
139
+ }
140
+
141
+ const payloadInput = payloadEnvelopes?.get(slot);
142
+ if (payloadInput?.hasPayloadEnvelope()) {
143
+ if (!payloadInput.isComplete()) {
144
+ // we validated DA before reaching this
145
+ throw new Error(`Payload envelope for slot ${slot} not complete after DA verification`);
146
+ }
147
+ // we already awaited DA in verifyBlocksInEpoch for this segment
148
+ const payloadDA = payloadDAStatuses.get(slot);
149
+ if (payloadDA === undefined) {
150
+ throw new Error(`Missing payload DA status for slot ${slot}`);
151
+ }
152
+ await importExecutionPayload.call(this, payloadInput, payloadDA, {validSignature: false});
153
+ }
103
154
 
104
- for (const fullyVerifiedBlock of fullyVerifiedBlocks) {
105
- // TODO: Consider batching importBlock too if it takes significant time
106
- await importBlock.call(this, fullyVerifiedBlock, opts);
107
155
  await nextEventLoop();
108
156
  }
109
157
  } catch (e) {
@@ -4,7 +4,13 @@ import {toRootHex, withTimeout} from "@lodestar/utils";
4
4
  import {VersionedHashes} from "../../../execution/index.js";
5
5
  import {kzgCommitmentToVersionedHash} from "../../../util/blobs.js";
6
6
  import {MissingColumnMeta} from "../blockInput/types.js";
7
- import {AddPayloadEnvelopeProps, ColumnWithSource, CreateFromBlockProps, SourceMeta} from "./types.js";
7
+ import {
8
+ AddPayloadEnvelopeProps,
9
+ ColumnWithSource,
10
+ CreateFromBidProps,
11
+ CreateFromBlockProps,
12
+ SourceMeta,
13
+ } from "./types.js";
8
14
 
9
15
  export type PayloadEnvelopeInputState =
10
16
  | {
@@ -64,6 +70,7 @@ export class PayloadEnvelopeInput {
64
70
  readonly proposerIndex: ValidatorIndex;
65
71
  readonly bid: gloas.ExecutionPayloadBid;
66
72
  readonly versionedHashes: VersionedHashes;
73
+ readonly daOutOfRange: boolean;
67
74
 
68
75
  private columnsCache = new Map<ColumnIndex, ColumnWithSource>();
69
76
 
@@ -73,6 +80,7 @@ export class PayloadEnvelopeInput {
73
80
  private timeCreatedSec: number;
74
81
 
75
82
  private readonly payloadEnvelopeDataPromise: PromiseParts<gloas.SignedExecutionPayloadEnvelope>;
83
+ private readonly allDataPromise: PromiseParts<gloas.DataColumnSidecar[]>;
76
84
  private readonly columnsDataPromise: PromiseParts<gloas.DataColumnSidecar[]>;
77
85
 
78
86
  state: PayloadEnvelopeInputState;
@@ -86,6 +94,7 @@ export class PayloadEnvelopeInput {
86
94
  sampledColumns: ColumnIndex[];
87
95
  custodyColumns: ColumnIndex[];
88
96
  timeCreatedSec: number;
97
+ daOutOfRange: boolean;
89
98
  }) {
90
99
  this.blockRootHex = props.blockRootHex;
91
100
  this.slot = props.slot;
@@ -96,15 +105,18 @@ export class PayloadEnvelopeInput {
96
105
  this.sampledColumns = props.sampledColumns;
97
106
  this.custodyColumns = props.custodyColumns;
98
107
  this.timeCreatedSec = props.timeCreatedSec;
108
+ this.daOutOfRange = props.daOutOfRange;
99
109
  this.payloadEnvelopeDataPromise = createPromise();
110
+ this.allDataPromise = createPromise();
100
111
  this.columnsDataPromise = createPromise();
101
112
 
102
113
  const noBlobs = props.bid.blobKzgCommitments.length === 0;
103
114
  const noSampledColumns = props.sampledColumns.length === 0;
104
- const hasAllData = noBlobs || noSampledColumns;
115
+ const hasAllData = props.daOutOfRange || noBlobs || noSampledColumns;
105
116
 
106
117
  if (hasAllData) {
107
118
  this.state = {hasPayload: false, hasAllData: true, hasComputedAllData: true};
119
+ this.allDataPromise.resolve(this.getSampledColumns());
108
120
  this.columnsDataPromise.resolve(this.getSampledColumns());
109
121
  } else {
110
122
  this.state = {hasPayload: false, hasAllData: false, hasComputedAllData: false};
@@ -122,6 +134,27 @@ export class PayloadEnvelopeInput {
122
134
  sampledColumns: props.sampledColumns,
123
135
  custodyColumns: props.custodyColumns,
124
136
  timeCreatedSec: props.timeCreatedSec,
137
+ daOutOfRange: props.daOutOfRange,
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Create a `PayloadEnvelopeInput` from a state's `latestExecutionPayloadBid` (the bid
143
+ * recorded in beacon state for the latest imported block). Used when seeding the cache
144
+ * for a checkpoint anchor block — we have the bid via state but not the full
145
+ * SignedBeaconBlock body.
146
+ */
147
+ static createFromBid(props: CreateFromBidProps): PayloadEnvelopeInput {
148
+ return new PayloadEnvelopeInput({
149
+ blockRootHex: props.blockRootHex,
150
+ slot: props.slot,
151
+ forkName: props.forkName,
152
+ proposerIndex: props.proposerIndex,
153
+ bid: props.bid,
154
+ sampledColumns: props.sampledColumns,
155
+ custodyColumns: props.custodyColumns,
156
+ timeCreatedSec: props.timeCreatedSec,
157
+ daOutOfRange: props.daOutOfRange,
125
158
  });
126
159
  }
127
160
 
@@ -149,6 +182,7 @@ export class PayloadEnvelopeInput {
149
182
  throw new Error("Payload envelope beacon_block_root mismatch");
150
183
  }
151
184
 
185
+ // TODO GLOAS: track source by metrics, maybe inside the seen cache
152
186
  const source: SourceMeta = {
153
187
  source: props.source,
154
188
  seenTimestampSec: props.seenTimestampSec,
@@ -203,6 +237,12 @@ export class PayloadEnvelopeInput {
203
237
  return true;
204
238
  }
205
239
 
240
+ // Resolve allDataPromise on the first transition to hasAllData (either sampled-complete or
241
+ // reconstruction-threshold branch). Guarded so it fires exactly once.
242
+ if (!this.state.hasAllData && hasAllData) {
243
+ this.allDataPromise.resolve(sampledColumns);
244
+ }
245
+
206
246
  if (hasComputedAllData) {
207
247
  this.columnsDataPromise.resolve(sampledColumns);
208
248
  }
@@ -297,8 +337,11 @@ export class PayloadEnvelopeInput {
297
337
  return this.state.hasAllData;
298
338
  }
299
339
 
340
+ /**
341
+ * Strictly checks missing sampled columns. Does NOT short-circuit on `state.hasAllData`.
342
+ */
300
343
  getMissingSampledColumnMeta(): MissingColumnMeta {
301
- if (this.state.hasAllData) {
344
+ if (this.state.hasComputedAllData) {
302
345
  return {missing: [], versionedHashes: this.versionedHashes};
303
346
  }
304
347
 
@@ -315,6 +358,24 @@ export class PayloadEnvelopeInput {
315
358
  return this.state.hasComputedAllData;
316
359
  }
317
360
 
361
+ waitForAllData(timeout: number, signal?: AbortSignal): Promise<gloas.DataColumnSidecar[]> {
362
+ if (this.state.hasAllData) {
363
+ return Promise.resolve(this.getSampledColumns());
364
+ }
365
+ return withTimeout(() => this.allDataPromise.promise, timeout, signal);
366
+ }
367
+
368
+ async waitForEnvelopeAndAllData(timeout: number, signal?: AbortSignal): Promise<this> {
369
+ if (!this.state.hasPayload || !this.state.hasAllData) {
370
+ await withTimeout(
371
+ () => Promise.all([this.payloadEnvelopeDataPromise.promise, this.allDataPromise.promise]),
372
+ timeout,
373
+ signal
374
+ );
375
+ }
376
+ return this;
377
+ }
378
+
318
379
  waitForComputedAllData(timeout: number, signal?: AbortSignal): Promise<gloas.DataColumnSidecar[]> {
319
380
  if (this.state.hasComputedAllData) {
320
381
  return Promise.resolve(this.getSampledColumns());