@lodestar/beacon-node 1.43.0-dev.e341cdc614 → 1.43.0-dev.e3c96e7a79

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 (345) 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/archiveStore/archiveStore.d.ts.map +1 -1
  19. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  20. package/lib/chain/archiveStore/interface.d.ts +4 -4
  21. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  22. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
  23. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
  24. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
  25. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +2 -2
  26. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  27. package/lib/chain/archiveStore/utils/archiveBlocks.js +110 -58
  28. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  29. package/lib/chain/blocks/blockInput/blockInput.d.ts +3 -0
  30. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  31. package/lib/chain/blocks/blockInput/blockInput.js +4 -1
  32. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  33. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  34. package/lib/chain/blocks/importBlock.js +16 -28
  35. package/lib/chain/blocks/importBlock.js.map +1 -1
  36. package/lib/chain/blocks/importExecutionPayload.d.ts +28 -14
  37. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  38. package/lib/chain/blocks/importExecutionPayload.js +88 -90
  39. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  40. package/lib/chain/blocks/index.d.ts +5 -3
  41. package/lib/chain/blocks/index.d.ts.map +1 -1
  42. package/lib/chain/blocks/index.js +59 -26
  43. package/lib/chain/blocks/index.js.map +1 -1
  44. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +4 -0
  45. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  46. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +9 -2
  47. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  48. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +1 -0
  49. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  50. package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
  51. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  52. package/lib/chain/blocks/types.d.ts +15 -20
  53. package/lib/chain/blocks/types.d.ts.map +1 -1
  54. package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
  55. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  56. package/lib/chain/blocks/utils/chainSegment.js +89 -12
  57. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  58. package/lib/chain/blocks/verifyBlock.d.ts +5 -3
  59. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  60. package/lib/chain/blocks/verifyBlock.js +50 -7
  61. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  62. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
  63. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  64. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
  65. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  66. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
  67. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  68. package/lib/chain/blocks/verifyBlocksSanityChecks.js +25 -5
  69. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  70. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
  71. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
  72. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +79 -0
  73. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
  74. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  75. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
  76. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  77. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
  78. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
  79. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
  80. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  81. package/lib/chain/chain.d.ts +8 -6
  82. package/lib/chain/chain.d.ts.map +1 -1
  83. package/lib/chain/chain.js +29 -13
  84. package/lib/chain/chain.js.map +1 -1
  85. package/lib/chain/emitter.d.ts +3 -14
  86. package/lib/chain/emitter.d.ts.map +1 -1
  87. package/lib/chain/emitter.js +0 -4
  88. package/lib/chain/emitter.js.map +1 -1
  89. package/lib/chain/errors/blockError.d.ts +8 -1
  90. package/lib/chain/errors/blockError.d.ts.map +1 -1
  91. package/lib/chain/errors/blockError.js +2 -0
  92. package/lib/chain/errors/blockError.js.map +1 -1
  93. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  94. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  95. package/lib/chain/errors/executionPayloadBid.js +1 -0
  96. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  97. package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
  98. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  99. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  100. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  101. package/lib/chain/errors/index.d.ts +1 -0
  102. package/lib/chain/errors/index.d.ts.map +1 -1
  103. package/lib/chain/errors/index.js +1 -0
  104. package/lib/chain/errors/index.js.map +1 -1
  105. package/lib/chain/errors/proposerPreferences.d.ts +40 -0
  106. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  107. package/lib/chain/errors/proposerPreferences.js +14 -0
  108. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  109. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  110. package/lib/chain/forkChoice/index.js +11 -19
  111. package/lib/chain/forkChoice/index.js.map +1 -1
  112. package/lib/chain/initState.d.ts.map +1 -1
  113. package/lib/chain/initState.js +6 -1
  114. package/lib/chain/initState.js.map +1 -1
  115. package/lib/chain/interface.d.ts +7 -5
  116. package/lib/chain/interface.d.ts.map +1 -1
  117. package/lib/chain/interface.js.map +1 -1
  118. package/lib/chain/opPools/payloadAttestationPool.d.ts +3 -2
  119. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  120. package/lib/chain/opPools/payloadAttestationPool.js +26 -4
  121. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  122. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  123. package/lib/chain/prepareNextSlot.js +45 -17
  124. package/lib/chain/prepareNextSlot.js.map +1 -1
  125. package/lib/chain/produceBlock/produceBlockBody.d.ts +13 -2
  126. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  127. package/lib/chain/produceBlock/produceBlockBody.js +68 -25
  128. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  129. package/lib/chain/regen/interface.d.ts +1 -0
  130. package/lib/chain/regen/interface.d.ts.map +1 -1
  131. package/lib/chain/regen/interface.js +1 -0
  132. package/lib/chain/regen/interface.js.map +1 -1
  133. package/lib/chain/regen/queued.d.ts.map +1 -1
  134. package/lib/chain/regen/queued.js +1 -4
  135. package/lib/chain/regen/queued.js.map +1 -1
  136. package/lib/chain/regen/regen.d.ts.map +1 -1
  137. package/lib/chain/regen/regen.js +1 -4
  138. package/lib/chain/regen/regen.js.map +1 -1
  139. package/lib/chain/seenCache/index.d.ts +1 -0
  140. package/lib/chain/seenCache/index.d.ts.map +1 -1
  141. package/lib/chain/seenCache/index.js +1 -0
  142. package/lib/chain/seenCache/index.js.map +1 -1
  143. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +22 -6
  144. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  145. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +53 -17
  146. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  147. package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
  148. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  149. package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
  150. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  151. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  152. package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -1
  153. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  154. package/lib/chain/validation/block.d.ts.map +1 -1
  155. package/lib/chain/validation/block.js +1 -0
  156. package/lib/chain/validation/block.js.map +1 -1
  157. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  158. package/lib/chain/validation/executionPayloadBid.js +24 -9
  159. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  160. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  161. package/lib/chain/validation/executionPayloadEnvelope.js +19 -9
  162. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  163. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  164. package/lib/chain/validation/payloadAttestationMessage.js +4 -3
  165. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  166. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  167. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  168. package/lib/chain/validation/proposerPreferences.js +91 -0
  169. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  170. package/lib/db/repositories/executionPayloadEnvelopeArchive.js +1 -1
  171. package/lib/db/repositories/executionPayloadEnvelopeArchive.js.map +1 -1
  172. package/lib/execution/engine/http.d.ts.map +1 -1
  173. package/lib/execution/engine/http.js +21 -14
  174. package/lib/execution/engine/http.js.map +1 -1
  175. package/lib/execution/engine/interface.d.ts +1 -0
  176. package/lib/execution/engine/interface.d.ts.map +1 -1
  177. package/lib/execution/engine/mock.d.ts.map +1 -1
  178. package/lib/execution/engine/mock.js +6 -0
  179. package/lib/execution/engine/mock.js.map +1 -1
  180. package/lib/execution/engine/types.d.ts +20 -0
  181. package/lib/execution/engine/types.d.ts.map +1 -1
  182. package/lib/execution/engine/types.js +18 -0
  183. package/lib/execution/engine/types.js.map +1 -1
  184. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  185. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  186. package/lib/metrics/metrics/lodestar.js +4 -0
  187. package/lib/metrics/metrics/lodestar.js.map +1 -1
  188. package/lib/network/gossip/interface.d.ts +7 -1
  189. package/lib/network/gossip/interface.d.ts.map +1 -1
  190. package/lib/network/gossip/interface.js +1 -0
  191. package/lib/network/gossip/interface.js.map +1 -1
  192. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  193. package/lib/network/gossip/scoringParameters.js +12 -1
  194. package/lib/network/gossip/scoringParameters.js.map +1 -1
  195. package/lib/network/gossip/topic.d.ts +13 -2
  196. package/lib/network/gossip/topic.d.ts.map +1 -1
  197. package/lib/network/gossip/topic.js +6 -0
  198. package/lib/network/gossip/topic.js.map +1 -1
  199. package/lib/network/interface.d.ts +1 -0
  200. package/lib/network/interface.d.ts.map +1 -1
  201. package/lib/network/network.d.ts +1 -0
  202. package/lib/network/network.d.ts.map +1 -1
  203. package/lib/network/network.js +6 -1
  204. package/lib/network/network.js.map +1 -1
  205. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  206. package/lib/network/processor/gossipHandlers.js +41 -19
  207. package/lib/network/processor/gossipHandlers.js.map +1 -1
  208. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  209. package/lib/network/processor/gossipQueues/index.js +5 -0
  210. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  211. package/lib/network/processor/index.d.ts.map +1 -1
  212. package/lib/network/processor/index.js +6 -5
  213. package/lib/network/processor/index.js.map +1 -1
  214. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  215. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  216. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  217. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  218. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  219. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  220. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  221. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  222. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  223. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  224. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  225. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  226. package/lib/node/nodejs.d.ts.map +1 -1
  227. package/lib/node/nodejs.js +6 -4
  228. package/lib/node/nodejs.js.map +1 -1
  229. package/lib/sync/constants.d.ts +3 -1
  230. package/lib/sync/constants.d.ts.map +1 -1
  231. package/lib/sync/constants.js +3 -4
  232. package/lib/sync/constants.js.map +1 -1
  233. package/lib/sync/range/batch.d.ts +28 -2
  234. package/lib/sync/range/batch.d.ts.map +1 -1
  235. package/lib/sync/range/batch.js +146 -44
  236. package/lib/sync/range/batch.js.map +1 -1
  237. package/lib/sync/range/chain.d.ts +12 -2
  238. package/lib/sync/range/chain.d.ts.map +1 -1
  239. package/lib/sync/range/chain.js +53 -9
  240. package/lib/sync/range/chain.js.map +1 -1
  241. package/lib/sync/range/range.d.ts.map +1 -1
  242. package/lib/sync/range/range.js +17 -6
  243. package/lib/sync/range/range.js.map +1 -1
  244. package/lib/sync/types.d.ts +34 -0
  245. package/lib/sync/types.d.ts.map +1 -1
  246. package/lib/sync/types.js +34 -0
  247. package/lib/sync/types.js.map +1 -1
  248. package/lib/sync/unknownBlock.d.ts +22 -1
  249. package/lib/sync/unknownBlock.d.ts.map +1 -1
  250. package/lib/sync/unknownBlock.js +604 -53
  251. package/lib/sync/unknownBlock.js.map +1 -1
  252. package/lib/sync/utils/downloadByRange.d.ts +46 -10
  253. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  254. package/lib/sync/utils/downloadByRange.js +162 -24
  255. package/lib/sync/utils/downloadByRange.js.map +1 -1
  256. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  257. package/lib/sync/utils/downloadByRoot.js +16 -2
  258. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  259. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  260. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  261. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  262. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  263. package/lib/util/sszBytes.d.ts.map +1 -1
  264. package/lib/util/sszBytes.js +20 -5
  265. package/lib/util/sszBytes.js.map +1 -1
  266. package/package.json +17 -16
  267. package/src/api/impl/beacon/blocks/index.ts +22 -9
  268. package/src/api/impl/beacon/pool/index.ts +83 -1
  269. package/src/api/impl/beacon/state/utils.ts +2 -2
  270. package/src/api/impl/debug/index.ts +0 -1
  271. package/src/api/impl/lodestar/index.ts +1 -1
  272. package/src/api/impl/validator/index.ts +82 -5
  273. package/src/chain/archiveStore/archiveStore.ts +5 -5
  274. package/src/chain/archiveStore/interface.ts +4 -4
  275. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +4 -4
  276. package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
  277. package/src/chain/blocks/blockInput/blockInput.ts +4 -1
  278. package/src/chain/blocks/importBlock.ts +16 -48
  279. package/src/chain/blocks/importExecutionPayload.ts +109 -105
  280. package/src/chain/blocks/index.ts +73 -23
  281. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +10 -2
  282. package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -0
  283. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  284. package/src/chain/blocks/types.ts +15 -25
  285. package/src/chain/blocks/utils/chainSegment.ts +114 -17
  286. package/src/chain/blocks/verifyBlock.ts +70 -9
  287. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  288. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  289. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +134 -0
  290. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  291. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  292. package/src/chain/chain.ts +48 -26
  293. package/src/chain/emitter.ts +3 -14
  294. package/src/chain/errors/blockError.ts +4 -1
  295. package/src/chain/errors/executionPayloadBid.ts +6 -0
  296. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  297. package/src/chain/errors/index.ts +1 -0
  298. package/src/chain/errors/proposerPreferences.ts +47 -0
  299. package/src/chain/forkChoice/index.ts +8 -24
  300. package/src/chain/initState.ts +9 -1
  301. package/src/chain/interface.ts +11 -3
  302. package/src/chain/opPools/payloadAttestationPool.ts +29 -8
  303. package/src/chain/prepareNextSlot.ts +53 -18
  304. package/src/chain/produceBlock/produceBlockBody.ts +91 -21
  305. package/src/chain/regen/interface.ts +1 -0
  306. package/src/chain/regen/queued.ts +2 -7
  307. package/src/chain/regen/regen.ts +2 -7
  308. package/src/chain/seenCache/index.ts +1 -0
  309. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +71 -20
  310. package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
  311. package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
  312. package/src/chain/validation/block.ts +1 -0
  313. package/src/chain/validation/executionPayloadBid.ts +25 -8
  314. package/src/chain/validation/executionPayloadEnvelope.ts +20 -10
  315. package/src/chain/validation/payloadAttestationMessage.ts +5 -3
  316. package/src/chain/validation/proposerPreferences.ts +110 -0
  317. package/src/db/repositories/executionPayloadEnvelopeArchive.ts +1 -1
  318. package/src/execution/engine/http.ts +21 -14
  319. package/src/execution/engine/interface.ts +1 -0
  320. package/src/execution/engine/mock.ts +8 -1
  321. package/src/execution/engine/types.ts +41 -0
  322. package/src/metrics/metrics/lodestar.ts +4 -0
  323. package/src/network/gossip/interface.ts +6 -0
  324. package/src/network/gossip/scoringParameters.ts +14 -1
  325. package/src/network/gossip/topic.ts +6 -0
  326. package/src/network/interface.ts +1 -0
  327. package/src/network/network.ts +12 -1
  328. package/src/network/processor/gossipHandlers.ts +56 -20
  329. package/src/network/processor/gossipQueues/index.ts +5 -0
  330. package/src/network/processor/index.ts +6 -5
  331. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  332. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  333. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  334. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  335. package/src/node/nodejs.ts +6 -4
  336. package/src/sync/constants.ts +4 -4
  337. package/src/sync/range/batch.ts +204 -49
  338. package/src/sync/range/chain.ts +69 -11
  339. package/src/sync/range/range.ts +18 -6
  340. package/src/sync/types.ts +72 -0
  341. package/src/sync/unknownBlock.ts +762 -57
  342. package/src/sync/utils/downloadByRange.ts +272 -39
  343. package/src/sync/utils/downloadByRoot.ts +24 -2
  344. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  345. package/src/util/sszBytes.ts +25 -5
