@lodestar/beacon-node 1.43.0-dev.e5b13221e5 → 1.43.0-dev.ff409c46ce

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 (317) 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 +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 -2
  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 -81
  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 +5 -17
  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 +31 -13
  124. package/lib/chain/prepareNextSlot.js.map +1 -1
  125. package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -1
  126. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  127. package/lib/chain/produceBlock/produceBlockBody.js +47 -14
  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/validation/block.d.ts.map +1 -1
  152. package/lib/chain/validation/block.js +1 -0
  153. package/lib/chain/validation/block.js.map +1 -1
  154. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  155. package/lib/chain/validation/executionPayloadBid.js +24 -9
  156. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  157. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  158. package/lib/chain/validation/executionPayloadEnvelope.js +11 -1
  159. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  160. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  161. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  162. package/lib/chain/validation/proposerPreferences.js +91 -0
  163. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  164. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  165. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  166. package/lib/metrics/metrics/lodestar.js +4 -0
  167. package/lib/metrics/metrics/lodestar.js.map +1 -1
  168. package/lib/network/gossip/interface.d.ts +7 -1
  169. package/lib/network/gossip/interface.d.ts.map +1 -1
  170. package/lib/network/gossip/interface.js +1 -0
  171. package/lib/network/gossip/interface.js.map +1 -1
  172. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  173. package/lib/network/gossip/scoringParameters.js +12 -1
  174. package/lib/network/gossip/scoringParameters.js.map +1 -1
  175. package/lib/network/gossip/topic.d.ts +29 -766
  176. package/lib/network/gossip/topic.d.ts.map +1 -1
  177. package/lib/network/gossip/topic.js +6 -0
  178. package/lib/network/gossip/topic.js.map +1 -1
  179. package/lib/network/interface.d.ts +1 -0
  180. package/lib/network/interface.d.ts.map +1 -1
  181. package/lib/network/network.d.ts +1 -0
  182. package/lib/network/network.d.ts.map +1 -1
  183. package/lib/network/network.js +5 -0
  184. package/lib/network/network.js.map +1 -1
  185. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  186. package/lib/network/processor/gossipHandlers.js +38 -16
  187. package/lib/network/processor/gossipHandlers.js.map +1 -1
  188. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  189. package/lib/network/processor/gossipQueues/index.js +5 -0
  190. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  191. package/lib/network/processor/index.d.ts.map +1 -1
  192. package/lib/network/processor/index.js +6 -5
  193. package/lib/network/processor/index.js.map +1 -1
  194. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  195. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  196. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  197. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  198. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  199. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  200. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  201. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  202. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  203. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  204. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  205. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  206. package/lib/node/nodejs.js +2 -2
  207. package/lib/node/nodejs.js.map +1 -1
  208. package/lib/sync/constants.d.ts +3 -1
  209. package/lib/sync/constants.d.ts.map +1 -1
  210. package/lib/sync/constants.js +3 -4
  211. package/lib/sync/constants.js.map +1 -1
  212. package/lib/sync/range/batch.d.ts +28 -2
  213. package/lib/sync/range/batch.d.ts.map +1 -1
  214. package/lib/sync/range/batch.js +146 -44
  215. package/lib/sync/range/batch.js.map +1 -1
  216. package/lib/sync/range/chain.d.ts +12 -2
  217. package/lib/sync/range/chain.d.ts.map +1 -1
  218. package/lib/sync/range/chain.js +53 -9
  219. package/lib/sync/range/chain.js.map +1 -1
  220. package/lib/sync/range/range.d.ts.map +1 -1
  221. package/lib/sync/range/range.js +17 -6
  222. package/lib/sync/range/range.js.map +1 -1
  223. package/lib/sync/types.d.ts +34 -0
  224. package/lib/sync/types.d.ts.map +1 -1
  225. package/lib/sync/types.js +34 -0
  226. package/lib/sync/types.js.map +1 -1
  227. package/lib/sync/unknownBlock.d.ts +29 -1
  228. package/lib/sync/unknownBlock.d.ts.map +1 -1
  229. package/lib/sync/unknownBlock.js +738 -61
  230. package/lib/sync/unknownBlock.js.map +1 -1
  231. package/lib/sync/utils/downloadByRange.d.ts +46 -10
  232. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  233. package/lib/sync/utils/downloadByRange.js +162 -24
  234. package/lib/sync/utils/downloadByRange.js.map +1 -1
  235. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  236. package/lib/sync/utils/downloadByRoot.js +16 -2
  237. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  238. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  239. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  240. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  241. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  242. package/lib/util/sszBytes.d.ts.map +1 -1
  243. package/lib/util/sszBytes.js +8 -6
  244. package/lib/util/sszBytes.js.map +1 -1
  245. package/package.json +16 -15
  246. package/src/api/impl/beacon/blocks/index.ts +21 -5
  247. package/src/api/impl/beacon/pool/index.ts +83 -1
  248. package/src/api/impl/beacon/state/utils.ts +2 -2
  249. package/src/api/impl/debug/index.ts +0 -1
  250. package/src/api/impl/lodestar/index.ts +1 -1
  251. package/src/api/impl/validator/index.ts +82 -1
  252. package/src/chain/archiveStore/archiveStore.ts +5 -5
  253. package/src/chain/archiveStore/interface.ts +4 -4
  254. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +4 -4
  255. package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
  256. package/src/chain/blocks/blockInput/blockInput.ts +4 -1
  257. package/src/chain/blocks/importBlock.ts +16 -48
  258. package/src/chain/blocks/importExecutionPayload.ts +109 -95
  259. package/src/chain/blocks/index.ts +73 -23
  260. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +10 -2
  261. package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -0
  262. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  263. package/src/chain/blocks/types.ts +15 -25
  264. package/src/chain/blocks/utils/chainSegment.ts +114 -17
  265. package/src/chain/blocks/verifyBlock.ts +70 -9
  266. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  267. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  268. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +134 -0
  269. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  270. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  271. package/src/chain/chain.ts +48 -26
  272. package/src/chain/emitter.ts +3 -14
  273. package/src/chain/errors/blockError.ts +4 -1
  274. package/src/chain/errors/executionPayloadBid.ts +6 -0
  275. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  276. package/src/chain/errors/index.ts +1 -0
  277. package/src/chain/errors/proposerPreferences.ts +47 -0
  278. package/src/chain/forkChoice/index.ts +2 -22
  279. package/src/chain/initState.ts +9 -1
  280. package/src/chain/interface.ts +11 -3
  281. package/src/chain/opPools/payloadAttestationPool.ts +29 -8
  282. package/src/chain/prepareNextSlot.ts +36 -14
  283. package/src/chain/produceBlock/produceBlockBody.ts +57 -13
  284. package/src/chain/regen/interface.ts +1 -0
  285. package/src/chain/regen/queued.ts +2 -7
  286. package/src/chain/regen/regen.ts +2 -7
  287. package/src/chain/seenCache/index.ts +1 -0
  288. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +71 -20
  289. package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
  290. package/src/chain/validation/block.ts +1 -0
  291. package/src/chain/validation/executionPayloadBid.ts +25 -8
  292. package/src/chain/validation/executionPayloadEnvelope.ts +12 -2
  293. package/src/chain/validation/proposerPreferences.ts +110 -0
  294. package/src/metrics/metrics/lodestar.ts +4 -0
  295. package/src/network/gossip/interface.ts +6 -0
  296. package/src/network/gossip/scoringParameters.ts +14 -1
  297. package/src/network/gossip/topic.ts +6 -0
  298. package/src/network/interface.ts +1 -0
  299. package/src/network/network.ts +11 -0
  300. package/src/network/processor/gossipHandlers.ts +53 -17
  301. package/src/network/processor/gossipQueues/index.ts +5 -0
  302. package/src/network/processor/index.ts +6 -5
  303. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  304. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  305. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  306. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  307. package/src/node/nodejs.ts +2 -2
  308. package/src/sync/constants.ts +4 -4
  309. package/src/sync/range/batch.ts +204 -49
  310. package/src/sync/range/chain.ts +69 -11
  311. package/src/sync/range/range.ts +18 -6
  312. package/src/sync/types.ts +72 -0
  313. package/src/sync/unknownBlock.ts +928 -65
  314. package/src/sync/utils/downloadByRange.ts +272 -39
  315. package/src/sync/utils/downloadByRoot.ts +24 -2
  316. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  317. package/src/util/sszBytes.ts +8 -6
