@lodestar/beacon-node 1.42.0-rc.0 → 1.43.0-dev.07875b3e0c

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 (320) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +21 -4
  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 +4 -0
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  8. package/lib/api/impl/beacon/state/index.js +13 -10
  9. package/lib/api/impl/beacon/state/index.js.map +1 -1
  10. package/lib/api/impl/beacon/state/utils.d.ts +2 -2
  11. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  12. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  13. package/lib/api/impl/lodestar/attesterSlashing.d.ts +8 -0
  14. package/lib/api/impl/lodestar/attesterSlashing.d.ts.map +1 -0
  15. package/lib/api/impl/lodestar/attesterSlashing.js +29 -0
  16. package/lib/api/impl/lodestar/attesterSlashing.js.map +1 -0
  17. package/lib/api/impl/lodestar/index.d.ts.map +1 -1
  18. package/lib/api/impl/lodestar/index.js +39 -0
  19. package/lib/api/impl/lodestar/index.js.map +1 -1
  20. package/lib/api/impl/validator/index.d.ts.map +1 -1
  21. package/lib/api/impl/validator/index.js +8 -5
  22. package/lib/api/impl/validator/index.js.map +1 -1
  23. package/lib/chain/GetBlobsTracker.d.ts +1 -1
  24. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  25. package/lib/chain/GetBlobsTracker.js +1 -2
  26. package/lib/chain/GetBlobsTracker.js.map +1 -1
  27. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  28. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  29. package/lib/chain/archiveStore/interface.d.ts +4 -4
  30. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  31. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
  32. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
  33. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +2 -4
  34. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
  35. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +2 -2
  36. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  37. package/lib/chain/archiveStore/utils/archiveBlocks.js +110 -58
  38. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  39. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  40. package/lib/chain/blocks/importBlock.js +29 -35
  41. package/lib/chain/blocks/importBlock.js.map +1 -1
  42. package/lib/chain/blocks/importExecutionPayload.d.ts +15 -14
  43. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  44. package/lib/chain/blocks/importExecutionPayload.js +69 -82
  45. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  46. package/lib/chain/blocks/index.d.ts.map +1 -1
  47. package/lib/chain/blocks/index.js +1 -2
  48. package/lib/chain/blocks/index.js.map +1 -1
  49. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +3 -0
  50. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  51. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +20 -0
  52. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  53. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -0
  54. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  55. package/lib/chain/blocks/payloadEnvelopeProcessor.js +6 -4
  56. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  57. package/lib/chain/blocks/types.d.ts +15 -21
  58. package/lib/chain/blocks/types.d.ts.map +1 -1
  59. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  60. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +3 -2
  61. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  62. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  63. package/lib/chain/blocks/verifyBlocksSignatures.js +4 -2
  64. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  65. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
  66. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
  67. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +76 -0
  68. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
  69. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +14 -0
  70. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -0
  71. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +25 -0
  72. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -0
  73. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
  74. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
  75. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
  76. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  77. package/lib/chain/chain.d.ts +5 -4
  78. package/lib/chain/chain.d.ts.map +1 -1
  79. package/lib/chain/chain.js +32 -38
  80. package/lib/chain/chain.js.map +1 -1
  81. package/lib/chain/emitter.d.ts +16 -4
  82. package/lib/chain/emitter.d.ts.map +1 -1
  83. package/lib/chain/emitter.js +5 -0
  84. package/lib/chain/emitter.js.map +1 -1
  85. package/lib/chain/errors/attestationError.d.ts +8 -1
  86. package/lib/chain/errors/attestationError.d.ts.map +1 -1
  87. package/lib/chain/errors/attestationError.js +4 -0
  88. package/lib/chain/errors/attestationError.js.map +1 -1
  89. package/lib/chain/errors/blockError.d.ts +11 -1
  90. package/lib/chain/errors/blockError.d.ts.map +1 -1
  91. package/lib/chain/errors/blockError.js +4 -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/forkChoice/index.d.ts.map +1 -1
  102. package/lib/chain/forkChoice/index.js +21 -23
  103. package/lib/chain/forkChoice/index.js.map +1 -1
  104. package/lib/chain/interface.d.ts +4 -3
  105. package/lib/chain/interface.d.ts.map +1 -1
  106. package/lib/chain/interface.js.map +1 -1
  107. package/lib/chain/lightClient/index.d.ts +2 -2
  108. package/lib/chain/lightClient/index.d.ts.map +1 -1
  109. package/lib/chain/lightClient/index.js +7 -0
  110. package/lib/chain/lightClient/index.js.map +1 -1
  111. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  112. package/lib/chain/opPools/aggregatedAttestationPool.js +5 -2
  113. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  114. package/lib/chain/opPools/executionPayloadBidPool.d.ts +2 -2
  115. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
  116. package/lib/chain/opPools/executionPayloadBidPool.js +2 -2
  117. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
  118. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  119. package/lib/chain/prepareNextSlot.js +32 -11
  120. package/lib/chain/prepareNextSlot.js.map +1 -1
  121. package/lib/chain/produceBlock/computeNewStateRoot.d.ts +1 -7
  122. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  123. package/lib/chain/produceBlock/computeNewStateRoot.js +1 -28
  124. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  125. package/lib/chain/produceBlock/produceBlockBody.d.ts +5 -10
  126. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  127. package/lib/chain/produceBlock/produceBlockBody.js +49 -19
  128. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  129. package/lib/chain/regen/errors.d.ts +1 -11
  130. package/lib/chain/regen/errors.d.ts.map +1 -1
  131. package/lib/chain/regen/errors.js +0 -2
  132. package/lib/chain/regen/errors.js.map +1 -1
  133. package/lib/chain/regen/interface.d.ts +6 -12
  134. package/lib/chain/regen/interface.d.ts.map +1 -1
  135. package/lib/chain/regen/queued.d.ts +6 -11
  136. package/lib/chain/regen/queued.d.ts.map +1 -1
  137. package/lib/chain/regen/queued.js +8 -40
  138. package/lib/chain/regen/queued.js.map +1 -1
  139. package/lib/chain/regen/regen.d.ts +0 -5
  140. package/lib/chain/regen/regen.d.ts.map +1 -1
  141. package/lib/chain/regen/regen.js +7 -34
  142. package/lib/chain/regen/regen.js.map +1 -1
  143. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +11 -4
  144. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  145. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +20 -18
  146. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  147. package/lib/chain/stateCache/datastore/db.d.ts +5 -4
  148. package/lib/chain/stateCache/datastore/db.d.ts.map +1 -1
  149. package/lib/chain/stateCache/datastore/db.js +10 -32
  150. package/lib/chain/stateCache/datastore/db.js.map +1 -1
  151. package/lib/chain/stateCache/datastore/file.d.ts +1 -1
  152. package/lib/chain/stateCache/datastore/file.d.ts.map +1 -1
  153. package/lib/chain/stateCache/datastore/file.js +5 -5
  154. package/lib/chain/stateCache/datastore/file.js.map +1 -1
  155. package/lib/chain/stateCache/datastore/types.d.ts +1 -1
  156. package/lib/chain/stateCache/datastore/types.d.ts.map +1 -1
  157. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +1 -7
  158. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  159. package/lib/chain/stateCache/fifoBlockStateCache.js +0 -8
  160. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  161. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +13 -30
  162. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  163. package/lib/chain/stateCache/persistentCheckpointsCache.js +120 -216
  164. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  165. package/lib/chain/stateCache/types.d.ts +8 -15
  166. package/lib/chain/stateCache/types.d.ts.map +1 -1
  167. package/lib/chain/stateCache/types.js.map +1 -1
  168. package/lib/chain/validation/aggregateAndProof.js +12 -0
  169. package/lib/chain/validation/aggregateAndProof.js.map +1 -1
  170. package/lib/chain/validation/attestation.d.ts.map +1 -1
  171. package/lib/chain/validation/attestation.js +12 -0
  172. package/lib/chain/validation/attestation.js.map +1 -1
  173. package/lib/chain/validation/block.d.ts.map +1 -1
  174. package/lib/chain/validation/block.js +27 -5
  175. package/lib/chain/validation/block.js.map +1 -1
  176. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  177. package/lib/chain/validation/executionPayloadBid.js +19 -4
  178. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  179. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  180. package/lib/chain/validation/executionPayloadEnvelope.js +27 -12
  181. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  182. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  183. package/lib/chain/validation/payloadAttestationMessage.js +8 -4
  184. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  185. package/lib/chain/validation/syncCommittee.d.ts.map +1 -1
  186. package/lib/chain/validation/syncCommittee.js +4 -0
  187. package/lib/chain/validation/syncCommittee.js.map +1 -1
  188. package/lib/chain/validation/syncCommitteeContributionAndProof.js +4 -1
  189. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  190. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  191. package/lib/chain/validatorMonitor.js +3 -3
  192. package/lib/chain/validatorMonitor.js.map +1 -1
  193. package/lib/db/repositories/executionPayloadEnvelopeArchive.js +1 -1
  194. package/lib/db/repositories/executionPayloadEnvelopeArchive.js.map +1 -1
  195. package/lib/execution/engine/http.d.ts.map +1 -1
  196. package/lib/execution/engine/http.js +21 -14
  197. package/lib/execution/engine/http.js.map +1 -1
  198. package/lib/execution/engine/interface.d.ts +1 -0
  199. package/lib/execution/engine/interface.d.ts.map +1 -1
  200. package/lib/execution/engine/mock.d.ts.map +1 -1
  201. package/lib/execution/engine/mock.js +6 -0
  202. package/lib/execution/engine/mock.js.map +1 -1
  203. package/lib/execution/engine/types.d.ts +20 -0
  204. package/lib/execution/engine/types.d.ts.map +1 -1
  205. package/lib/execution/engine/types.js +18 -0
  206. package/lib/execution/engine/types.js.map +1 -1
  207. package/lib/network/gossip/topic.d.ts +3 -2
  208. package/lib/network/gossip/topic.d.ts.map +1 -1
  209. package/lib/network/network.js +1 -1
  210. package/lib/network/network.js.map +1 -1
  211. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  212. package/lib/network/processor/gossipHandlers.js +26 -6
  213. package/lib/network/processor/gossipHandlers.js.map +1 -1
  214. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  215. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +2 -1
  216. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  217. package/lib/network/reqresp/handlers/beaconBlocksByRoot.d.ts.map +1 -1
  218. package/lib/network/reqresp/handlers/beaconBlocksByRoot.js +2 -0
  219. package/lib/network/reqresp/handlers/beaconBlocksByRoot.js.map +1 -1
  220. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts +2 -2
  221. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  222. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +7 -3
  223. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  224. package/lib/network/reqresp/handlers/blobSidecarsByRoot.d.ts.map +1 -1
  225. package/lib/network/reqresp/handlers/blobSidecarsByRoot.js +6 -0
  226. package/lib/network/reqresp/handlers/blobSidecarsByRoot.js.map +1 -1
  227. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts +2 -2
  228. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  229. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +7 -3
  230. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  231. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  232. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +2 -1
  233. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  234. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
  235. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +3 -8
  236. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  237. package/lib/node/nodejs.d.ts.map +1 -1
  238. package/lib/node/nodejs.js +6 -1
  239. package/lib/node/nodejs.js.map +1 -1
  240. package/lib/node/notifier.d.ts.map +1 -1
  241. package/lib/node/notifier.js +2 -2
  242. package/lib/node/notifier.js.map +1 -1
  243. package/lib/util/sszBytes.d.ts.map +1 -1
  244. package/lib/util/sszBytes.js +16 -3
  245. package/lib/util/sszBytes.js.map +1 -1
  246. package/package.json +16 -16
  247. package/src/api/impl/beacon/blocks/index.ts +30 -4
  248. package/src/api/impl/beacon/pool/index.ts +4 -0
  249. package/src/api/impl/beacon/state/index.ts +15 -15
  250. package/src/api/impl/beacon/state/utils.ts +2 -2
  251. package/src/api/impl/lodestar/attesterSlashing.ts +43 -0
  252. package/src/api/impl/lodestar/index.ts +51 -1
  253. package/src/api/impl/validator/index.ts +10 -6
  254. package/src/chain/GetBlobsTracker.ts +1 -2
  255. package/src/chain/archiveStore/archiveStore.ts +5 -5
  256. package/src/chain/archiveStore/interface.ts +4 -4
  257. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +6 -8
  258. package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
  259. package/src/chain/blocks/importBlock.ts +33 -42
  260. package/src/chain/blocks/importExecutionPayload.ts +83 -99
  261. package/src/chain/blocks/index.ts +1 -2
  262. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +27 -0
  263. package/src/chain/blocks/payloadEnvelopeProcessor.ts +6 -5
  264. package/src/chain/blocks/types.ts +15 -26
  265. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +2 -1
  266. package/src/chain/blocks/verifyBlocksSignatures.ts +9 -2
  267. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
  268. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +38 -0
  269. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  270. package/src/chain/chain.ts +47 -62
  271. package/src/chain/emitter.ts +15 -3
  272. package/src/chain/errors/attestationError.ts +6 -1
  273. package/src/chain/errors/blockError.ts +7 -1
  274. package/src/chain/errors/executionPayloadBid.ts +6 -0
  275. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  276. package/src/chain/forkChoice/index.ts +19 -28
  277. package/src/chain/interface.ts +7 -2
  278. package/src/chain/lightClient/index.ts +15 -3
  279. package/src/chain/opPools/aggregatedAttestationPool.ts +6 -1
  280. package/src/chain/opPools/executionPayloadBidPool.ts +3 -3
  281. package/src/chain/prepareNextSlot.ts +38 -11
  282. package/src/chain/produceBlock/computeNewStateRoot.ts +1 -37
  283. package/src/chain/produceBlock/produceBlockBody.ts +74 -23
  284. package/src/chain/regen/errors.ts +1 -6
  285. package/src/chain/regen/interface.ts +6 -12
  286. package/src/chain/regen/queued.ts +12 -48
  287. package/src/chain/regen/regen.ts +8 -36
  288. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +22 -20
  289. package/src/chain/stateCache/datastore/db.ts +10 -33
  290. package/src/chain/stateCache/datastore/file.ts +5 -6
  291. package/src/chain/stateCache/datastore/types.ts +2 -3
  292. package/src/chain/stateCache/fifoBlockStateCache.ts +1 -10
  293. package/src/chain/stateCache/persistentCheckpointsCache.ts +139 -247
  294. package/src/chain/stateCache/types.ts +8 -14
  295. package/src/chain/validation/aggregateAndProof.ts +13 -0
  296. package/src/chain/validation/attestation.ts +13 -0
  297. package/src/chain/validation/block.ts +30 -7
  298. package/src/chain/validation/executionPayloadBid.ts +21 -3
  299. package/src/chain/validation/executionPayloadEnvelope.ts +32 -13
  300. package/src/chain/validation/payloadAttestationMessage.ts +9 -3
  301. package/src/chain/validation/syncCommittee.ts +5 -1
  302. package/src/chain/validation/syncCommitteeContributionAndProof.ts +5 -1
  303. package/src/chain/validatorMonitor.ts +3 -2
  304. package/src/db/repositories/executionPayloadEnvelopeArchive.ts +1 -1
  305. package/src/execution/engine/http.ts +21 -14
  306. package/src/execution/engine/interface.ts +1 -0
  307. package/src/execution/engine/mock.ts +8 -1
  308. package/src/execution/engine/types.ts +41 -0
  309. package/src/network/network.ts +1 -1
  310. package/src/network/processor/gossipHandlers.ts +31 -10
  311. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +3 -1
  312. package/src/network/reqresp/handlers/beaconBlocksByRoot.ts +3 -0
  313. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +15 -3
  314. package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +11 -0
  315. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +19 -3
  316. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +3 -1
  317. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +3 -12
  318. package/src/node/nodejs.ts +7 -2
  319. package/src/node/notifier.ts +7 -2
  320. package/src/util/sszBytes.ts +21 -3