@@ -4,12 +4,14 @@ import {getSafeExecutionBlockHash} from "@lodestar/fork-choice";
4
4
  import {ForkPostBellatrix, ForkSeq, SLOTS_PER_EPOCH, isForkPostBellatrix} from "@lodestar/params";
5
5
  import {
6
6
  IBeaconStateView,
7
+ IBeaconStateViewBellatrix,
7
8
  StateHashTreeRootSource,
8
9
  computeEpochAtSlot,
9
10
  computeTimeAtSlot,
10
11
  isStatePostBellatrix,
12
+ isStatePostGloas,
11
13
  } from "@lodestar/state-transition";
12
- import {Slot} from "@lodestar/types";
14
+ import {Bytes32, Slot} from "@lodestar/types";
13
15
  import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils";
14
16
  import {GENESIS_SLOT, ZERO_HASH_HEX} from "../constants/constants.js";
15
17
  import {BuilderStatus} from "../execution/builder/http.js";
@@ -81,6 +83,8 @@ export class PrepareNextSlotScheduler {
81
83
  // calling updateHead() here before we produce a block to reduce reorg possibility
82
84
  const headBlock = this.chain.recomputeForkChoiceHead(ForkchoiceCaller.prepareNextSlot);
83
85
  const {slot: headSlot, blockRoot: headRoot} = headBlock;
86
+ // may be updated below if we predict a proposer-boost-reorg
87
+ let updatedHead = headBlock;
84
88
 
85
89
  // PS: previously this was comparing slots, but that gave no leway on the skipped
86
90
  // slots on epoch bounday. Making it more fluid.
@@ -123,7 +127,6 @@ export class PrepareNextSlotScheduler {
123
127
  const proposerIndex = prepareState.getBeaconProposer(prepareSlot);
124
128
  const feeRecipient = this.chain.beaconProposerCache.get(proposerIndex);
125
129
  let updatedPrepareState = prepareState;
126
- let updatedHeadRoot = headRoot;
127
130
 
128
131
  if (feeRecipient) {
129
132
  // If we are proposing next slot, we need to predict if we can proposer-boost-reorg or not
@@ -146,7 +149,7 @@ export class PrepareNextSlotScheduler {
146
149
  {dontTransferCache: !isEpochTransition},
147
150
  RegenCaller.predictProposerHead
148
151
  );
149
- updatedHeadRoot = proposerHeadRoot;
152
+ updatedHead = proposerHead;
150
153
  }
151
154
 
152
155
  // Update the builder status, if enabled shoot an api call to check status
@@ -156,28 +159,54 @@ export class PrepareNextSlotScheduler {
156
159
  this.logger.error("Builder disabled as the check status api failed", {prepareSlot}, e as Error);
157
160
  });
158
161
  }