@@ -4,6 +4,7 @@ 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,
@@ -83,7 +84,7 @@ export class PrepareNextSlotScheduler {
83
84
  const headBlock = this.chain.recomputeForkChoiceHead(ForkchoiceCaller.prepareNextSlot);
84
85
  const {slot: headSlot, blockRoot: headRoot} = headBlock;
85
86
  // may be updated below if we predict a proposer-boost-reorg
86
- let updatedHeadRoot = headRoot;
87
+ let updatedHead = headBlock;
87
88
 
88
89
  // PS: previously this was comparing slots, but that gave no leway on the skipped
89
90
  // slots on epoch bounday. Making it more fluid.
@@ -148,7 +149,7 @@ export class PrepareNextSlotScheduler {
148
149
  {dontTransferCache: !isEpochTransition},
149
150
  RegenCaller.predictProposerHead
150
151
  );
151
- updatedHeadRoot = proposerHeadRoot;
152
+ updatedHead = proposerHead;
152
153
  }
153
154
 
154
155
  // Update the builder status, if enabled shoot an api call to check status
@@ -165,10 +166,22 @@ export class PrepareNextSlotScheduler {
165
166
  }
166
167
 
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;
168
171
  if (isStatePostGloas(updatedPrepareState)) {
169
- parentBlockHash = this.chain.forkChoice.shouldExtendPayload(updatedHeadRoot)
170
- ? updatedPrepareState.latestExecutionPayloadBid.blockHash
171
- : updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
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
+ }
172
185
  } else {
173
186
  parentBlockHash = updatedPrepareState.latestExecutionPayloadHeader.blockHash;
174
187
  }
