@lodestar/beacon-node 1.43.0-dev.bc569affb9 → 1.43.0-dev.c5efeb6c90

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 (352) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +16 -5
  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 +86 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/debug/index.d.ts.map +1 -1
  8. package/lib/api/impl/debug/index.js +0 -1
  9. package/lib/api/impl/debug/index.js.map +1 -1
  10. package/lib/api/impl/lodestar/index.js +1 -1
  11. package/lib/api/impl/lodestar/index.js.map +1 -1
  12. package/lib/api/impl/validator/index.d.ts.map +1 -1
  13. package/lib/api/impl/validator/index.js +85 -12
  14. package/lib/api/impl/validator/index.js.map +1 -1
  15. package/lib/chain/blocks/blockInput/blockInput.d.ts +3 -0
  16. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  17. package/lib/chain/blocks/blockInput/blockInput.js +4 -1
  18. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  19. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  20. package/lib/chain/blocks/importBlock.js +16 -28
  21. package/lib/chain/blocks/importBlock.js.map +1 -1
  22. package/lib/chain/blocks/importExecutionPayload.d.ts +23 -6
  23. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  24. package/lib/chain/blocks/importExecutionPayload.js +57 -24
  25. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  26. package/lib/chain/blocks/index.d.ts +5 -3
  27. package/lib/chain/blocks/index.d.ts.map +1 -1
  28. package/lib/chain/blocks/index.js +58 -25
  29. package/lib/chain/blocks/index.js.map +1 -1
  30. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +12 -1
  31. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  32. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +28 -2
  33. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  34. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +17 -0
  35. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  36. package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
  37. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  38. package/lib/chain/blocks/types.d.ts +4 -3
  39. package/lib/chain/blocks/types.d.ts.map +1 -1
  40. package/lib/chain/blocks/utils/chainSegment.d.ts +21 -2
  41. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  42. package/lib/chain/blocks/utils/chainSegment.js +92 -12
  43. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  44. package/lib/chain/blocks/verifyBlock.d.ts +5 -3
  45. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  46. package/lib/chain/blocks/verifyBlock.js +50 -7
  47. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  48. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
  49. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  50. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
  51. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  52. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
  53. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  54. package/lib/chain/blocks/verifyBlocksSanityChecks.js +25 -5
  55. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  56. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  57. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  58. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +12 -8
  59. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  60. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  61. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
  62. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  63. package/lib/chain/chain.d.ts +5 -3
  64. package/lib/chain/chain.d.ts.map +1 -1
  65. package/lib/chain/chain.js +38 -13
  66. package/lib/chain/chain.js.map +1 -1
  67. package/lib/chain/emitter.d.ts +0 -11
  68. package/lib/chain/emitter.d.ts.map +1 -1
  69. package/lib/chain/emitter.js +0 -4
  70. package/lib/chain/emitter.js.map +1 -1
  71. package/lib/chain/errors/blockError.d.ts +8 -1
  72. package/lib/chain/errors/blockError.d.ts.map +1 -1
  73. package/lib/chain/errors/blockError.js +2 -0
  74. package/lib/chain/errors/blockError.js.map +1 -1
  75. package/lib/chain/errors/executionPayloadBid.d.ts +19 -1
  76. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  77. package/lib/chain/errors/executionPayloadBid.js +3 -0
  78. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  79. package/lib/chain/errors/index.d.ts +1 -0
  80. package/lib/chain/errors/index.d.ts.map +1 -1
  81. package/lib/chain/errors/index.js +1 -0
  82. package/lib/chain/errors/index.js.map +1 -1
  83. package/lib/chain/errors/proposerPreferences.d.ts +40 -0
  84. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  85. package/lib/chain/errors/proposerPreferences.js +14 -0
  86. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  87. package/lib/chain/initState.d.ts.map +1 -1
  88. package/lib/chain/initState.js +6 -1
  89. package/lib/chain/initState.js.map +1 -1
  90. package/lib/chain/interface.d.ts +5 -3
  91. package/lib/chain/interface.d.ts.map +1 -1
  92. package/lib/chain/interface.js.map +1 -1
  93. package/lib/chain/lightClient/index.d.ts.map +1 -1
  94. package/lib/chain/lightClient/index.js +1 -1
  95. package/lib/chain/lightClient/index.js.map +1 -1
  96. package/lib/chain/opPools/index.d.ts +1 -0
  97. package/lib/chain/opPools/index.d.ts.map +1 -1
  98. package/lib/chain/opPools/index.js +1 -0
  99. package/lib/chain/opPools/index.js.map +1 -1
  100. package/lib/chain/opPools/payloadAttestationPool.d.ts +4 -3
  101. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  102. package/lib/chain/opPools/payloadAttestationPool.js +56 -14
  103. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  104. package/lib/chain/opPools/proposerPreferencesPool.d.ts +29 -0
  105. package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -0
  106. package/lib/chain/opPools/proposerPreferencesPool.js +56 -0
  107. package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -0
  108. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  109. package/lib/chain/prepareNextSlot.js +16 -18
  110. package/lib/chain/prepareNextSlot.js.map +1 -1
  111. package/lib/chain/produceBlock/produceBlockBody.d.ts +12 -3
  112. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  113. package/lib/chain/produceBlock/produceBlockBody.js +35 -17
  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/regen/queued.d.ts.map +1 -1
  120. package/lib/chain/regen/queued.js +1 -4
  121. package/lib/chain/regen/queued.js.map +1 -1
  122. package/lib/chain/regen/regen.d.ts.map +1 -1
  123. package/lib/chain/regen/regen.js +1 -4
  124. package/lib/chain/regen/regen.js.map +1 -1
  125. package/lib/chain/seenCache/index.d.ts +1 -0
  126. package/lib/chain/seenCache/index.d.ts.map +1 -1
  127. package/lib/chain/seenCache/index.js +1 -0
  128. package/lib/chain/seenCache/index.js.map +1 -1
  129. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +21 -11
  130. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  131. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +70 -20
  132. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  133. package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
  134. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  135. package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
  136. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  137. package/lib/chain/validation/block.d.ts.map +1 -1
  138. package/lib/chain/validation/block.js +1 -0
  139. package/lib/chain/validation/block.js.map +1 -1
  140. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  141. package/lib/chain/validation/executionPayloadBid.js +68 -17
  142. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  143. package/lib/chain/validation/payloadAttestationMessage.d.ts +1 -1
  144. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  145. package/lib/chain/validation/payloadAttestationMessage.js +5 -3
  146. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  147. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  148. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  149. package/lib/chain/validation/proposerPreferences.js +91 -0
  150. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  151. package/lib/metrics/metrics/lodestar.d.ts +5 -0
  152. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  153. package/lib/metrics/metrics/lodestar.js +9 -0
  154. package/lib/metrics/metrics/lodestar.js.map +1 -1
  155. package/lib/network/gossip/interface.d.ts +7 -1
  156. package/lib/network/gossip/interface.d.ts.map +1 -1
  157. package/lib/network/gossip/interface.js +1 -0
  158. package/lib/network/gossip/interface.js.map +1 -1
  159. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  160. package/lib/network/gossip/scoringParameters.js +12 -1
  161. package/lib/network/gossip/scoringParameters.js.map +1 -1
  162. package/lib/network/gossip/topic.d.ts +29 -766
  163. package/lib/network/gossip/topic.d.ts.map +1 -1
  164. package/lib/network/gossip/topic.js +6 -0
  165. package/lib/network/gossip/topic.js.map +1 -1
  166. package/lib/network/interface.d.ts +3 -0
  167. package/lib/network/interface.d.ts.map +1 -1
  168. package/lib/network/network.d.ts +3 -0
  169. package/lib/network/network.d.ts.map +1 -1
  170. package/lib/network/network.js +13 -0
  171. package/lib/network/network.js.map +1 -1
  172. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  173. package/lib/network/processor/gossipHandlers.js +77 -20
  174. package/lib/network/processor/gossipHandlers.js.map +1 -1
  175. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  176. package/lib/network/processor/gossipQueues/index.js +5 -0
  177. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  178. package/lib/network/processor/index.d.ts.map +1 -1
  179. package/lib/network/processor/index.js +6 -5
  180. package/lib/network/processor/index.js.map +1 -1
  181. package/lib/network/reqresp/ReqRespBeaconNode.d.ts.map +1 -1
  182. package/lib/network/reqresp/ReqRespBeaconNode.js +1 -1
  183. package/lib/network/reqresp/ReqRespBeaconNode.js.map +1 -1
  184. package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts +9 -0
  185. package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts.map +1 -0
  186. package/lib/network/reqresp/handlers/beaconBlocksByHead.js +61 -0
  187. package/lib/network/reqresp/handlers/beaconBlocksByHead.js.map +1 -0
  188. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  189. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  190. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  191. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  192. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  193. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  194. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  195. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  196. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  197. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  198. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  199. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  200. package/lib/network/reqresp/handlers/index.d.ts.map +1 -1
  201. package/lib/network/reqresp/handlers/index.js +5 -0
  202. package/lib/network/reqresp/handlers/index.js.map +1 -1
  203. package/lib/network/reqresp/interface.d.ts +1 -1
  204. package/lib/network/reqresp/interface.js +1 -1
  205. package/lib/network/reqresp/protocols.d.ts +1 -0
  206. package/lib/network/reqresp/protocols.d.ts.map +1 -1
  207. package/lib/network/reqresp/protocols.js +5 -0
  208. package/lib/network/reqresp/protocols.js.map +1 -1
  209. package/lib/network/reqresp/rateLimit.d.ts.map +1 -1
  210. package/lib/network/reqresp/rateLimit.js +4 -0
  211. package/lib/network/reqresp/rateLimit.js.map +1 -1
  212. package/lib/network/reqresp/score.d.ts.map +1 -1
  213. package/lib/network/reqresp/score.js +1 -0
  214. package/lib/network/reqresp/score.js.map +1 -1
  215. package/lib/network/reqresp/types.d.ts +3 -0
  216. package/lib/network/reqresp/types.d.ts.map +1 -1
  217. package/lib/network/reqresp/types.js +3 -0
  218. package/lib/network/reqresp/types.js.map +1 -1
  219. package/lib/node/nodejs.js +2 -2
  220. package/lib/node/nodejs.js.map +1 -1
  221. package/lib/sync/constants.d.ts +7 -1
  222. package/lib/sync/constants.d.ts.map +1 -1
  223. package/lib/sync/constants.js +7 -4
  224. package/lib/sync/constants.js.map +1 -1
  225. package/lib/sync/range/batch.d.ts +55 -8
  226. package/lib/sync/range/batch.d.ts.map +1 -1
  227. package/lib/sync/range/batch.js +291 -66
  228. package/lib/sync/range/batch.js.map +1 -1
  229. package/lib/sync/range/chain.d.ts +22 -4
  230. package/lib/sync/range/chain.d.ts.map +1 -1
  231. package/lib/sync/range/chain.js +103 -11
  232. package/lib/sync/range/chain.js.map +1 -1
  233. package/lib/sync/range/range.d.ts.map +1 -1
  234. package/lib/sync/range/range.js +71 -11
  235. package/lib/sync/range/range.js.map +1 -1
  236. package/lib/sync/range/utils/peerBalancer.d.ts +2 -1
  237. package/lib/sync/range/utils/peerBalancer.d.ts.map +1 -1
  238. package/lib/sync/range/utils/peerBalancer.js +8 -4
  239. package/lib/sync/range/utils/peerBalancer.js.map +1 -1
  240. package/lib/sync/sync.d.ts.map +1 -1
  241. package/lib/sync/sync.js +13 -0
  242. package/lib/sync/sync.js.map +1 -1
  243. package/lib/sync/types.d.ts +34 -0
  244. package/lib/sync/types.d.ts.map +1 -1
  245. package/lib/sync/types.js +34 -0
  246. package/lib/sync/types.js.map +1 -1
  247. package/lib/sync/unknownBlock.d.ts +29 -1
  248. package/lib/sync/unknownBlock.d.ts.map +1 -1
  249. package/lib/sync/unknownBlock.js +727 -61
  250. package/lib/sync/unknownBlock.js.map +1 -1
  251. package/lib/sync/utils/downloadByRange.d.ts +73 -10
  252. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  253. package/lib/sync/utils/downloadByRange.js +213 -26
  254. package/lib/sync/utils/downloadByRange.js.map +1 -1
  255. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  256. package/lib/sync/utils/downloadByRoot.js +16 -2
  257. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  258. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  259. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  260. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  261. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  262. package/lib/sync/utils/rateLimit.d.ts +2 -0
  263. package/lib/sync/utils/rateLimit.d.ts.map +1 -0
  264. package/lib/sync/utils/rateLimit.js +15 -0
  265. package/lib/sync/utils/rateLimit.js.map +1 -0
  266. package/lib/util/dependentRoot.d.ts +6 -2
  267. package/lib/util/dependentRoot.d.ts.map +1 -1
  268. package/lib/util/dependentRoot.js +20 -16
  269. package/lib/util/dependentRoot.js.map +1 -1
  270. package/lib/util/sszBytes.d.ts.map +1 -1
  271. package/lib/util/sszBytes.js +8 -6
  272. package/lib/util/sszBytes.js.map +1 -1
  273. package/package.json +15 -16
  274. package/src/api/impl/beacon/blocks/index.ts +21 -5
  275. package/src/api/impl/beacon/pool/index.ts +136 -1
  276. package/src/api/impl/debug/index.ts +0 -1
  277. package/src/api/impl/lodestar/index.ts +1 -1
  278. package/src/api/impl/validator/index.ts +100 -11
  279. package/src/chain/blocks/blockInput/blockInput.ts +4 -1
  280. package/src/chain/blocks/importBlock.ts +16 -48
  281. package/src/chain/blocks/importExecutionPayload.ts +76 -30
  282. package/src/chain/blocks/index.ts +71 -22
  283. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +37 -3
  284. package/src/chain/blocks/payloadEnvelopeInput/types.ts +18 -0
  285. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  286. package/src/chain/blocks/types.ts +4 -3
  287. package/src/chain/blocks/utils/chainSegment.ts +117 -17
  288. package/src/chain/blocks/verifyBlock.ts +70 -9
  289. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  290. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  291. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +16 -8
  292. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  293. package/src/chain/chain.ts +46 -10
  294. package/src/chain/emitter.ts +0 -11
  295. package/src/chain/errors/blockError.ts +4 -1
  296. package/src/chain/errors/executionPayloadBid.ts +22 -1
  297. package/src/chain/errors/index.ts +1 -0
  298. package/src/chain/errors/proposerPreferences.ts +47 -0
  299. package/src/chain/initState.ts +9 -1
  300. package/src/chain/interface.ts +9 -1
  301. package/src/chain/lightClient/index.ts +6 -6
  302. package/src/chain/opPools/index.ts +1 -0
  303. package/src/chain/opPools/payloadAttestationPool.ts +63 -18
  304. package/src/chain/opPools/proposerPreferencesPool.ts +59 -0
  305. package/src/chain/prepareNextSlot.ts +21 -29
  306. package/src/chain/produceBlock/produceBlockBody.ts +46 -22
  307. package/src/chain/regen/interface.ts +1 -0
  308. package/src/chain/regen/queued.ts +2 -7
  309. package/src/chain/regen/regen.ts +2 -7
  310. package/src/chain/seenCache/index.ts +1 -0
  311. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +90 -24
  312. package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
  313. package/src/chain/validation/block.ts +1 -0
  314. package/src/chain/validation/executionPayloadBid.ts +71 -18
  315. package/src/chain/validation/payloadAttestationMessage.ts +6 -4
  316. package/src/chain/validation/proposerPreferences.ts +110 -0
  317. package/src/metrics/metrics/lodestar.ts +10 -0
  318. package/src/network/gossip/interface.ts +6 -0
  319. package/src/network/gossip/scoringParameters.ts +14 -1
  320. package/src/network/gossip/topic.ts +6 -0
  321. package/src/network/interface.ts +3 -0
  322. package/src/network/network.ts +34 -0
  323. package/src/network/processor/gossipHandlers.ts +96 -20
  324. package/src/network/processor/gossipQueues/index.ts +5 -0
  325. package/src/network/processor/index.ts +6 -5
  326. package/src/network/reqresp/ReqRespBeaconNode.ts +1 -0
  327. package/src/network/reqresp/handlers/beaconBlocksByHead.ts +91 -0
  328. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  329. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  330. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  331. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  332. package/src/network/reqresp/handlers/index.ts +5 -0
  333. package/src/network/reqresp/interface.ts +1 -1
  334. package/src/network/reqresp/protocols.ts +6 -0
  335. package/src/network/reqresp/rateLimit.ts +4 -0
  336. package/src/network/reqresp/score.ts +1 -0
  337. package/src/network/reqresp/types.ts +5 -0
  338. package/src/node/nodejs.ts +2 -2
  339. package/src/sync/constants.ts +8 -4
  340. package/src/sync/range/batch.ts +388 -75
  341. package/src/sync/range/chain.ts +131 -14
  342. package/src/sync/range/range.ts +86 -11
  343. package/src/sync/range/utils/peerBalancer.ts +9 -3
  344. package/src/sync/sync.ts +13 -1
  345. package/src/sync/types.ts +72 -0
  346. package/src/sync/unknownBlock.ts +915 -65
  347. package/src/sync/utils/downloadByRange.ts +386 -39
  348. package/src/sync/utils/downloadByRoot.ts +24 -2
  349. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  350. package/src/sync/utils/rateLimit.ts +16 -0
  351. package/src/util/dependentRoot.ts +22 -18
  352. package/src/util/sszBytes.ts +8 -6