162
+ }
163
+
164
+ if (!isStatePostBellatrix(updatedPrepareState)) {
165
+ throw new Error("Expected Bellatrix state for payload attributes");
166
+ }
167
+
168
+ let parentBlockHash: Bytes32;
169
+ // Apply parent payload once here as it's reused by EL prep and SSE emit below
170
+ let stateAfterParentPayload: IBeaconStateViewBellatrix = updatedPrepareState;
171
+ if (isStatePostGloas(updatedPrepareState)) {
172
+ if (this.chain.forkChoice.shouldExtendPayload(updatedHead.blockRoot)) {
173
+ parentBlockHash = updatedPrepareState.latestExecutionPayloadBid.blockHash;
174
+ // Skip applying parent payload unless we're proposing the next slot or have to emit payload_attributes events
175
+ if (feeRecipient !== undefined || this.chain.opts.emitPayloadAttributes === true) {
176
+ const parentExecutionRequests = await this.chain.getParentExecutionRequests(
177
+ updatedHead.slot,
178
+ updatedHead.blockRoot
179
+ );
180
+ stateAfterParentPayload = updatedPrepareState.withParentPayloadApplied(parentExecutionRequests);
181
+ }
182
+ } else {
183
+ parentBlockHash = updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
184
+ }
185
+ } else {
186
+ parentBlockHash = updatedPrepareState.latestExecutionPayloadHeader.blockHash;
187
+ }
159
188
 