@@ -189,11 +202,11 @@ export class PrepareNextSlotScheduler {
189
202
  this.chain,
190
203
  this.logger,
191
204
  fork as ForkPostBellatrix, // State is of execution type
192
- fromHex(updatedHeadRoot),
205
+ fromHex(updatedHead.blockRoot),
193
206
  parentBlockHash,
194
207
  safeBlockHash,
195
208
  finalizedBlockHash,
196
- updatedPrepareState,
209
+ stateAfterParentPayload,
197
210
  feeRecipient
198
211
  );
199
212
  this.logger.verbose("PrepareNextSlotScheduler prepared new payload", {
@@ -203,21 +216,30 @@ export class PrepareNextSlotScheduler {
203
216
  });
204
217
  }
205
218
 
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
+ }
227
+ }
228
+
206
229
  this.computeStateHashTreeRoot(updatedPrepareState, isEpochTransition);
207
230
 
208
- // 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.
209
233
  if (
210
- this.chain.opts.emitPayloadAttributes === true &&
234
+ (feeRecipient || this.chain.opts.emitPayloadAttributes === true) &&
211
235
  this.chain.emitter.listenerCount(routes.events.EventType.payloadAttributes)
212
236
  ) {
213
237
  const data = getPayloadAttributesForSSE(fork as ForkPostBellatrix, this.chain, {
214
- prepareState: updatedPrepareState,
238
+ prepareState: stateAfterParentPayload,
215
239
  prepareSlot,
216
- parentBlockRoot: fromHex(headRoot),
240
+ parentBlockRoot: fromHex(updatedHead.blockRoot),
217
241
  parentBlockHash,
218
- // The likely consumers of this API are builders and will anyway ignore the
219
- // feeRecipient, so just pass zero hash for now till a real use case arises
220
- feeRecipient: "0x0000000000000000000000000000000000000000000000000000000000000000",
242
+ feeRecipient: feeRecipient ?? "0x0000000000000000000000000000000000000000",
221
243
  });
222
244
  this.chain.emitter.emit(routes.events.EventType.payloadAttributes, {data, version: fork});
223
245
  }
@@ -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,9 +215,19 @@ export async function produceBlockBody<T extends BlockType>(
214
215
  });
215
216
 
216
217
  // Get execution payload from EL