@@ -8,14 +8,15 @@ import {
8
8
  ProtoArray,
9
9
  ProtoBlock,
10
10
  ForkChoiceOpts as RawForkChoiceOpts,
11
- getCheckpointPayloadStatus,
12
11
  } from "@lodestar/fork-choice";
13
- import {ForkSeq, ZERO_HASH_HEX} from "@lodestar/params";
12
+ import {ZERO_HASH_HEX} from "@lodestar/params";
14
13
  import {
15
14
  DataAvailabilityStatus,
16
15
  IBeaconStateView,
17
16
  computeEpochAtSlot,
18
17
  computeStartSlotAtEpoch,
18
+ isStatePostBellatrix,
19
+ isStatePostGloas,
19
20
  } from "@lodestar/state-transition";
20
21
  import {Slot, ssz} from "@lodestar/types";
21
22
  import {Logger, toRootHex} from "@lodestar/utils";
@@ -102,12 +103,6 @@ export function initializeForkChoiceFromFinalizedState(
102
103
 
103
104
  const isForkPostGloas = computeEpochAtSlot(state.slot) >= config.GLOAS_FORK_EPOCH;
104
105
 
105
- // Determine justified checkpoint payload status
106
- const justifiedPayloadStatus = getCheckpointPayloadStatus(config, state, justifiedCheckpoint.epoch);
107
-
108
- // Determine finalized checkpoint payload status
109
- const finalizedPayloadStatus = getCheckpointPayloadStatus(config, state, finalizedCheckpoint.epoch);
110
-
111
106
  return new forkchoiceConstructor(
112
107
  config,
113
108
 
@@ -117,8 +112,6 @@ export function initializeForkChoiceFromFinalizedState(
117
112
  finalizedCheckpoint,
118
113
  justifiedBalances,
119
114
  justifiedBalancesGetter,
120
- justifiedPayloadStatus,
121
- finalizedPayloadStatus,
122
115
  {
123
116
  onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
124
117
  onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
@@ -142,19 +135,21 @@ export function initializeForkChoiceFromFinalizedState(
142
135
  unrealizedFinalizedEpoch: finalizedCheckpoint.epoch,
143
136
  unrealizedFinalizedRoot: toRootHex(finalizedCheckpoint.root),
144
137
 
145
- ...(state.isExecutionStateType && state.isMergeTransitionComplete
138
+ ...(isStatePostBellatrix(state) && state.isExecutionStateType && state.isMergeTransitionComplete
146
139
  ? {
147
- executionPayloadBlockHash: toRootHex(state.latestBlockHash),
140
+ executionPayloadBlockHash: isStatePostGloas(state)
141
+ ? toRootHex(state.latestBlockHash)
142
+ : toRootHex(state.latestExecutionPayloadHeader.blockHash),
148
143
  // TODO GLOAS: executionPayloadNumber is not tracked in BeaconState post-gloas (EIP-7732 removed
149
144
  // latestExecutionPayloadHeader). Using 0 as unavailable fallback until a solution is found.
150
- executionPayloadNumber: config.getForkSeq(state.slot) >= ForkSeq.gloas ? 0 : state.payloadBlockNumber,
145
+ executionPayloadNumber: isStatePostGloas(state) ? 0 : state.payloadBlockNumber,
151
146
  executionStatus: blockHeader.slot === GENESIS_SLOT ? ExecutionStatus.Valid : ExecutionStatus.Syncing,
152
147
  }
153
148
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
154
149
 
155
150
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
156
- payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
157
- parentBlockHash: isForkPostGloas ? toRootHex(state.latestBlockHash) : null,
151
+ payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
152
+ parentBlockHash: isStatePostGloas(state) ? toRootHex(state.latestBlockHash) : null,
158
153
  },
159
154
  currentSlot
160
155
  ),
@@ -200,19 +195,12 @@ export function initializeForkChoiceFromUnfinalizedState(
200
195
 
201
196
  const isForkPostGloas = computeEpochAtSlot(unfinalizedState.slot) >= config.GLOAS_FORK_EPOCH;
202
197
 
203
- // For unfinalized state, use getCheckpointPayloadStatus to determine the correct status.
204
- // It checks state.execution_payload_availability to determine EMPTY vs FULL.
205
- const justifiedPayloadStatus = getCheckpointPayloadStatus(config, unfinalizedState, justifiedCheckpoint.epoch);
206
- const finalizedPayloadStatus = getCheckpointPayloadStatus(config, unfinalizedState, finalizedCheckpoint.epoch);
207
-
208
198
  const store = new ForkChoiceStore(
209
199
  currentSlot,
210
200
  justifiedCheckpoint,
211
201
  finalizedCheckpoint,
212
202
  justifiedBalances,
213
203
  justifiedBalancesGetter,
214
- justifiedPayloadStatus,
215
- finalizedPayloadStatus,
216
204
  {
217
205
  onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
218
206
  onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
@@ -237,20 +225,23 @@ export function initializeForkChoiceFromUnfinalizedState(
237
225
  unrealizedFinalizedEpoch: finalizedCheckpoint.epoch,
238
226
  unrealizedFinalizedRoot: toRootHex(finalizedCheckpoint.root),
239
227
 
240
- ...(unfinalizedState.isExecutionStateType && unfinalizedState.isMergeTransitionComplete
228
+ ...(isStatePostBellatrix(unfinalizedState) &&
229
+ unfinalizedState.isExecutionStateType &&
230
+ unfinalizedState.isMergeTransitionComplete
241
231
  ? {
242
- executionPayloadBlockHash: toRootHex(unfinalizedState.latestBlockHash),
232
+ executionPayloadBlockHash: isStatePostGloas(unfinalizedState)
233
+ ? toRootHex(unfinalizedState.latestBlockHash)
234
+ : toRootHex(unfinalizedState.latestExecutionPayloadHeader.blockHash),
243
235
  // TODO GLOAS: executionPayloadNumber is not tracked in BeaconState post-gloas (EIP-7732 removed
244
236
  // latestExecutionPayloadHeader). Using 0 as unavailable fallback until a solution is found.
245
- executionPayloadNumber:
246
- config.getForkSeq(unfinalizedState.slot) >= ForkSeq.gloas ? 0 : unfinalizedState.payloadBlockNumber,
237
+ executionPayloadNumber: isStatePostGloas(unfinalizedState) ? 0 : unfinalizedState.payloadBlockNumber,
247
238
  executionStatus: blockHeader.slot === GENESIS_SLOT ? ExecutionStatus.Valid : ExecutionStatus.Syncing,
248
239
  }
249
240
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
250
241
 
251
242
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
252
- payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
253
- parentBlockHash: isForkPostGloas ? toRootHex(unfinalizedState.latestBlockHash) : null,
243
+ payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
244
+ parentBlockHash: isStatePostGloas(unfinalizedState) ? toRootHex(unfinalizedState.latestBlockHash) : null,
254
245
  };
255
246
 
256
247
  const parentSlot = blockHeader.slot - 1;
@@ -1,6 +1,6 @@
1
1
  import {Type} from "@chainsafe/ssz";
2
2
  import {BeaconConfig} from "@lodestar/config";
3
- import {CheckpointWithHex, CheckpointWithPayloadStatus, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
3
+ import {CheckpointWithHex, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
4
4
  import {EpochShuffling, IBeaconStateView, PubkeyCache} from "@lodestar/state-transition";
5
5
  import {
6
6
  BeaconBlock,
@@ -18,6 +18,7 @@ import {
18
18
  altair,
19
19
  capella,
20
20
  deneb,
21
+ gloas,
21
22
  phase0,
22
23
  rewards,
23
24
  } from "@lodestar/types";
@@ -194,7 +195,7 @@ export interface IBeaconChain {
194
195
  ): {state: IBeaconStateView; executionOptimistic: boolean; finalized: boolean} | null;
195
196
  /** Return state bytes by checkpoint */
196
197
  getStateOrBytesByCheckpoint(
197
- checkpoint: CheckpointWithPayloadStatus
198
+ checkpoint: CheckpointWithHex
198
199
  ): Promise<{state: IBeaconStateView | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null>;
199
200
 
200
201
  /**
@@ -226,6 +227,10 @@ export interface IBeaconChain {
226
227
  indices: number[]
227
228
  ): Promise<(Uint8Array | undefined)[]>;
228
229
  getSerializedExecutionPayloadEnvelope(blockSlot: Slot, blockRootHex: string): Promise<Uint8Array | null>;
230
+ getExecutionPayloadEnvelope(
231
+ blockSlot: Slot,
232
+ blockRootHex: string
233
+ ): Promise<gloas.SignedExecutionPayloadEnvelope | null>;
229
234
 
230
235
  produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody>;
231
236
  produceBlock(blockAttributes: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}): Promise<{
@@ -21,7 +21,7 @@ import {
21
21
  isForkPostElectra,
22
22
  } from "@lodestar/params";
23
23
  import {
24
- IBeaconStateView,
24
+ type IBeaconStateViewAltair,
25
25
  computeStartSlotAtEpoch,
26
26
  computeSyncPeriodAtEpoch,
27
27
  computeSyncPeriodAtSlot,
@@ -260,7 +260,11 @@ export class LightClientServer {
260
260
  * - Persist state witness
261
261
  * - Use block's syncAggregate
262
262
  */
263
- onImportBlockHead(block: BeaconBlock<ForkPostAltair>, postState: IBeaconStateView, parentBlockSlot: Slot): void {
263
+ onImportBlockHead(
264
+ block: BeaconBlock<ForkPostAltair>,
265
+ postState: IBeaconStateViewAltair,
266
+ parentBlockSlot: Slot
267
+ ): void {
264
268
  // TEMP: To disable this functionality for fork_choice spec tests.
265
269
  // Since the tests have deep-reorgs attested data is not available often printing lots of error logs.
266
270
  // While this function is only called for head blocks, best to disable.
@@ -268,6 +272,14 @@ export class LightClientServer {
268
272
  return;
269
273
  }
270
274
 
275
+ // TODO GLOAS: Light client updates for gloas are not yet updated in the spec.
276
+ // The block body no longer contains execution payload, so `blockToLightClientHeader`
277
+ // cannot construct a header from a gloas block. Skip all light client processing
278
+ // for post-gloas blocks, revisit once there is a spec for it.
279
+ if (this.config.getForkSeq(block.slot) >= ForkSeq.gloas) {
280
+ return;
281
+ }
282
+
271
283
  // What is the syncAggregate signing?
272
284
  // From the state-transition
273
285
  // ```
@@ -396,7 +408,7 @@ export class LightClientServer {
396
408
 
397
409
  private async persistPostBlockImportData(
398
410
  block: BeaconBlock<ForkPostAltair>,
399
- postState: IBeaconStateView,
411
+ postState: IBeaconStateViewAltair,
400
412
  parentBlockSlot: Slot
401
413
  ): Promise<void> {
402
414
  const blockSlot = block.slot;
@@ -26,6 +26,8 @@ import {
26
26
  computeSlotsSinceEpochStart,
27
27
  computeStartSlotAtEpoch,
28
28
  getAttestationParticipationStatus,
29
+ isStatePostAltair,
30
+ isStatePostGloas,
29
31
  } from "@lodestar/state-transition";
30
32
  import {Attestation, Epoch, RootHex, Slot, electra, isElectraAttestation, phase0, ssz} from "@lodestar/types";
31
33
  import {MapDef, assert, toRootHex} from "@lodestar/utils";
@@ -359,7 +361,7 @@ export class AggregatedAttestationPool {
359
361
  inclusionDistance,
360
362
  stateEpoch,
361
363
  rootCache,
362
- ForkSeq[fork] >= ForkSeq.gloas ? state.executionPayloadAvailability : null
364
+ isStatePostGloas(state) ? state.executionPayloadAvailability : null
363
365
  );
364
366
 
365
367
  const weight =
@@ -742,6 +744,9 @@ export function getNotSeenValidatorsFn(
742
744
  if (config.getForkName(stateSlot) === ForkName.phase0) {
743
745
  throw new Error("getNotSeenValidatorsFn is not supported phase0 state");
744
746
  }
747
+ if (!isStatePostAltair(state)) {
748
+ throw new Error("Expected Altair state for participation tracking");
749
+ }
745
750
 
746
751
  // altair and future forks
747
752
  // Get attestations to be included in an altair block.
@@ -59,13 +59,13 @@ export class ExecutionPayloadBidPool {
59
59
  }
60
60
 
61
61
  /**
62
- * Return the highest-value bid matching slot, parent block root, and parent block hash.
62
+ * Return the highest-value bid matching slot, parent block hash, and parent block root.
63
63
  * Used for gossip validation and block production.
64
64
  */
65
65
  getBestBid(
66
- parentBlockRoot: BlockRootHex,
66
+ slot: Slot,
67
67
  parentBlockHash: BlockHashHex,
68
- slot: Slot
68
+ parentBlockRoot: BlockRootHex
69
69
  ): gloas.ExecutionPayloadBid | null {
70
70
  const bidByParentHash = this.bidByParentHashByParentRootBySlot.get(slot)?.get(parentBlockRoot);
71
71
  return bidByParentHash?.get(parentBlockHash) ?? null;
@@ -1,14 +1,16 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {ChainForkConfig} from "@lodestar/config";
3
- import {PayloadStatus, getSafeExecutionBlockHash} from "@lodestar/fork-choice";
3
+ 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
7
  StateHashTreeRootSource,
8
8
  computeEpochAtSlot,
9
9
  computeTimeAtSlot,
10
+ isStatePostBellatrix,
11
+ isStatePostGloas,
10
12
  } from "@lodestar/state-transition";
11
- import {Slot} from "@lodestar/types";
13
+ import {Bytes32, Slot} from "@lodestar/types";
12
14
  import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils";
13
15
  import {GENESIS_SLOT, ZERO_HASH_HEX} from "../constants/constants.js";
14
16
  import {BuilderStatus} from "../execution/builder/http.js";
@@ -80,6 +82,8 @@ export class PrepareNextSlotScheduler {
80
82
  // calling updateHead() here before we produce a block to reduce reorg possibility
81
83
  const headBlock = this.chain.recomputeForkChoiceHead(ForkchoiceCaller.prepareNextSlot);
82
84
  const {slot: headSlot, blockRoot: headRoot} = headBlock;
85
+ // may be updated below if we predict a proposer-boost-reorg
86
+ let updatedHead = headBlock;
83
87
 
84
88
  // PS: previously this was comparing slots, but that gave no leway on the skipped
85
89
  // slots on epoch bounday. Making it more fluid.
@@ -122,7 +126,6 @@ export class PrepareNextSlotScheduler {
122
126
  const proposerIndex = prepareState.getBeaconProposer(prepareSlot);
123
127
  const feeRecipient = this.chain.beaconProposerCache.get(proposerIndex);
124
128
  let updatedPrepareState = prepareState;
125
- let updatedHeadRoot = headRoot;
126
129
 
127
130
  if (feeRecipient) {
128
131
  // If we are proposing next slot, we need to predict if we can proposer-boost-reorg or not
@@ -145,7 +148,7 @@ export class PrepareNextSlotScheduler {
145
148
  {dontTransferCache: !isEpochTransition},
146
149
  RegenCaller.predictProposerHead
147
150
  );
148
- updatedHeadRoot = proposerHeadRoot;
151
+ updatedHead = proposerHead;
149
152
  }
150
153
 
151
154
  // Update the builder status, if enabled shoot an api call to check status
@@ -155,7 +158,22 @@ export class PrepareNextSlotScheduler {
155
158
  this.logger.error("Builder disabled as the check status api failed", {prepareSlot}, e as Error);
156
159
  });
157
160
  }
161
+ }
162
+
163
+ if (!isStatePostBellatrix(updatedPrepareState)) {
164
+ throw new Error("Expected Bellatrix state for payload attributes");
165
+ }
166
+
167
+ let parentBlockHash: Bytes32;
168
+ if (isStatePostGloas(updatedPrepareState)) {
169
+ parentBlockHash = this.chain.forkChoice.shouldExtendPayload(updatedHead.blockRoot)
170
+ ? updatedPrepareState.latestExecutionPayloadBid.blockHash
171
+ : updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
172
+ } else {
173
+ parentBlockHash = updatedPrepareState.latestExecutionPayloadHeader.blockHash;
174
+ }
158
175
 
176
+ if (feeRecipient) {
159
177
  const preparationTime =
160
178
  computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
161
179
  this.metrics?.blockPayload.payloadAdvancePrepTime.observe(preparationTime);
@@ -163,14 +181,16 @@ export class PrepareNextSlotScheduler {
163
181
  const safeBlockHash = getSafeExecutionBlockHash(this.chain.forkChoice);
164
182
  const finalizedBlockHash =
165
183
  this.chain.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
184
+
166
185
  // awaiting here instead of throwing an async call because there is no other task
167
- // left for scheduler and this gives nice sematics to catch and log errors in the
186
+ // left for scheduler and this gives nice semantics to catch and log errors in the
168
187
  // try/catch wrapper here.
169
188
  await prepareExecutionPayload(
170
189
  this.chain,
171
190
  this.logger,
172
191
  fork as ForkPostBellatrix, // State is of execution type
173
- fromHex(updatedHeadRoot),
192
+ fromHex(updatedHead.blockRoot),
193
+ parentBlockHash,
174
194
  safeBlockHash,
175
195
  finalizedBlockHash,
176
196
  updatedPrepareState,
@@ -183,6 +203,16 @@ export class PrepareNextSlotScheduler {
183
203
  });
184
204
  }
185
205
 
206
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
207
+ // Cutoff = slot of the parent of the block we'll actually build on (post-reorg).
208
+ // Steady state: cache holds just 2 entries — head (parent for next-slot production)
209
+ // and head.parent (proposer-boost-reorg fallback). Anything older is evicted.
210
+ const updatedHeadParent = this.chain.forkChoice.getBlockHexDefaultStatus(updatedHead.parentRoot);
211
+ if (updatedHeadParent) {
212
+ this.chain.seenPayloadEnvelopeInputCache.pruneBelow(updatedHeadParent.slot);
213
+ }
214
+ }
215
+
186
216
  this.computeStateHashTreeRoot(updatedPrepareState, isEpochTransition);
187
217
 
188
218
  // If emitPayloadAttributes is true emit a SSE payloadAttributes event
@@ -194,6 +224,7 @@ export class PrepareNextSlotScheduler {
194
224
  prepareState: updatedPrepareState,
195
225
  prepareSlot,
196
226
  parentBlockRoot: fromHex(headRoot),
227
+ parentBlockHash,
197
228
  // The likely consumers of this API are builders and will anyway ignore the
198
229
  // feeRecipient, so just pass zero hash for now till a real use case arises
199
230
  feeRecipient: "0x0000000000000000000000000000000000000000000000000000000000000000",
@@ -209,11 +240,7 @@ export class PrepareNextSlotScheduler {
209
240
  // + if next slot is a skipped slot, it'd help getting target checkpoint state faster to validate attestations
210
241
  if (isEpochTransition) {
211
242
  this.metrics?.precomputeNextEpochTransition.count.inc({result: "success"}, 1);
212
- // Determine payloadPresent from head block's payload status
213
- // Pre-Gloas: payloadStatus is always FULL → payloadPresent = true
214
- // Post-Gloas: FULL → true, EMPTY → false, PENDING → false (conservative, treat as block state)
215
- const payloadPresent = headBlock.payloadStatus === PayloadStatus.FULL;
216
- const previousHits = this.chain.regen.updatePreComputedCheckpoint(headRoot, nextEpoch, payloadPresent);
243
+ const previousHits = this.chain.regen.updatePreComputedCheckpoint(headRoot, nextEpoch);
217
244
  if (previousHits === 0) {
218
245
  this.metrics?.precomputeNextEpochTransition.waste.inc();
219
246
  }
@@ -1,11 +1,10 @@
1
1
  import {
2
2
  DataAvailabilityStatus,
3
3
  ExecutionPayloadStatus,
4
- G2_POINT_AT_INFINITY,
5
4
  IBeaconStateView,
6
5
  StateHashTreeRootSource,
7
6
  } from "@lodestar/state-transition";
8
- import {BeaconBlock, BlindedBeaconBlock, Gwei, Root, gloas} from "@lodestar/types";
7
+ import {BeaconBlock, BlindedBeaconBlock, Gwei, Root} from "@lodestar/types";
9
8
  import {ZERO_HASH} from "../../constants/index.js";
10
9
  import {Metrics} from "../../metrics/index.js";
11
10
 
@@ -52,38 +51,3 @@ export function computeNewStateRoot(
52
51
 
53
52
  return {newStateRoot, proposerReward, postState};
54
53
  }
55
-
56
- /**
57
- * Compute the state root after processing an execution payload envelope.
58
- * Similar to `computeNewStateRoot` but for payload envelope processing.
59
- *
60
- */
61
- export function computeEnvelopeStateRoot(
62
- metrics: Metrics | null,
63
- postBlockState: IBeaconStateView,
64
- envelope: gloas.ExecutionPayloadEnvelope
65
- ): Root {
66
- const signedEnvelope: gloas.SignedExecutionPayloadEnvelope = {
67
- message: envelope,
68
- signature: G2_POINT_AT_INFINITY,
69
- };
70
-
71
- const processEnvelopeTimer = metrics?.blockPayload.executionPayloadEnvelopeProcessingTime.startTimer();
72
- const postEnvelopeState = postBlockState.processExecutionPayloadEnvelope(signedEnvelope, {
73
- // Signature is zero-ed (G2_POINT_AT_INFINITY), skip verification
74
- verifySignature: false,
75
- // State root is being computed here, the envelope doesn't have it yet
76
- verifyStateRoot: false,
77
- // Preserve cache in source state, since the resulting state is not added to the state cache
78
- dontTransferCache: true,
79
- });
80
- processEnvelopeTimer?.();
81
-
82
- const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer({
83
- source: StateHashTreeRootSource.computeEnvelopeStateRoot,
84
- });
85
- const stateRoot = postEnvelopeState.hashTreeRoot();
86
- hashTreeRootTimer?.();
87
-
88
- return stateRoot;
89
- }
@@ -14,7 +14,15 @@ import {
14
14
  isForkPostBellatrix,
15
15
  isForkPostGloas,
16
16
  } from "@lodestar/params";
17
- import {G2_POINT_AT_INFINITY, IBeaconStateView, computeTimeAtSlot} from "@lodestar/state-transition";
17
+ import {
18
+ G2_POINT_AT_INFINITY,
19
+ IBeaconStateView,
20
+ type IBeaconStateViewBellatrix,
21
+ computeTimeAtSlot,
22
+ isStatePostBellatrix,
23
+ isStatePostCapella,
24
+ isStatePostGloas,
25
+ } from "@lodestar/state-transition";
18
26
  import {
19
27
  BLSPubkey,
20
28
  BLSSignature,
@@ -38,8 +46,9 @@ import {
38
46
  electra,
39
47
  fulu,
40
48
  gloas,
49
+ ssz,
41
50
  } from "@lodestar/types";
42
- import {Logger, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
51
+ import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
43
52
  import {ZERO_HASH_HEX} from "../../constants/index.js";
44
53
  import {numToQuantity} from "../../execution/engine/utils.js";
45
54
  import {
@@ -102,12 +111,6 @@ export type ProduceFullGloas = {
102
111
  executionRequests: electra.ExecutionRequests;
103
112
  blobsBundle: BlobsBundle<ForkPostGloas>;
104
113
  cells: fulu.Cell[][];
105
- /**
106
- * Cached envelope state root computed during block production.
107
- * This is the state root after running `processExecutionPayloadEnvelope` on the
108
- * post-block state, and later used to construct the `ExecutionPayloadEnvelope`.
109
- */
110
- envelopeStateRoot: Root;
111
114
  };
112
115
  export type ProduceFullFulu = {
113
116
  type: BlockType.Full;
@@ -191,6 +194,10 @@ export async function produceBlockBody<T extends BlockType>(
191
194
  this.logger.verbose("Producing beacon block body", logMeta);
192
195
 
193
196
  if (isForkPostGloas(fork)) {
197
+ if (!isStatePostGloas(currentState)) {
198
+ throw new Error("Expected Gloas state for Gloas block production");
199
+ }
200
+
194
201
  // TODO GLOAS: support non self-building here, the block type differentiation between
195
202
  // full and blinded no longer makes sense in gloas, it might be a good idea to move
196
203
  // this into a completely separate function and have pre/post gloas more separated
@@ -207,11 +214,15 @@ export async function produceBlockBody<T extends BlockType>(
207
214
  });
208
215
 
209
216
  // Get execution payload from EL
217
+ const parentBlockHash = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot))
218
+ ? currentState.latestExecutionPayloadBid.blockHash
219
+ : currentState.latestExecutionPayloadBid.parentBlockHash;
210
220
  const prepareRes = await prepareExecutionPayload(
211
221
  this,
212
222
  this.logger,
213
223
  fork,
214
224
  parentBlockRoot,
225
+ parentBlockHash,
215
226
  safeBlockHash,
216
227
  finalizedBlockHash ?? ZERO_HASH_HEX,
217
228
  currentState,
@@ -248,8 +259,8 @@ export async function produceBlockBody<T extends BlockType>(
248
259
 
249
260
  // Create self-build execution payload bid
250
261
  const bid: gloas.ExecutionPayloadBid = {
251
- parentBlockHash: currentState.latestBlockHash,
252
- parentBlockRoot: parentBlockRoot,
262
+ parentBlockHash,
263
+ parentBlockRoot,
253
264
  blockHash: executionPayload.blockHash,
254
265
  prevRandao: currentState.getRandaoMix(currentState.epoch),
255
266
  feeRecipient: executionPayload.feeRecipient,
@@ -259,6 +270,7 @@ export async function produceBlockBody<T extends BlockType>(
259
270
  value: 0,
260
271
  executionPayment: 0,
261
272
  blobKzgCommitments: blobsBundle.commitments,
273
+ executionRequestsRoot: ssz.electra.ExecutionRequests.hashTreeRoot(executionRequests),
262
274
  };
263
275
  const signedBid: gloas.SignedExecutionPayloadBid = {
264
276
  message: bid,
@@ -270,6 +282,7 @@ export async function produceBlockBody<T extends BlockType>(
270
282
  gloasBody.signedExecutionPayloadBid = signedBid;
271
283
  // TODO GLOAS: Get payload attestations from pool for previous slot
272
284
  gloasBody.payloadAttestations = [];
285
+ // TODO GLOAS: set parentExecutionRequests in the block body
273
286
  blockBody = gloasBody as AssembledBodyType<T>;
274
287
 
275
288
  // Store execution payload data required to construct execution payload envelope later
@@ -297,6 +310,10 @@ export async function produceBlockBody<T extends BlockType>(
297
310
  shouldOverrideBuilder,
298
311
  });
299
312
  } else if (isForkPostBellatrix(fork)) {
313
+ if (!isStatePostBellatrix(currentState)) {
314
+ throw new Error("Expected Bellatrix state for execution block production");
315
+ }
316
+
300
317
  const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
301
318
  const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
302
319
  const feeRecipient = requestedFeeRecipient ?? this.beaconProposerCache.getOrDefault(proposerIndex);
@@ -323,6 +340,7 @@ export async function produceBlockBody<T extends BlockType>(
323
340
  this.logger,
324
341
  fork,
325
342
  parentBlockRoot,
343
+ currentState.latestExecutionPayloadHeader.blockHash,
326
344
  safeBlockHash,
327
345
  finalizedBlockHash ?? ZERO_HASH_HEX,
328
346
  currentState,
@@ -431,6 +449,7 @@ export async function produceBlockBody<T extends BlockType>(
431
449
  this.logger,
432
450
  fork,
433
451
  parentBlockRoot,
452
+ currentState.latestExecutionPayloadHeader.blockHash,
434
453
  safeBlockHash,
435
454
  finalizedBlockHash ?? ZERO_HASH_HEX,
436
455
  currentState,
@@ -596,17 +615,17 @@ export async function prepareExecutionPayload(
596
615
  logger: Logger,
597
616
  fork: ForkPostBellatrix,
598
617
  parentBlockRoot: Root,
618
+ parentBlockHash: Bytes32,
599
619
  safeBlockHash: RootHex,
600
620
  finalizedBlockHash: RootHex,
601
- state: IBeaconStateView,
621
+ state: IBeaconStateViewBellatrix,
602
622
  suggestedFeeRecipient: string
603
623
  ): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
604
- const parentHash = state.latestBlockHash;
605
624
  const timestamp = computeTimeAtSlot(chain.config, state.slot, state.genesisTime);
606
625
  const prevRandao = state.getRandaoMix(state.epoch);
607
626
 
608
627
  const payloadIdCached = chain.executionEngine.payloadIdCache.get({
609
- headBlockHash: toRootHex(parentHash),
628
+ headBlockHash: toRootHex(parentBlockHash),
610
629
  finalizedBlockHash,
611
630
  timestamp: numToQuantity(timestamp),
612
631
  prevRandao: toHex(prevRandao),
@@ -635,12 +654,13 @@ export async function prepareExecutionPayload(
635
654
  prepareState: state,
636
655
  prepareSlot: state.slot,
637
656
  parentBlockRoot,
657
+ parentBlockHash,
638
658
  feeRecipient: suggestedFeeRecipient,
639
659
  });
640
660
 
641
661
  payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
642
662
  fork,
643
- toRootHex(parentHash),
663
+ toRootHex(parentBlockHash),
644
664
  safeBlockHash,
645
665
  finalizedBlockHash,
646
666
  attributes
@@ -666,7 +686,7 @@ async function prepareExecutionPayloadHeader(
666
686
  config: ChainForkConfig;
667
687
  },
668
688
  fork: ForkPostBellatrix,
669
- state: IBeaconStateView,
689
+ state: IBeaconStateViewBellatrix,
670
690
  proposerPubKey: BLSPubkey
671
691
  ): Promise<{
672
692
  header: ExecutionPayloadHeader;
@@ -692,20 +712,30 @@ export function getPayloadAttributesForSSE(
692
712
  prepareState,
693
713
  prepareSlot,
694
714
  parentBlockRoot,
715
+ parentBlockHash,
695
716
  feeRecipient,
696
- }: {prepareState: IBeaconStateView; prepareSlot: Slot; parentBlockRoot: Root; feeRecipient: string}
717
+ }: {
718
+ prepareState: IBeaconStateViewBellatrix;
719
+ prepareSlot: Slot;
720
+ parentBlockRoot: Root;
721
+ parentBlockHash: Bytes32;
722
+ feeRecipient: string;
723
+ }
697
724
  ): SSEPayloadAttributes {
698
- const parentHash = prepareState.latestBlockHash;
699
725
  const payloadAttributes = preparePayloadAttributes(fork, chain, {
700
726
  prepareState,
701
727
  prepareSlot,
702
728
  parentBlockRoot,
729
+ parentBlockHash,
703
730
  feeRecipient,
704
731
  });
705
732
 
706
733
  let parentBlockNumber: number;
707
734
  if (isForkPostGloas(fork)) {
708
- const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(toRootHex(parentBlockRoot), toRootHex(parentHash));
735
+ const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
736
+ toRootHex(parentBlockRoot),
737
+ toRootHex(parentBlockHash)
738
+ );
709
739
  if (parentBlock?.executionPayloadBlockHash == null) {
710
740
  throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
711
741
  }
@@ -719,7 +749,7 @@ export function getPayloadAttributesForSSE(
719
749
  proposalSlot: prepareSlot,
720
750
  parentBlockNumber,
721
751
  parentBlockRoot,
722
- parentBlockHash: parentHash,
752
+ parentBlockHash,
723
753
  payloadAttributes,
724
754
  };
725
755
  return ssePayloadAttributes;
@@ -734,11 +764,13 @@ function preparePayloadAttributes(
734
764
  prepareState,
735
765
  prepareSlot,
736
766
  parentBlockRoot,
767
+ parentBlockHash,
737
768
  feeRecipient,
738
769
  }: {
739
- prepareState: IBeaconStateView;
770
+ prepareState: IBeaconStateViewBellatrix;
740
771
  prepareSlot: Slot;
741
772
  parentBlockRoot: Root;
773
+ parentBlockHash: Bytes32;
742
774
  feeRecipient: string;
743
775
  }
744
776
  ): SSEPayloadAttributes["payloadAttributes"] {
@@ -751,15 +783,34 @@ function preparePayloadAttributes(
751
783
  };
752
784
 
753
785
  if (ForkSeq[fork] >= ForkSeq.capella) {
754
- // withdrawals logic is now fork aware as it changes on electra fork post capella
755
- (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
756
- prepareState.getExpectedWithdrawals().expectedWithdrawals;
786
+ if (!isStatePostCapella(prepareState)) {
787
+ throw new Error("Expected Capella state for withdrawals");
788
+ }
789
+
790
+ if (isStatePostGloas(prepareState)) {
791
+ const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
792
+ // When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
793
+ // already deducted from CL balances but never credited on the EL (the envelope
794
+ // was not delivered). The next payload must carry those same withdrawals to
795
+ // restore CL/EL consistency, otherwise validators permanently lose that balance.
796
+ (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals = isExtendingPayload
797
+ ? prepareState.getExpectedWithdrawals().expectedWithdrawals
798
+ : prepareState.payloadExpectedWithdrawals;
799
+ } else {
800
+ // withdrawals logic is now fork aware as it changes on electra fork post capella
801
+ (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
802
+ prepareState.getExpectedWithdrawals().expectedWithdrawals;
803
+ }
757
804
  }
758
805
 
759
806
  if (ForkSeq[fork] >= ForkSeq.deneb) {
760
807
  (payloadAttributes as deneb.SSEPayloadAttributes["payloadAttributes"]).parentBeaconBlockRoot = parentBlockRoot;
761
808
  }
762
809
 
810
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
811
+ (payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
812
+ }
813
+
763
814
  return payloadAttributes;
764
815
  }
765
816