@@ -14,6 +14,7 @@ import {
14
14
  isForkPostBellatrix,
15
15
  isForkPostDeneb,
16
16
  isForkPostElectra,
17
+ isForkPostFulu,
17
18
  isForkPostGloas,
18
19
  } from "@lodestar/params";
19
20
  import {
@@ -26,6 +27,7 @@ import {
26
27
  computeTimeAtSlot,
27
28
  getCurrentSlot,
28
29
  isStatePostAltair,
30
+ isStatePostGloas,
29
31
  proposerShufflingDecisionRoot,
30
32
  } from "@lodestar/state-transition";
31
33
  import {
@@ -1049,6 +1051,36 @@ export function getValidatorApi(
1049
1051
  };
1050
1052
  },
1051
1053
 
1054
+ async producePayloadAttestationData({slot}) {
1055
+ const fork = config.getForkName(slot);
1056
+ if (!isForkPostGloas(fork)) {
1057
+ throw new ApiError(400, `producePayloadAttestationData is not supported before Gloas fork=${fork}`);
1058
+ }
1059
+
1060
+ notWhileSyncing();
1061
+ await waitForSlot(slot);
1062
+
1063
+ const block = chain.forkChoice.getCanonicalBlockClosestLteSlot(slot);
1064
+ if (!block) {
1065
+ throw new ApiError(404, `No canonical block found at or before slot=${slot}`);
1066
+ }
1067
+
1068
+ const blockIsForSlot = block.slot === slot;
1069
+ const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
1070
+ const payloadPresent = blockIsForSlot && (payloadInput?.hasPayloadEnvelope() ?? false);
1071
+ const blobDataAvailable = blockIsForSlot && (payloadInput?.hasAllData() ?? false);
1072
+
1073
+ return {
1074
+ data: {
1075
+ beaconBlockRoot: fromHex(block.blockRoot),
1076
+ slot,
1077
+ payloadPresent,
1078
+ blobDataAvailable,
1079
+ },
1080
+ meta: {version: fork},
1081
+ };
1082
+ },
1083
+
1052
1084
  /**
1053
1085
  * GET `/eth/v1/validator/sync_committee_contribution`
1054
1086
  *
@@ -1093,26 +1125,33 @@ export function getValidatorApi(
1093
1125
  async getProposerDuties({epoch}, _context, opts?: {v2?: boolean}) {
1094
1126
  notWhileSyncing();
1095
1127
 
1096
- // Early check that epoch is no more than current_epoch + 1, or allow for pre-genesis
1097
1128
  const currentEpoch = currentEpochWithDisparity();
1098
1129
  const nextEpoch = currentEpoch + 1;
1099
- if (currentEpoch >= 0 && epoch > nextEpoch) {
1130
+ const startSlot = computeStartSlotAtEpoch(epoch);
1131
+ const prepareNextSlotLookAheadMs =
1132
+ config.SLOT_DURATION_MS - config.getSlotComponentDurationMs(PREPARE_NEXT_SLOT_BPS);
1133
+ const toNextEpochMs = msToNextEpoch();
1134
+ const nearNextEpoch = toNextEpochMs < prepareNextSlotLookAheadMs;
1135
+ // Post-Fulu the proposer lookahead is deterministic and known a full epoch ahead, so
1136
+ // close to the boundary `currentEpoch + 2` is serveable from the upcoming-epoch
1137
+ // checkpoint state (its `nextProposers`). Pre-Fulu / mid-epoch: `currentEpoch + 1` max.
1138
+ const isPostFulu = isForkPostFulu(config.getForkName(startSlot));
1139
+ const maxFutureEpoch = isPostFulu && nearNextEpoch && opts?.v2 ? nextEpoch + 1 : nextEpoch;
1140
+ if (currentEpoch >= 0 && epoch > maxFutureEpoch) {
1100
1141
  throw new ApiError(400, `Requested epoch ${epoch} must not be more than one epoch in the future`);
1101
1142
  }
1102
1143
 
1103
1144
  const head = chain.forkChoice.getHead();
1104
1145
  let state: IBeaconStateView | undefined = undefined;
1105
- const startSlot = computeStartSlotAtEpoch(epoch);
1106
- const prepareNextSlotLookAheadMs =
1107
- config.SLOT_DURATION_MS - config.getSlotComponentDurationMs(PREPARE_NEXT_SLOT_BPS);
1108
- const toNextEpochMs = msToNextEpoch();
1109
1146
  // validators may request next epoch's duties when it's close to next epoch
1110
- // this is to avoid missed block proposal due to 0 epoch look ahead
1111
- if (epoch === nextEpoch && toNextEpochMs < prepareNextSlotLookAheadMs) {
1147
+ // this is to avoid missed block proposal due to 0 epoch look ahead.
1148
+ // Post-Fulu, `nextEpoch + 1` is served from the same upcoming-epoch (`nextEpoch`)
1149
+ // checkpoint state via its `nextProposers` (deterministic proposer lookahead).
1150
+ if (nearNextEpoch && (epoch === nextEpoch || (isPostFulu && epoch === nextEpoch + 1))) {
1112
1151
  // wait for maximum 1 slot for cp state which is the timeout of validator api
1113
1152
  const cpState = await waitForCheckpointState({
1114
1153
  rootHex: head.blockRoot,
1115
- epoch,
1154
+ epoch: nextEpoch,
1116
1155
  });
1117
1156
  if (cpState) {
1118
1157
  state = cpState;
@@ -1187,7 +1226,7 @@ export function getValidatorApi(
1187
1226
  // It should be set to the latest block applied to `self` or the genesis block root.
1188
1227
  const dependentRoot =
1189
1228
  // In v2 the dependent root is different after fulu due to deterministic proposer lookahead
1190
- proposerShufflingDecisionRoot(opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0, state) ||
1229
+ proposerShufflingDecisionRoot(opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0, state, epoch) ||
1191
1230
  (await getGenesisBlockRoot(state));
1192
1231
 
1193
1232
  return {
@@ -1263,6 +1302,55 @@ export function getValidatorApi(
1263
1302
  };
1264
1303
  },
1265
1304
 
1305
+ async getPtcDuties({epoch, indices}) {
1306
+ notWhileSyncing();
1307
+
1308
+ if (indices.length === 0) {
1309
+ throw new ApiError(400, "No validator to get PTC duties");
1310
+ }
1311
+
1312
+ const startSlot = computeStartSlotAtEpoch(epoch);
1313
+ const fork = config.getForkName(startSlot);
1314
+ if (!isForkPostGloas(fork)) {
1315
+ throw new ApiError(400, `PTC duties are not supported before Gloas fork=${fork}`);
1316
+ }
1317
+
1318
+ await waitForNextClosestEpoch();
1319
+
1320
+ if (epoch > chain.clock.currentEpoch + 1) {
1321
+ throw new ApiError(400, "Cannot get PTC duties for epoch more than one ahead");
1322
+ }
1323
+
1324
+ const head = chain.forkChoice.getHead();
1325
+ const state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.getDuties);
1326
+ if (!isStatePostGloas(state)) {
1327
+ throw new ApiError(400, `PTC duties are not available before Gloas fork=${state.forkName}`);
1328
+ }
1329
+
1330
+ const pubkeys = getPubkeysForIndices(state, indices);
1331
+ const ptcs = state.getEpochPTCs(epoch);
1332
+ const duties: routes.validator.PtcDuty[] = [];
1333
+ for (let i = 0, len = indices.length; i < len; i++) {
1334
+ const validatorIndex = indices[i];
1335
+ for (let j = 0; j < SLOTS_PER_EPOCH; j++) {
1336
+ if (ptcs[j].indexOf(validatorIndex) !== -1) {
1337
+ duties.push({pubkey: pubkeys[i], validatorIndex, slot: j + startSlot});
1338
+ break;
1339
+ }
1340
+ }
1341
+ }
1342
+
1343
+ const dependentRoot = fromHex(state.getShufflingDecisionRoot(epoch)) || (await getGenesisBlockRoot(state));
1344
+
1345
+ return {
1346
+ data: duties,
1347
+ meta: {
1348
+ dependentRoot: toRootHex(dependentRoot),
1349
+ executionOptimistic: isOptimisticBlock(head),
1350
+ },
1351
+ };
1352
+ },
1353
+
1266
1354
  /**
1267
1355
  * `POST /eth/v1/validator/duties/sync/{epoch}`
1268
1356
  *
@@ -1641,13 +1729,14 @@ export function getValidatorApi(
1641
1729
  throw Error("Cached block production result is not full block");
1642
1730
  }
1643
1731
 
1644
- const {executionPayload, executionRequests} = produceResult as ProduceFullGloas;
1732
+ const {executionPayload, executionRequests, parentBlockRoot} = produceResult as ProduceFullGloas;
1645
1733
 
1646
1734
  const envelope: gloas.ExecutionPayloadEnvelope = {
1647
1735
  payload: executionPayload,
1648
1736
  executionRequests: executionRequests,
1649
1737
  builderIndex: BUILDER_INDEX_SELF_BUILD,
1650
1738
  beaconBlockRoot,
1739
+ parentBeaconBlockRoot: parentBlockRoot,
1651
1740
  };
1652
1741
 
1653
1742
  logger.info("Produced execution payload envelope", {
@@ -895,8 +895,11 @@ export class BlockInputColumns extends AbstractBlockInput<ForkColumnsDA, fulu.Da
895
895
  return this.getAllColumnsWithSource().map(({columnSidecar}) => columnSidecar);
896
896
  }
897
897
 
898
+ /**
899
+ * Strictly checks missing sampled columns. Does NOT short-circuit on `state.hasAllData`.
900
+ */
898
901
  getMissingSampledColumnMeta(): MissingColumnMeta {
899
- if (this.state.hasAllData) {
902
+ if (this.state.hasComputedAllData) {
900
903
  return {
901
904
  missing: [],
902
905
  versionedHashes: this.state.versionedHashes,
@@ -9,14 +9,7 @@ import {
9
9
  NotReorgedReason,
10
10
  getSafeExecutionBlockHash,
11
11
  } from "@lodestar/fork-choice";
12
- import {
13
- ForkPostAltair,
14
- ForkPostElectra,
15
- ForkPostGloas,
16
- ForkSeq,
17
- MAX_SEED_LOOKAHEAD,
18
- SLOTS_PER_EPOCH,
19
- } from "@lodestar/params";
12
+ import {ForkPostAltair, ForkPostElectra, ForkSeq, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params";
20
13
  import {
21
14
  IBeaconStateView,
22
15
  RootCache,
@@ -27,17 +20,7 @@ import {
27
20
  isStatePostAltair,
28
21
  isStatePostBellatrix,
29
22
  } from "@lodestar/state-transition";
30
- import {
31
- Attestation,
32
- BeaconBlock,
33
- SignedBeaconBlock,
34
- altair,
35
- capella,
36
- electra,
37
- isGloasBeaconBlock,
38
- phase0,
39
- ssz,
40
- } from "@lodestar/types";
23
+ import {Attestation, BeaconBlock, altair, capella, electra, isGloasBeaconBlock, phase0, ssz} from "@lodestar/types";
41
24
  import {isErrorAborted, toRootHex} from "@lodestar/utils";
42
25
  import {ZERO_HASH_HEX} from "../../constants/index.js";
43
26
  import {callInNextEventLoop} from "../../util/eventLoop.js";
@@ -86,8 +69,8 @@ export async function importBlock(
86
69
  fullyVerifiedBlock: FullyVerifiedBlock,
87
70
  opts: ImportBlockOpts
88
71
  ): Promise<void> {
89
- const {blockInput, postState, parentBlockSlot, executionStatus, dataAvailabilityStatus, indexedAttestations} =
90
- fullyVerifiedBlock;
72
+ const {blockInput, postState, parentBlockSlot, dataAvailabilityStatus, indexedAttestations} = fullyVerifiedBlock;
73
+ let {executionStatus} = fullyVerifiedBlock;
91
74
  const block = blockInput.getBlock();
92
75
  const source = blockInput.getBlockSource();
93
76
  const {slot: blockSlot} = block.message;
@@ -122,12 +105,23 @@ export async function importBlock(
122
105
 
123
106
  // Should compute checkpoint balances before forkchoice.onBlock
124
107
  this.checkpointBalancesCache.processState(blockRootHex, postState);
108
+ if (fork >= ForkSeq.gloas) {
109
+ const parentRootHex = toRootHex(block.message.parentRoot);
110
+ const parentBlock = this.forkChoice.getBlockHexDefaultStatus(parentRootHex);
111
+ if (parentBlock === null) {
112
+ throw Error(`Parent block not found in forkChoice, parentRoot=${parentRootHex}`);
113
+ }
114
+ if (parentBlock.executionStatus === ExecutionStatus.Invalid) {
115
+ throw Error(`Parent block has invalid execution status, parentRoot=${parentRootHex}`);
116
+ }
117
+ executionStatus = parentBlock.executionStatus;
118
+ }
125
119
  const blockSummary = this.forkChoice.onBlock(
126
120
  block.message,
127
121
  postState,
128
122
  blockDelaySec,
129
123
  currentSlot,
130
- fork >= ForkSeq.gloas ? ExecutionStatus.PayloadSeparated : executionStatus,
124
+ executionStatus,
131
125
  dataAvailabilityStatus
132
126
  );
133
127
 
@@ -135,32 +129,6 @@ export async function importBlock(
135
129
  // Some block event handlers require state being in state cache so need to do this before emitting EventType.block
136
130
  this.regen.processState(blockRootHex, postState);
137
131
 
138
- // For Gloas blocks, create PayloadEnvelopeInput so it's available for later payload import
139
- if (fork >= ForkSeq.gloas) {
140
- const payloadInput = this.seenPayloadEnvelopeInputCache.add({
141
- blockRootHex,
142
- block: block as SignedBeaconBlock<ForkPostGloas>,
143
- forkName: blockInput.forkName,
144
- sampledColumns: this.custodyConfig.sampledColumns,
145
- custodyColumns: this.custodyConfig.custodyColumns,
146
- timeCreatedSec: fullyVerifiedBlock.seenTimestampSec,
147
- });
148
- this.logger.debug("Created PayloadEnvelopeInput for block", {
149
- slot: blockSlot,
150
- root: blockRootHex,
151
- source: source.source,
152
- ...(opts.seenTimestampSec !== undefined ? {recvToImport: Date.now() / 1000 - opts.seenTimestampSec} : {}),
153
- });
154
-
155
- // Immediately attempt fetch of data columns from execution engine as the bid contains kzg commitments
156
- // which is all the information we need so there is no reason to delay until execution payload arrives
157
- // TODO GLOAS: If we want EL retries after this initial attempt, add an explicit retry policy here
158
- // (for example later in the slot). Do not couple retries to incoming gossip columns.
159
- // Columns fetched here feed payloadInput.addColumn, which resolves waitForAllData for any
160
- // in-flight importExecutionPayload. No processExecutionPayload trigger needed from this path.
161
- this.getBlobsTracker.triggerGetBlobs(payloadInput);
162
- }
163
-
164
132
  this.metrics?.importBlock.bySource.inc({source: source.source});
165
133
  this.logger.verbose("Added block to forkchoice and state cache", {slot: blockSlot, root: blockRootHex});
166
134
 
@@ -1,7 +1,8 @@
1
1
  import {routes} from "@lodestar/api";
2
- import {ExecutionStatus, PayloadExecutionStatus} from "@lodestar/fork-choice";
3
- import {isStatePostGloas} from "@lodestar/state-transition";
4
- import {fromHex} 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";
5
6
  import {ExecutionPayloadStatus} from "../../execution/index.js";
6
7
  import {isQueueErrorAborted} from "../../util/queue/index.js";
7
8
  import {BeaconChain} from "../chain.js";
@@ -20,6 +21,7 @@ export enum PayloadErrorCode {
20
21
  EXECUTION_ENGINE_INVALID = "PAYLOAD_ERROR_EXECUTION_ENGINE_INVALID",
21
22
  EXECUTION_ENGINE_ERROR = "PAYLOAD_ERROR_EXECUTION_ENGINE_ERROR",
22
23
  BLOCK_NOT_IN_FORK_CHOICE = "PAYLOAD_ERROR_BLOCK_NOT_IN_FORK_CHOICE",
24
+ MISS_BLOCK_STATE = "PAYLOAD_ERROR_MISS_BLOCK_STATE",
23
25
  ENVELOPE_VERIFICATION_ERROR = "PAYLOAD_ERROR_ENVELOPE_VERIFICATION_ERROR",
24
26
  INVALID_SIGNATURE = "PAYLOAD_ERROR_INVALID_SIGNATURE",
25
27
  }
@@ -39,6 +41,10 @@ export type PayloadErrorType =
39
41
  code: PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE;
40
42
  blockRootHex: string;
41
43
  }
44
+ | {
45
+ code: PayloadErrorCode.MISS_BLOCK_STATE;
46
+ blockRootHex: string;
47
+ }
42
48
  | {
43
49
  code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR;
44
50
  message: string;
@@ -60,7 +66,6 @@ function toForkChoiceExecutionStatus(status: ExecutionPayloadStatus): PayloadExe
60
66
  switch (status) {
61
67
  case ExecutionPayloadStatus.VALID:
62
68
  return ExecutionStatus.Valid;
63
- // TODO GLOAS: Handle optimistic import for payload
64
69
  case ExecutionPayloadStatus.SYNCING:
65
70
  case ExecutionPayloadStatus.ACCEPTED:
66
71
  return ExecutionStatus.Syncing;
@@ -75,21 +80,24 @@ function toForkChoiceExecutionStatus(status: ExecutionPayloadStatus): PayloadExe
75
80
  * The envelope is only verified here, no state mutation. State effects from the payload
76
81
  * are applied on the next block via processParentExecutionPayload.
77
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).
85
+ *
78
86
  * Steps:
79
87
  * 1. Emit `execution_payload_available` event for payload attestation
80
88
  * 2. Get the ProtoBlock from fork choice
81
- * 3. Wait for data columns to be available
82
- * 4. Regenerate state for envelope verification
83
- * 5. Verify envelope (fields against state, signature, and EL in parallel where possible)
84
- * 6. Persist verified payload envelope to hot DB (waits for write-queue space for backpressure)
85
- * 7. Update fork choice (transitions the block's PENDING variant to FULL)
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
86
94
  * 8. Record metrics for payload envelope and column sources
87
95
  * 9. Emit `execution_payload` event
88
96
  */
89
97
  export async function importExecutionPayload(
90
98
  this: BeaconChain,
91
99
  payloadInput: PayloadEnvelopeInput,
92
- signal: AbortSignal,
100
+ dataAvailabilityStatus: DataAvailabilityStatus,
93
101
  opts: ImportPayloadOpts = {}
94
102
  ): Promise<void> {
95
103
  const signedEnvelope = payloadInput.getPayloadEnvelope();
@@ -119,17 +127,20 @@ export async function importExecutionPayload(
119
127
  });
120
128
  }
121
129
 
122
- // 3. Wait for data columns to be available.
123
- // The helper is shared with future gloas sync services; take the single-item batch form here.
124
- await verifyPayloadsDataAvailability([payloadInput], signal);
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
+ );
125
137
 
126
- // 4. Regenerate state for envelope verification
127
- const blockState = await this.regen.getBlockSlotState(
128
- protoBlock,
129
- protoBlock.slot,
130
- {dontTransferCache: true},
131
- RegenCaller.processBlock
132
- );
138
+ if (blockState == null) {
139
+ throw new PayloadError({
140
+ code: PayloadErrorCode.MISS_BLOCK_STATE,
141
+ blockRootHex: protoBlock.blockRoot,
142
+ });
143
+ }
133
144
  if (!isStatePostGloas(blockState)) {
134
145
  throw new PayloadError({
135
146
  code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
@@ -137,7 +148,7 @@ export async function importExecutionPayload(
137
148
  });
138
149
  }
139
150
 
140
- // 5. Verify envelope fields against state first to fail fast before the EL + BLS work.
151
+ // 4. Verify envelope fields against state first to fail fast before the EL + BLS work.
141
152
  // When validSignature is true, gossip/API has already verified both the signature and the
142
153
  // executionRequestsRoot, so we skip those checks here.
143
154
  try {
@@ -154,13 +165,13 @@ export async function importExecutionPayload(
154
165
  );
155
166
  }
156
167
 
157
- // 5a. Run EL and signature verification in parallel
168
+ // 4a. Run EL and signature verification in parallel
158
169
  const [execResult, signatureValid] = await Promise.all([
159
170
  this.executionEngine.notifyNewPayload(
160
171
  fork,
161
172
  envelope.payload,
162
173
  payloadInput.getVersionedHashes(),
163
- fromHex(protoBlock.parentRoot),
174
+ envelope.parentBeaconBlockRoot,
164
175
  envelope.executionRequests
165
176
  ),
166
177
 
@@ -176,12 +187,12 @@ export async function importExecutionPayload(
176
187
  ),
177
188
  ]);
178
189
 
179
- // 5b. Check signature verification result
190
+ // 4b. Check signature verification result
180
191
  if (!signatureValid) {
181
192
  throw new PayloadError({code: PayloadErrorCode.INVALID_SIGNATURE});
182
193
  }
183
194
 
184
- // 5c. Handle EL response
195
+ // 4c. Handle EL response
185
196
  switch (execResult.status) {
186
197
  case ExecutionPayloadStatus.VALID:
187
198
  break;
@@ -207,7 +218,7 @@ export async function importExecutionPayload(
207
218
  });
208
219
  }
209
220
 
210
- // 6. Persist payload envelope to hot DB. Wait for write-queue space here to apply backpressure
221
+ // 5. Persist payload envelope to hot DB. Wait for write-queue space here to apply backpressure
211
222
  // on the import pipeline during sync, then perform the write asynchronously to avoid blocking.
212
223
  await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
213
224
  this.unfinalizedPayloadEnvelopeWrites.push(payloadInput).catch((e) => {
@@ -220,9 +231,27 @@ export async function importExecutionPayload(
220
231
  }
221
232
  });
222
233
 
223
- // 7. Update fork choice, transitions the block's PENDING variant to FULL
234
+ // 6. Update fork choice, transitions the block's PENDING variant to FULL
224
235
  const execStatus = toForkChoiceExecutionStatus(execResult.status);
225
- this.forkChoice.onExecutionPayload(blockRootHex, blockHashHex, envelope.payload.blockNumber, execStatus);
236
+ this.forkChoice.onExecutionPayload(
237
+ blockRootHex,
238
+ blockHashHex,
239
+ envelope.payload.blockNumber,
240
+ execStatus,
241
+ dataAvailabilityStatus
242
+ );
243
+
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
+ });
254
+ }
226
255
 
227
256
  // 8. Record metrics for payload envelope and column sources
228
257
  this.metrics?.importPayload.bySource.inc({source: payloadInput.getPayloadEnvelopeSource().source});
@@ -237,8 +266,7 @@ export async function importExecutionPayload(
237
266
  builderIndex: envelope.builderIndex,
238
267
  blockHash: blockHashHex,
239
268
  blockRoot: blockRootHex,
240
- // TODO GLOAS: revisit once we support optimistic import
241
- executionOptimistic: false,
269
+ executionOptimistic: execStatus === ExecutionStatus.Syncing,
242
270
  });
243
271
  }
244
272
 
@@ -249,3 +277,21 @@ export async function importExecutionPayload(
249
277
  blockHash: blockHashHex,
250
278
  });
251
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,24 +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
118
  parentBlockSlot: parentSlots[i],
93
119
  executionStatus: executionStatuses[i],
94
120
  // start supporting optimistic syncing/processing
95
- dataAvailabilityStatus: dataAvailabilityStatuses[i],
121
+ dataAvailabilityStatus: blockDAStatuses[i],
96
122
  proposerBalanceDelta: proposerBalanceDeltas[i],
97
123
  indexedAttestations: indexedAttestationsByBlock[i],
98
124
  // TODO: Make this param mandatory and capture in gossip
99
125
  seenTimestampSec: opts.seenTimestampSec ?? Math.floor(Date.now() / 1000),
100
- })
101
- );
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
+ }
102
154
 
103
- for (const fullyVerifiedBlock of fullyVerifiedBlocks) {
104
- // TODO: Consider batching importBlock too if it takes significant time
105
- await importBlock.call(this, fullyVerifiedBlock, opts);
106
155
  await nextEventLoop();
107
156
  }
108
157
  } catch (e) {