217
- const parentBlockHash = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot))
218
- ? currentState.latestExecutionPayloadBid.blockHash
219
- : currentState.latestExecutionPayloadBid.parentBlockHash;
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
+ }
220
231
  const prepareRes = await prepareExecutionPayload(
221
232
  this,
222
233
  this.logger,
@@ -225,7 +236,7 @@ export async function produceBlockBody<T extends BlockType>(
225
236
  parentBlockHash,
226
237
  safeBlockHash,
227
238
  finalizedBlockHash ?? ZERO_HASH_HEX,
228
- currentState,
239
+ stateAfterParentPayload,
229
240
  feeRecipient
230
241
  );
231
242
 
@@ -280,8 +291,19 @@ export async function produceBlockBody<T extends BlockType>(
280
291
  const commonBlockBody = await commonBlockBodyPromise;
281
292
  const gloasBody = Object.assign({}, commonBlockBody) as gloas.BeaconBlockBody;
282
293
  gloasBody.signedExecutionPayloadBid = signedBid;
283
- // TODO GLOAS: Get payload attestations from pool for previous slot
284
- 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
+ }
285
307
  blockBody = gloasBody as AssembledBodyType<T>;
286
308
 
287
309
  // Store execution payload data required to construct execution payload envelope later
@@ -290,6 +312,7 @@ export async function produceBlockBody<T extends BlockType>(
290
312
  gloasResult.executionRequests = executionRequests;
291
313
  gloasResult.blobsBundle = blobsBundle;
292
314
  gloasResult.cells = cells;
315
+ gloasResult.parentBlockRoot = fromHex(parentBlock.blockRoot);
293
316
 
294
317
  const fetchedTime = Date.now() / 1000 - computeTimeAtSlot(this.config, blockSlot, this.genesisTime);
295
318
  this.metrics?.blockPayload.payloadFetchedTime.observe({prepType}, fetchedTime);
@@ -617,6 +640,10 @@ export async function prepareExecutionPayload(
617
640
  parentBlockHash: Bytes32,
618
641
  safeBlockHash: RootHex,
619
642
  finalizedBlockHash: RootHex,
643
+ /**
644
+ * Post-gloas, when extending a full parent, callers must apply
645
+ * parent execution payload first (see `withParentPayloadApplied`).
646
+ */
620
647
  state: IBeaconStateViewBellatrix,
621
648
  suggestedFeeRecipient: string
622
649
  ): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
@@ -714,6 +741,10 @@ export function getPayloadAttributesForSSE(
714
741
  parentBlockHash,
715
742
  feeRecipient,
716
743
  }: {
744
+ /**
745
+ * Post-gloas, when extending a full parent, callers must apply
746
+ * parent execution payload first (see `withParentPayloadApplied`).
747
+ */
717
748
  prepareState: IBeaconStateViewBellatrix;
718
749
  prepareSlot: Slot;
719
750
  parentBlockRoot: Root;
@@ -766,6 +797,10 @@ function preparePayloadAttributes(
766
797
  parentBlockHash,
767
798
  feeRecipient,
768
799
  }: {
800
+ /**
801
+ * Post-gloas, when extending a full parent, callers must apply
802
+ * parent execution payload first (see `withParentPayloadApplied`).
803
+ */
769
804
  prepareState: IBeaconStateViewBellatrix;
770
805
  prepareSlot: Slot;
771
806
  parentBlockRoot: Root;
@@ -788,13 +823,22 @@ function preparePayloadAttributes(
788
823
 
789
824
  if (isStatePostGloas(prepareState)) {
790
825
  const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
791
- // When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
792
- // already deducted from CL balances but never credited on the EL (the envelope
793
- // was not delivered). The next payload must carry those same withdrawals to
794
- // restore CL/EL consistency, otherwise validators permanently lose that balance.
795
- (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals = isExtendingPayload
796
- ? prepareState.getExpectedWithdrawals().expectedWithdrawals
797
- : prepareState.payloadExpectedWithdrawals;
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
+ }
798
842
  } else {
799
843
  // withdrawals logic is now fork aware as it changes on electra fork post capella
800
844
  (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
@@ -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
+ }
@@ -103,6 +103,7 @@ export async function validateGossipBlock(
103
103
  if (chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHashHex) === null) {
104
104
  throw new BlockGossipError(GossipAction.IGNORE, {
105
105
  code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN,
106
+ parentRoot,
106
107
  parentBlockHash: parentBlockHashHex,
107
108
  });
108
109
  }
@@ -1,5 +1,6 @@
1
1
  import {PublicKey} from "@chainsafe/blst";
2
2
  import {
3
+ computeEpochAtSlot,
3
4
  createSingleSignatureSetFromComponents,
4
5
  getExecutionPayloadBidSigningRoot,
5
6
  isActiveBuilder,
@@ -47,9 +48,12 @@ async function validateExecutionPayloadBid(
47
48
  });
48
49
  }
49
50
 
50
- // [IGNORE] the `SignedProposerPreferences` where `preferences.proposal_slot`
51
- // is equal to `bid.slot` has been seen.
52
- // TODO GLOAS: Implement this along with proposer preference
51
+ // [IGNORE] A `SignedProposerPreferences` matching `bid.slot` and the bid's branch has been
52
+ // seen i.e. `proposal_slot == bid.slot` AND `dependent_root ==
53
+ // get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))`,
54
+ // where `parent_state` is the post-state of `bid.parent_block_root`.
55
+ // This is the message referenced as `proposer_preferences` in the following REJECT rules.
56
+ // TODO GLOAS: Implement once a ProposerPreferencesPool exists.
53
57
 
54
58
  // [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
55
59
  // `is_active_builder(state, bid.builder_index)` returns `True`.
@@ -70,11 +74,24 @@ async function validateExecutionPayloadBid(
70
74
  });
71
75
  }
72
76
 
73
- // [REJECT] `bid.fee_recipient` matches the `fee_recipient` from the proposer's
74
- // `SignedProposerPreferences` associated with `bid.slot`.
75
- // [REJECT] `bid.gas_limit` matches the `gas_limit` from the proposer's
76
- // `SignedProposerPreferences` associated with `bid.slot`.
77
- // TODO GLOAS: Implement this along with proposer preference
77
+ // [REJECT] `bid.fee_recipient == proposer_preferences.fee_recipient`.
78
+ // [REJECT] `bid.gas_limit == proposer_preferences.gas_limit`.
79
+ // Both compared against the matching `proposer_preferences` defined above (same branch
80
+ // via dependent_root, same proposal_slot).
81
+ // TODO GLOAS: Implement once a ProposerPreferencesPool exists.
82
+
83
+ // [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
84
+ // consensus layer -- i.e. validate that
85
+ // `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
86
+ const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
87
+ const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
88
+ if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
89
+ throw new ExecutionPayloadBidError(GossipAction.REJECT, {
90
+ code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
91
+ blobKzgCommitmentsLen,
92
+ commitmentLimit: maxBlobsPerBlock,
93
+ });
94
+ }
78
95
 
79
96
  // [IGNORE] this is the first signed bid seen with a valid signature from the given builder for this slot.
80
97
  if (chain.seenExecutionPayloadBids.isKnown(bid.slot, bid.builderIndex)) {
@@ -4,8 +4,8 @@ import {
4
4
  getExecutionPayloadEnvelopeSignatureSet,
5
5
  isStatePostGloas,
6
6
  } from "@lodestar/state-transition";
7
- import {gloas} from "@lodestar/types";
8
- import {toRootHex} from "@lodestar/utils";
7
+ import {gloas, ssz} from "@lodestar/types";
8
+ import {byteArrayEquals, toRootHex} from "@lodestar/utils";
9
9
  import {ExecutionPayloadEnvelopeError, ExecutionPayloadEnvelopeErrorCode, GossipAction} from "../errors/index.js";
10
10
  import {IBeaconChain} from "../index.js";
11
11
  import {RegenCaller} from "../regen/index.js";
@@ -107,6 +107,16 @@ async function validateExecutionPayloadEnvelope(
107
107
  });
108
108
  }
109
109
 
110
+ // [REJECT] `hash_tree_root(envelope.execution_requests) == bid.execution_requests_root`
111
+ const requestsRoot = ssz.electra.ExecutionRequests.hashTreeRoot(envelope.executionRequests);
112
+ if (!byteArrayEquals(requestsRoot, payloadInput.getBid().executionRequestsRoot)) {
113
+ throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
114
+ code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_ROOT_MISMATCH,
115
+ envelopeRequestsRoot: toRootHex(requestsRoot),
116
+ bidRequestsRoot: toRootHex(payloadInput.getBid().executionRequestsRoot),
117
+ });
118
+ }
119
+
110
120
  // Get the block state to verify the builder's signature.
111
121
  const blockState = await chain.regen
112
122
  .getState(block.stateRoot, RegenCaller.validateGossipPayloadEnvelope)