189
+ if (feeRecipient) {
160
190
  const preparationTime =
161
191
  computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
162
192
  this.metrics?.blockPayload.payloadAdvancePrepTime.observe(preparationTime);
163
- if (!isStatePostBellatrix(updatedPrepareState)) {
164
- throw new Error("Expected Bellatrix state for payload preparation");
165
- }
166
193
 
167
194
  const safeBlockHash = getSafeExecutionBlockHash(this.chain.forkChoice);
168
195
  const finalizedBlockHash =
169
196
  this.chain.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
197
+
170
198
  // awaiting here instead of throwing an async call because there is no other task
171
- // left for scheduler and this gives nice sematics to catch and log errors in the
199
+ // left for scheduler and this gives nice semantics to catch and log errors in the
172
200
  // try/catch wrapper here.
173
201
  await prepareExecutionPayload(
174
202
  this.chain,
175
203
  this.logger,
176
204
  fork as ForkPostBellatrix, // State is of execution type
177
- fromHex(updatedHeadRoot),
205
+ fromHex(updatedHead.blockRoot),
206
+ parentBlockHash,
178
207
  safeBlockHash,
179
208
  finalizedBlockHash,
180
- updatedPrepareState,
209
+ stateAfterParentPayload,
181
210
  feeRecipient
182
211
  );
183
212
  this.logger.verbose("PrepareNextSlotScheduler prepared new payload", {
@@ -187,24 +216,30 @@ export class PrepareNextSlotScheduler {
187
216
  });
188
217
  }
189
218
 
190
- if (!isStatePostBellatrix(updatedPrepareState)) {
191
- throw new Error("Expected Bellatrix state for payload attributes");
219
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
220
+ // Cutoff = slot of the parent of the block we'll actually build on (post-reorg).
221
+ // Steady state: cache holds just 2 entries — head (parent for next-slot production)
222
+ // and head.parent (proposer-boost-reorg fallback). Anything older is evicted.
223
+ const updatedHeadParent = this.chain.forkChoice.getBlockHexDefaultStatus(updatedHead.parentRoot);
224
+ if (updatedHeadParent) {
225
+ this.chain.seenPayloadEnvelopeInputCache.pruneBelowParent(updatedHeadParent);
226
+ }
192
227
  }
193
228
 
194
229
  this.computeStateHashTreeRoot(updatedPrepareState, isEpochTransition);
195
230
 
196
- // If emitPayloadAttributes is true emit a SSE payloadAttributes event
231
+ // If emitPayloadAttributes is true emit a SSE payloadAttributes event for
232
+ // every slot. Without the flag, only emit the event if we are proposing in the next slot.
197
233
  if (
198
- this.chain.opts.emitPayloadAttributes === true &&
234
+ (feeRecipient || this.chain.opts.emitPayloadAttributes === true) &&
199
235
  this.chain.emitter.listenerCount(routes.events.EventType.payloadAttributes)
200
236
  ) {
201
237
  const data = getPayloadAttributesForSSE(fork as ForkPostBellatrix, this.chain, {
202
- prepareState: updatedPrepareState,
238
+ prepareState: stateAfterParentPayload,
203
239
  prepareSlot,
204
- parentBlockRoot: fromHex(headRoot),
205
- // The likely consumers of this API are builders and will anyway ignore the
206
- // feeRecipient, so just pass zero hash for now till a real use case arises
207
- feeRecipient: "0x0000000000000000000000000000000000000000000000000000000000000000",
240
+ parentBlockRoot: fromHex(updatedHead.blockRoot),
241
+ parentBlockHash,
242
+ feeRecipient: feeRecipient ?? "0x0000000000000000000000000000000000000000",
208
243
  });
209
244
  this.chain.emitter.emit(routes.events.EventType.payloadAttributes, {data, version: fork});
210
245
  }
@@ -19,7 +19,6 @@ import {
19
19
  IBeaconStateView,
20
20
  type IBeaconStateViewBellatrix,
21
21
  computeTimeAtSlot,
22
- isParentBlockFull,
23
22
  isStatePostBellatrix,
24
23
  isStatePostCapella,
25
24
  isStatePostGloas,
@@ -47,8 +46,9 @@ import {
47
46
  electra,
48
47
  fulu,
49
48
  gloas,
49
+ ssz,
50
50
  } from "@lodestar/types";
51
- import {Logger, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
51
+ import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
52
52
  import {ZERO_HASH_HEX} from "../../constants/index.js";
53
53
  import {numToQuantity} from "../../execution/engine/utils.js";
54
54
  import {
@@ -111,6 +111,7 @@ export type ProduceFullGloas = {
111
111
  executionRequests: electra.ExecutionRequests;
112
112
  blobsBundle: BlobsBundle<ForkPostGloas>;
113
113
  cells: fulu.Cell[][];
114
+ parentBlockRoot: Root;
114
115
  };
115
116
  export type ProduceFullFulu = {
116
117
  type: BlockType.Full;
@@ -214,14 +215,28 @@ export async function produceBlockBody<T extends BlockType>(
214
215
  });
215
216
 
216
217
  // Get execution payload from EL
218
+ let parentBlockHash: Bytes32;
219
+ let parentExecutionRequests: electra.ExecutionRequests;
220
+ // Apply parent payload once here as it's reused by EL prep and voluntary exit filtering below
221
+ let stateAfterParentPayload: IBeaconStateViewBellatrix = currentState;
222
+ const isExtendingPayload = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot));
223
+ if (isExtendingPayload) {
224
+ parentBlockHash = currentState.latestExecutionPayloadBid.blockHash;
225
+ parentExecutionRequests = await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot);
226
+ stateAfterParentPayload = currentState.withParentPayloadApplied(parentExecutionRequests);
227
+ } else {
228
+ parentBlockHash = currentState.latestExecutionPayloadBid.parentBlockHash;
229
+ parentExecutionRequests = ssz.electra.ExecutionRequests.defaultValue();
230
+ }
217
231
  const prepareRes = await prepareExecutionPayload(
218
232
  this,
219
233
  this.logger,
220
234
  fork,
221
235
  parentBlockRoot,
236
+ parentBlockHash,
222
237
  safeBlockHash,
223
238
  finalizedBlockHash ?? ZERO_HASH_HEX,
224
- currentState,
239
+ stateAfterParentPayload,
225
240
  feeRecipient
226
241
  );
227
242
 
@@ -255,8 +270,8 @@ export async function produceBlockBody<T extends BlockType>(
255
270
 
256
271
  // Create self-build execution payload bid
257
272
  const bid: gloas.ExecutionPayloadBid = {
258
- parentBlockHash: currentState.latestBlockHash,
259
- parentBlockRoot: parentBlockRoot,
273
+ parentBlockHash,
274
+ parentBlockRoot,
260
275
  blockHash: executionPayload.blockHash,
261
276
  prevRandao: currentState.getRandaoMix(currentState.epoch),
262
277
  feeRecipient: executionPayload.feeRecipient,
@@ -266,6 +281,7 @@ export async function produceBlockBody<T extends BlockType>(
266
281
  value: 0,
267
282
  executionPayment: 0,
268
283
  blobKzgCommitments: blobsBundle.commitments,
284
+ executionRequestsRoot: ssz.electra.ExecutionRequests.hashTreeRoot(executionRequests),
269
285
  };
270
286
  const signedBid: gloas.SignedExecutionPayloadBid = {
271
287
  message: bid,
@@ -275,8 +291,19 @@ export async function produceBlockBody<T extends BlockType>(
275
291
  const commonBlockBody = await commonBlockBodyPromise;
276
292
  const gloasBody = Object.assign({}, commonBlockBody) as gloas.BeaconBlockBody;
277
293
  gloasBody.signedExecutionPayloadBid = signedBid;
278
- // TODO GLOAS: Get payload attestations from pool for previous slot
279
- gloasBody.payloadAttestations = [];
294
+ gloasBody.payloadAttestations = this.payloadAttestationPool.getPayloadAttestationsForBlock(
295
+ parentBlock.blockRoot,
296
+ blockSlot - 1
297
+ );
298
+ gloasBody.parentExecutionRequests = parentExecutionRequests;
299
+ // Drop voluntary exits that parent_execution_requests have invalidated (e.g. a withdrawal
300
+ // request initiating an exit on the same validator). Op pool selected against the unapplied
301
+ // state, so re-validate against the post-apply state to avoid producing an invalid block.
302
+ if (isExtendingPayload && commonBlockBody.voluntaryExits.length > 0) {
303
+ gloasBody.voluntaryExits = commonBlockBody.voluntaryExits.filter((signedVoluntaryExit) =>
304
+ stateAfterParentPayload.isValidVoluntaryExit(signedVoluntaryExit, false)
305
+ );
306
+ }
280
307
  blockBody = gloasBody as AssembledBodyType<T>;
281
308
 
282
309
  // Store execution payload data required to construct execution payload envelope later
@@ -285,6 +312,7 @@ export async function produceBlockBody<T extends BlockType>(
285
312
  gloasResult.executionRequests = executionRequests;
286
313
  gloasResult.blobsBundle = blobsBundle;
287
314
  gloasResult.cells = cells;
315
+ gloasResult.parentBlockRoot = fromHex(parentBlock.blockRoot);
288
316
 
289
317
  const fetchedTime = Date.now() / 1000 - computeTimeAtSlot(this.config, blockSlot, this.genesisTime);
290
318
  this.metrics?.blockPayload.payloadFetchedTime.observe({prepType}, fetchedTime);
@@ -334,6 +362,7 @@ export async function produceBlockBody<T extends BlockType>(
334
362
  this.logger,
335
363
  fork,
336
364
  parentBlockRoot,
365
+ currentState.latestExecutionPayloadHeader.blockHash,
337
366
  safeBlockHash,
338
367
  finalizedBlockHash ?? ZERO_HASH_HEX,
339
368
  currentState,
@@ -442,6 +471,7 @@ export async function produceBlockBody<T extends BlockType>(
442
471
  this.logger,
443
472
  fork,
444
473
  parentBlockRoot,
474
+ currentState.latestExecutionPayloadHeader.blockHash,
445
475
  safeBlockHash,
446
476
  finalizedBlockHash ?? ZERO_HASH_HEX,
447
477
  currentState,
@@ -607,17 +637,21 @@ export async function prepareExecutionPayload(
607
637
  logger: Logger,
608
638
  fork: ForkPostBellatrix,
609
639
  parentBlockRoot: Root,
640
+ parentBlockHash: Bytes32,
610
641
  safeBlockHash: RootHex,
611
642
  finalizedBlockHash: RootHex,
643
+ /**
644
+ * Post-gloas, when extending a full parent, callers must apply
645
+ * parent execution payload first (see `withParentPayloadApplied`).
646
+ */
612
647
  state: IBeaconStateViewBellatrix,
613
648
  suggestedFeeRecipient: string
614
649
  ): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
615
- const parentHash = state.latestBlockHash;
616
650
  const timestamp = computeTimeAtSlot(chain.config, state.slot, state.genesisTime);
617
651
  const prevRandao = state.getRandaoMix(state.epoch);
618
652
 
619
653
  const payloadIdCached = chain.executionEngine.payloadIdCache.get({
620
- headBlockHash: toRootHex(parentHash),
654
+ headBlockHash: toRootHex(parentBlockHash),
621
655
  finalizedBlockHash,
622
656
  timestamp: numToQuantity(timestamp),
623
657
  prevRandao: toHex(prevRandao),
@@ -646,12 +680,13 @@ export async function prepareExecutionPayload(
646
680
  prepareState: state,
647
681
  prepareSlot: state.slot,
648
682
  parentBlockRoot,
683
+ parentBlockHash,
649
684
  feeRecipient: suggestedFeeRecipient,
650
685
  });
651
686
 
652
687
  payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
653
688
  fork,
654
- toRootHex(parentHash),
689
+ toRootHex(parentBlockHash),
655
690
  safeBlockHash,
656
691
  finalizedBlockHash,
657
692
  attributes
@@ -703,20 +738,34 @@ export function getPayloadAttributesForSSE(
703
738
  prepareState,
704
739
  prepareSlot,
705
740
  parentBlockRoot,
741
+ parentBlockHash,
706
742
  feeRecipient,
707
- }: {prepareState: IBeaconStateViewBellatrix; prepareSlot: Slot; parentBlockRoot: Root; feeRecipient: string}
743
+ }: {
744
+ /**
745
+ * Post-gloas, when extending a full parent, callers must apply
746
+ * parent execution payload first (see `withParentPayloadApplied`).
747
+ */
748
+ prepareState: IBeaconStateViewBellatrix;
749
+ prepareSlot: Slot;
750
+ parentBlockRoot: Root;
751
+ parentBlockHash: Bytes32;
752
+ feeRecipient: string;
753
+ }
708
754
  ): SSEPayloadAttributes {
709
- const parentHash = prepareState.latestBlockHash;
710
755
  const payloadAttributes = preparePayloadAttributes(fork, chain, {
711
756
  prepareState,
712
757
  prepareSlot,
713
758
  parentBlockRoot,
759
+ parentBlockHash,
714
760
  feeRecipient,
715
761
  });
716
762
 
717
763
  let parentBlockNumber: number;
718
764
  if (isForkPostGloas(fork)) {
719
- const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(toRootHex(parentBlockRoot), toRootHex(parentHash));
765
+ const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
766
+ toRootHex(parentBlockRoot),
767
+ toRootHex(parentBlockHash)
768
+ );
720
769
  if (parentBlock?.executionPayloadBlockHash == null) {
721
770
  throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
722
771
  }
@@ -730,7 +779,7 @@ export function getPayloadAttributesForSSE(
730
779
  proposalSlot: prepareSlot,
731
780
  parentBlockNumber,
732
781
  parentBlockRoot,
733
- parentBlockHash: parentHash,
782
+ parentBlockHash,
734
783
  payloadAttributes,
735
784
  };
736
785
  return ssePayloadAttributes;
@@ -745,11 +794,17 @@ function preparePayloadAttributes(
745
794
  prepareState,
746
795
  prepareSlot,
747
796
  parentBlockRoot,
797
+ parentBlockHash,
748
798
  feeRecipient,
749
799
  }: {
800
+ /**
801
+ * Post-gloas, when extending a full parent, callers must apply
802
+ * parent execution payload first (see `withParentPayloadApplied`).
803
+ */
750
804
  prepareState: IBeaconStateViewBellatrix;
751
805
  prepareSlot: Slot;
752
806
  parentBlockRoot: Root;
807
+ parentBlockHash: Bytes32;
753
808
  feeRecipient: string;
754
809
  }
755
810
  ): SSEPayloadAttributes["payloadAttributes"] {
@@ -766,13 +821,24 @@ function preparePayloadAttributes(
766
821
  throw new Error("Expected Capella state for withdrawals");
767
822
  }
768
823
 
769
- if (isStatePostGloas(prepareState) && !isParentBlockFull(prepareState)) {
770
- // When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
771
- // already deducted from CL balances but never credited on the EL (the envelope
772
- // was not delivered). The next payload must carry those same withdrawals to
773
- // restore CL/EL consistency, otherwise validators permanently lose that balance.
774
- (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
775
- prepareState.payloadExpectedWithdrawals;
824
+ if (isStatePostGloas(prepareState)) {
825
+ const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
826
+ if (isExtendingPayload) {
827
+ // applyParentExecutionPayload sets latestBlockHash = parentBid.blockHash, so a mismatch
828
+ // here means the caller did not apply parent payload to prepareState
829
+ if (!byteArrayEquals(prepareState.latestBlockHash, prepareState.latestExecutionPayloadBid.blockHash)) {
830
+ throw new Error("Expected state with parent execution payload applied for withdrawals");
831
+ }
832
+ (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
833
+ prepareState.getExpectedWithdrawals().expectedWithdrawals;
834
+ } else {
835
+ // When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
836
+ // already deducted from CL balances but never credited on the EL (the envelope
837
+ // was not delivered). The next payload must carry those same withdrawals to
838
+ // restore CL/EL consistency, otherwise validators permanently lose that balance.
839
+ (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
840
+ prepareState.payloadExpectedWithdrawals;
841
+ }
776
842
  } else {
777
843
  // withdrawals logic is now fork aware as it changes on electra fork post capella
778
844
  (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
@@ -784,6 +850,10 @@ function preparePayloadAttributes(
784
850
  (payloadAttributes as deneb.SSEPayloadAttributes["payloadAttributes"]).parentBeaconBlockRoot = parentBlockRoot;
785
851
  }
786
852
 
853
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
854
+ (payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
855
+ }
856
+
787
857
  return payloadAttributes;
788
858
  }
789
859
 
@@ -21,6 +21,7 @@ export enum RegenCaller {
21
21
  validateGossipAttestation = "validateGossipAttestation",
22
22
  validateGossipVoluntaryExit = "validateGossipVoluntaryExit",
23
23
  validateGossipExecutionPayloadBid = "validateGossipExecutionPayloadBid",
24
+ validateGossipProposerPreferences = "validateGossipProposerPreferences",
24
25
  onForkChoiceFinalized = "onForkChoiceFinalized",
25
26
  restApi = "restApi",
26
27
  }
@@ -1,7 +1,7 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
3
3
  import {IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
4
- import {BeaconBlock, Epoch, RootHex, Slot, isGloasBeaconBlock, phase0} from "@lodestar/types";
4
+ import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
5
5
  import {Logger, toRootHex} from "@lodestar/utils";
6
6
  import {Metrics} from "../../metrics/index.js";
7
7
  import {JobItemQueue} from "../../util/queue/index.js";
@@ -88,12 +88,7 @@ export class QueuedStateRegenerator implements IStateRegenerator {
88
88
  */
89
89
  getPreStateSync(block: BeaconBlock): IBeaconStateView | null {
90
90
  const parentRoot = toRootHex(block.parentRoot);
91
- const parentBlock = isGloasBeaconBlock(block)
92
- ? this.forkChoice.getBlockHexAndBlockHash(
93
- parentRoot,
94
- toRootHex(block.body.signedExecutionPayloadBid.message.parentBlockHash)
95
- )
96
- : this.forkChoice.getBlockHexDefaultStatus(parentRoot);
91
+ const parentBlock = this.forkChoice.getBlockHexDefaultStatus(parentRoot);
97
92
  if (!parentBlock) {
98
93
  throw new RegenError({
99
94
  code: RegenErrorCode.BLOCK_NOT_IN_FORKCHOICE,
@@ -9,7 +9,7 @@ import {
9
9
  computeEpochAtSlot,
10
10
  computeStartSlotAtEpoch,
11
11
  } from "@lodestar/state-transition";
12
- import {BeaconBlock, RootHex, SignedBeaconBlock, Slot, isGloasBeaconBlock} from "@lodestar/types";
12
+ import {BeaconBlock, RootHex, SignedBeaconBlock, Slot} from "@lodestar/types";
13
13
  import {Logger, fromHex, toRootHex} from "@lodestar/utils";
14
14
  import {IBeaconDb} from "../../db/index.js";
15
15
  import {Metrics} from "../../metrics/index.js";
@@ -57,12 +57,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
57
57
  regenCaller: RegenCaller
58
58
  ): Promise<IBeaconStateView> {
59
59
  const parentRoot = toRootHex(block.parentRoot);
60
- const parentBlock = isGloasBeaconBlock(block)
61
- ? this.modules.forkChoice.getBlockHexAndBlockHash(
62
- parentRoot,
63
- toRootHex(block.body.signedExecutionPayloadBid.message.parentBlockHash)
64
- )
65
- : this.modules.forkChoice.getBlockHexDefaultStatus(parentRoot);
60
+ const parentBlock = this.modules.forkChoice.getBlockHexDefaultStatus(parentRoot);
66
61
  if (!parentBlock) {
67
62
  throw new RegenError({
68
63
  code: RegenErrorCode.BLOCK_NOT_IN_FORKCHOICE,
@@ -5,3 +5,4 @@ export {SeenContributionAndProof} from "./seenCommitteeContribution.js";
5
5
  export {SeenExecutionPayloadBids} from "./seenExecutionPayloadBids.js";
6
6
  export {SeenBlockInput} from "./seenGossipBlockInput.js";
7
7
  export {PayloadEnvelopeInput, SeenPayloadEnvelopeInput} from "./seenPayloadEnvelopeInput.js";
8
+ export {SeenProposerPreferences} from "./seenProposerPreferences.js";
@@ -1,9 +1,12 @@
1
- import {CheckpointWithHex} from "@lodestar/fork-choice";
1
+ import {ChainForkConfig} from "@lodestar/config";
2
+ import {CheckpointWithHex, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
2
3
  import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
3
4
  import {RootHex} from "@lodestar/types";
4
5
  import {Logger} from "@lodestar/utils";
5
6
  import {Metrics} from "../../metrics/metrics.js";
7
+ import {IClock} from "../../util/clock.js";
6
8
  import {SerializedCache} from "../../util/serializedCache.js";
9
+ import {isDaOutOfRange} from "../blocks/blockInput/index.js";
7
10
  import {CreateFromBlockProps, PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
8
11
  import {ChainEvent, ChainEventEmitter} from "../emitter.js";
9
12
 
@@ -11,6 +14,9 @@ export type {PayloadEnvelopeInputState} from "../blocks/payloadEnvelopeInput/ind
11
14
  export {PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
12
15
 
13
16
  export type SeenPayloadEnvelopeInputModules = {
17
+ config: ChainForkConfig;
18
+ clock: IClock;
19
+ forkChoice: IForkChoice;
14
20
  chainEvents: ChainEventEmitter;
15
21
  signal: AbortSignal;
16
22
  serializedCache: SerializedCache;
@@ -21,10 +27,20 @@ export type SeenPayloadEnvelopeInputModules = {
21
27
  /**
22
28
  * Cache for tracking PayloadEnvelopeInput instances, keyed by beacon block root.
23
29
  *
24
- * Created during block import when a block is processed.
25
- * Pruned on finalization and after payload is written to DB.
30
+ * Created during block import when a block is processed. Two pruning paths:
31
+ * - `prepareNextSlot` calls `pruneBelow(headParentSlot)` every slot once the head we'll build
32
+ * on is known.
33
+ * - `onFinalized` calls `pruneBelow(finalizedSlot)` on every finalization for bulk cleanup.
34
+ *
35
+ * Steady state (linear chain, healthy progression): the cache holds ~2 entries — the head
36
+ * (parent for next-slot production) and its parent (proposer-boost-reorg fallback). It can
37
+ * transiently hold more during forks, range-sync bursts, or when `prepareNextSlot` skips
38
+ * ticks; subsequent ticks settle it back.
26
39
  */
27
40
  export class SeenPayloadEnvelopeInput {
41
+ private readonly config: ChainForkConfig;
42
+ private readonly clock: IClock;
43
+ private readonly forkChoice: IForkChoice;
28
44
  private readonly chainEvents: ChainEventEmitter;
29
45
  private readonly signal: AbortSignal;
30
46
  private readonly serializedCache: SerializedCache;
@@ -32,7 +48,19 @@ export class SeenPayloadEnvelopeInput {
32
48
  private readonly logger?: Logger;
33
49
  private payloadInputs = new Map<RootHex, PayloadEnvelopeInput>();
34
50
 
35
- constructor({chainEvents, signal, serializedCache, metrics, logger}: SeenPayloadEnvelopeInputModules) {
51
+ constructor({
52
+ config,
53
+ clock,
54
+ forkChoice,
55
+ chainEvents,
56
+ signal,
57
+ serializedCache,
58
+ metrics,
59
+ logger,
60
+ }: SeenPayloadEnvelopeInputModules) {
61
+ this.config = config;
62
+ this.clock = clock;
63
+ this.forkChoice = forkChoice;
36
64
  this.chainEvents = chainEvents;
37
65
  this.signal = signal;
38
66
  this.serializedCache = serializedCache;
@@ -51,14 +79,13 @@ export class SeenPayloadEnvelopeInput {
51
79
  });
52
80
  }
53
81
 
54
- this.chainEvents.on(ChainEvent.forkChoiceFinalized, this.onFinalized);
82
+ this.chainEvents.on(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
55
83
  this.signal.addEventListener("abort", () => {
56
- this.chainEvents.off(ChainEvent.forkChoiceFinalized, this.onFinalized);
84
+ this.chainEvents.off(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
57
85
  });
58
86
  }
59
87
 
60
- private onFinalized = (checkpoint: CheckpointWithHex): void => {
61
- // Prune all entries with slot < finalized slot
88
+ private pruneFinalized = (checkpoint: CheckpointWithHex): void => {
62
89
  const finalizedSlot = computeStartSlotAtEpoch(checkpoint.epoch);
63
90
  let deletedCount = 0;
64
91
  for (const [, input] of this.payloadInputs) {
@@ -67,16 +94,32 @@ export class SeenPayloadEnvelopeInput {
67
94
  deletedCount++;
68
95
  }
69
96
  }
70
- this.logger?.debug("SeenPayloadEnvelopeInput.onFinalized deleted cached entries", {deletedCount});
97
+
98
+ this.logger?.debug("SeenPayloadEnvelopeInput.pruneFinalized deleted entries", {
99
+ finalizedSlot,
100
+ finalizedRoot: checkpoint.rootHex,
101
+ deletedCount,
102
+ });
71
103
  };
72
104
 
73
- add(props: CreateFromBlockProps): PayloadEnvelopeInput {
74
- if (this.payloadInputs.has(props.blockRootHex)) {
75
- throw new Error(`PayloadEnvelopeInput already exists for block ${props.blockRootHex}`);
105
+ add(props: Omit<CreateFromBlockProps, "daOutOfRange">): PayloadEnvelopeInput {
106
+ const existing = this.payloadInputs.get(props.blockRootHex);
107
+ if (existing !== undefined) {
108
+ this.logger?.verbose("SeenPayloadEnvelopeInput.add reused existing entry", {
109
+ slot: existing.slot,
110
+ root: props.blockRootHex,
111
+ });
112
+ return existing;
76
113
  }
77
- const input = PayloadEnvelopeInput.createFromBlock(props);
114
+ const daOutOfRange = isDaOutOfRange(this.config, props.forkName, props.block.message.slot, this.clock.currentEpoch);
115
+ const input = PayloadEnvelopeInput.createFromBlock({...props, daOutOfRange});
78
116
  this.payloadInputs.set(props.blockRootHex, input);
79
117
  this.metrics?.seenCache.payloadEnvelopeInput.created.inc();
118
+ this.logger?.verbose("SeenPayloadEnvelopeInput.add created new entry", {
119
+ slot: input.slot,
120
+ root: props.blockRootHex,
121
+ daOutOfRange,
122
+ });
80
123
  return input;
81
124
  }
82
125
 
@@ -88,17 +131,25 @@ export class SeenPayloadEnvelopeInput {
88
131
  return this.payloadInputs.get(blockRootHex)?.hasPayloadEnvelope() ?? false;
89
132
  }
90
133
 
91
- prune(blockRootHex: RootHex): void {
92
- const payloadInput = this.payloadInputs.get(blockRootHex);
93
- if (payloadInput) {
94
- this.evictPayloadInput(payloadInput);
95
- }
96
- }
97
-
98
134
  size(): number {
99
135
  return this.payloadInputs.size;
100
136
  }
101
137
 
138
+ pruneBelowParent(parentBlock: ProtoBlock): void {
139
+ for (const block of this.forkChoice.getAllAncestorBlocks(parentBlock.blockRoot, parentBlock.payloadStatus)) {
140
+ if (block.slot < parentBlock.slot) {
141
+ const input = this.payloadInputs.get(block.blockRoot);
142
+ if (input) {
143
+ this.evictPayloadInput(input);
144
+ this.logger?.verbose("SeenPayloadEnvelopeInput.pruneBelowParent deleted", {
145
+ slot: block.slot,
146
+ root: block.blockRoot,
147
+ });
148
+ }
149
+ }
150
+ }
151
+ }
152
+
102
153
  private evictPayloadInput(payloadInput: PayloadEnvelopeInput): void {
103
154
  this.serializedCache.delete(payloadInput.getSerializedCacheKeys());
104
155
  this.payloadInputs.delete(payloadInput.blockRootHex);
@@ -0,0 +1,32 @@
1
+ import {RootHex, Slot, ValidatorIndex} from "@lodestar/types";
2
+ import {MapDef} from "@lodestar/utils";
3
+
4
+ /**
5
+ * Tracks signed proposer preferences we've already seen per (dependent_root, proposal_slot, validator_index).
6
+ */
7
+ export class SeenProposerPreferences {
8
+ private readonly validatorByDependentRootBySlot = new MapDef<Slot, Map<RootHex, ValidatorIndex>>(
9
+ () => new Map<RootHex, ValidatorIndex>()
10
+ );
11
+
12
+ isKnown(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): boolean {
13
+ return this.validatorByDependentRootBySlot.get(proposalSlot)?.get(dependentRoot) === validatorIndex;
14
+ }
15
+
16
+ add(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): void {
17
+ this.validatorByDependentRootBySlot.getOrDefault(proposalSlot).set(dependentRoot, validatorIndex);
18
+ }
19
+
20
+ /**
21
+ * Entries are only load-bearing while `proposal_slot > current_slot`. Once the slot has
22
+ * passed the `[IGNORE] proposal_slot > current_slot` gossip rule takes over, so drop them
23
+ * on each slot tick.
24
+ */
25
+ prune(currentSlot: Slot): void {
26
+ for (const slot of this.validatorByDependentRootBySlot.keys()) {
27
+ if (slot < currentSlot) {
28
+ this.validatorByDependentRootBySlot.delete(slot);
29
+ }
30
+ }
31
+ }
32
+ }
@@ -226,7 +226,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
226
226
  }
227
227
  sszTimer?.();
228
228
  const timer = this.metrics?.cpStateCache.stateReloadDuration.startTimer();
229
- const newCachedState = seedState.loadOtherState(stateBytes, validatorsBytes);
229
+ // preload validators and balances for faster state transition
230
+ const newCachedState = seedState.loadOtherState(stateBytes, validatorsBytes, {
231
+ preloadValidatorsAndBalances: true,
232
+ });
230
233
  // hashTreeRoot() calls the commit() inside
231
234
  // there is no modification inside the state, it's just that we want to compute and cache all roots
232
235
  const stateRoot = toRootHex(newCachedState.hashTreeRoot());