@lodestar/beacon-node 1.43.0-dev.433e692fd9 → 1.43.0-dev.4358217e12

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 (311) hide show
  1. package/lib/api/impl/beacon/blocks/index.js +7 -9
  2. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  3. package/lib/api/impl/beacon/state/utils.d.ts +2 -2
  4. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  6. package/lib/api/impl/lodestar/index.js +1 -1
  7. package/lib/api/impl/lodestar/index.js.map +1 -1
  8. package/lib/api/impl/validator/index.d.ts.map +1 -1
  9. package/lib/api/impl/validator/index.js +0 -4
  10. package/lib/api/impl/validator/index.js.map +1 -1
  11. package/lib/chain/GetBlobsTracker.d.ts +1 -1
  12. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  13. package/lib/chain/GetBlobsTracker.js +1 -2
  14. package/lib/chain/GetBlobsTracker.js.map +1 -1
  15. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  16. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  17. package/lib/chain/archiveStore/interface.d.ts +4 -4
  18. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  19. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
  20. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
  21. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
  22. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +2 -2
  23. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  24. package/lib/chain/archiveStore/utils/archiveBlocks.js +110 -58
  25. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  26. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  27. package/lib/chain/blocks/importBlock.js +9 -10
  28. package/lib/chain/blocks/importBlock.js.map +1 -1
  29. package/lib/chain/blocks/importExecutionPayload.d.ts +26 -13
  30. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  31. package/lib/chain/blocks/importExecutionPayload.js +86 -84
  32. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  33. package/lib/chain/blocks/index.d.ts +5 -3
  34. package/lib/chain/blocks/index.d.ts.map +1 -1
  35. package/lib/chain/blocks/index.js +28 -10
  36. package/lib/chain/blocks/index.js.map +1 -1
  37. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +3 -0
  38. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  39. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +20 -0
  40. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  41. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -0
  42. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  43. package/lib/chain/blocks/payloadEnvelopeProcessor.js +7 -5
  44. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  45. package/lib/chain/blocks/types.d.ts +14 -20
  46. package/lib/chain/blocks/types.d.ts.map +1 -1
  47. package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
  48. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  49. package/lib/chain/blocks/utils/chainSegment.js +81 -12
  50. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  51. package/lib/chain/blocks/verifyBlock.d.ts +3 -2
  52. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  53. package/lib/chain/blocks/verifyBlock.js +30 -5
  54. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  55. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  56. package/lib/chain/blocks/verifyBlocksSanityChecks.js +15 -4
  57. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  58. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
  59. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
  60. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +76 -0
  61. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
  62. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +14 -0
  63. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -0
  64. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +25 -0
  65. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -0
  66. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
  67. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
  68. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
  69. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  70. package/lib/chain/chain.d.ts +8 -6
  71. package/lib/chain/chain.d.ts.map +1 -1
  72. package/lib/chain/chain.js +19 -6
  73. package/lib/chain/chain.js.map +1 -1
  74. package/lib/chain/emitter.d.ts +16 -4
  75. package/lib/chain/emitter.d.ts.map +1 -1
  76. package/lib/chain/emitter.js +5 -0
  77. package/lib/chain/emitter.js.map +1 -1
  78. package/lib/chain/errors/blockError.d.ts +8 -1
  79. package/lib/chain/errors/blockError.d.ts.map +1 -1
  80. package/lib/chain/errors/blockError.js +2 -0
  81. package/lib/chain/errors/blockError.js.map +1 -1
  82. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  83. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  84. package/lib/chain/errors/executionPayloadBid.js +1 -0
  85. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  86. package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
  87. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  88. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  89. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  90. package/lib/chain/errors/index.d.ts +1 -0
  91. package/lib/chain/errors/index.d.ts.map +1 -1
  92. package/lib/chain/errors/index.js +1 -0
  93. package/lib/chain/errors/index.js.map +1 -1
  94. package/lib/chain/errors/proposerPreferences.d.ts +33 -0
  95. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  96. package/lib/chain/errors/proposerPreferences.js +13 -0
  97. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  98. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  99. package/lib/chain/forkChoice/index.js +11 -19
  100. package/lib/chain/forkChoice/index.js.map +1 -1
  101. package/lib/chain/interface.d.ts +7 -5
  102. package/lib/chain/interface.d.ts.map +1 -1
  103. package/lib/chain/interface.js.map +1 -1
  104. package/lib/chain/opPools/payloadAttestationPool.d.ts +2 -2
  105. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  106. package/lib/chain/opPools/payloadAttestationPool.js +4 -4
  107. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  108. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  109. package/lib/chain/prepareNextSlot.js +46 -16
  110. package/lib/chain/prepareNextSlot.js.map +1 -1
  111. package/lib/chain/produceBlock/produceBlockBody.d.ts +4 -2
  112. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  113. package/lib/chain/produceBlock/produceBlockBody.js +56 -26
  114. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  115. package/lib/chain/regen/interface.d.ts +1 -0
  116. package/lib/chain/regen/interface.d.ts.map +1 -1
  117. package/lib/chain/regen/interface.js +1 -0
  118. package/lib/chain/regen/interface.js.map +1 -1
  119. package/lib/chain/seenCache/index.d.ts +1 -0
  120. package/lib/chain/seenCache/index.d.ts.map +1 -1
  121. package/lib/chain/seenCache/index.js +1 -0
  122. package/lib/chain/seenCache/index.js.map +1 -1
  123. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +11 -4
  124. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  125. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +20 -18
  126. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  127. package/lib/chain/seenCache/seenProposerPreferences.d.ts +15 -0
  128. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  129. package/lib/chain/seenCache/seenProposerPreferences.js +25 -0
  130. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  131. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  132. package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -1
  133. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  134. package/lib/chain/validation/block.d.ts.map +1 -1
  135. package/lib/chain/validation/block.js +1 -0
  136. package/lib/chain/validation/block.js.map +1 -1
  137. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  138. package/lib/chain/validation/executionPayloadBid.js +13 -1
  139. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  140. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  141. package/lib/chain/validation/executionPayloadEnvelope.js +19 -9
  142. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  143. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  144. package/lib/chain/validation/payloadAttestationMessage.js +4 -3
  145. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  146. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  147. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  148. package/lib/chain/validation/proposerPreferences.js +69 -0
  149. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  150. package/lib/db/repositories/executionPayloadEnvelopeArchive.js +1 -1
  151. package/lib/db/repositories/executionPayloadEnvelopeArchive.js.map +1 -1
  152. package/lib/execution/engine/http.d.ts.map +1 -1
  153. package/lib/execution/engine/http.js +21 -14
  154. package/lib/execution/engine/http.js.map +1 -1
  155. package/lib/execution/engine/interface.d.ts +1 -0
  156. package/lib/execution/engine/interface.d.ts.map +1 -1
  157. package/lib/execution/engine/mock.d.ts.map +1 -1
  158. package/lib/execution/engine/mock.js +6 -0
  159. package/lib/execution/engine/mock.js.map +1 -1
  160. package/lib/execution/engine/types.d.ts +20 -0
  161. package/lib/execution/engine/types.d.ts.map +1 -1
  162. package/lib/execution/engine/types.js +18 -0
  163. package/lib/execution/engine/types.js.map +1 -1
  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 +11 -2
  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/network.js +1 -1
  180. package/lib/network/network.js.map +1 -1
  181. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  182. package/lib/network/processor/gossipHandlers.js +32 -12
  183. package/lib/network/processor/gossipHandlers.js.map +1 -1
  184. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  185. package/lib/network/processor/gossipQueues/index.js +5 -0
  186. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  187. package/lib/network/processor/index.d.ts.map +1 -1
  188. package/lib/network/processor/index.js +1 -0
  189. package/lib/network/processor/index.js.map +1 -1
  190. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  191. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  192. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  193. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  194. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  195. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  196. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  197. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  198. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  199. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  200. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  201. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  202. package/lib/node/nodejs.d.ts.map +1 -1
  203. package/lib/node/nodejs.js +4 -2
  204. package/lib/node/nodejs.js.map +1 -1
  205. package/lib/node/notifier.js +7 -1
  206. package/lib/node/notifier.js.map +1 -1
  207. package/lib/sync/range/batch.d.ts +12 -2
  208. package/lib/sync/range/batch.d.ts.map +1 -1
  209. package/lib/sync/range/batch.js +56 -30
  210. package/lib/sync/range/batch.js.map +1 -1
  211. package/lib/sync/range/chain.d.ts +6 -2
  212. package/lib/sync/range/chain.d.ts.map +1 -1
  213. package/lib/sync/range/chain.js +4 -3
  214. package/lib/sync/range/chain.js.map +1 -1
  215. package/lib/sync/range/range.d.ts.map +1 -1
  216. package/lib/sync/range/range.js +17 -6
  217. package/lib/sync/range/range.js.map +1 -1
  218. package/lib/sync/types.d.ts +34 -0
  219. package/lib/sync/types.d.ts.map +1 -1
  220. package/lib/sync/types.js +34 -0
  221. package/lib/sync/types.js.map +1 -1
  222. package/lib/sync/unknownBlock.d.ts +24 -1
  223. package/lib/sync/unknownBlock.d.ts.map +1 -1
  224. package/lib/sync/unknownBlock.js +649 -53
  225. package/lib/sync/unknownBlock.js.map +1 -1
  226. package/lib/sync/utils/downloadByRange.d.ts +46 -10
  227. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  228. package/lib/sync/utils/downloadByRange.js +147 -24
  229. package/lib/sync/utils/downloadByRange.js.map +1 -1
  230. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  231. package/lib/sync/utils/downloadByRoot.js +6 -2
  232. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  233. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  234. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  235. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  236. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  237. package/lib/util/sszBytes.d.ts.map +1 -1
  238. package/lib/util/sszBytes.js +16 -3
  239. package/lib/util/sszBytes.js.map +1 -1
  240. package/package.json +17 -16
  241. package/src/api/impl/beacon/blocks/index.ts +9 -9
  242. package/src/api/impl/beacon/state/utils.ts +2 -2
  243. package/src/api/impl/lodestar/index.ts +1 -1
  244. package/src/api/impl/validator/index.ts +0 -4
  245. package/src/chain/GetBlobsTracker.ts +1 -2
  246. package/src/chain/archiveStore/archiveStore.ts +5 -5
  247. package/src/chain/archiveStore/interface.ts +4 -4
  248. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +4 -4
  249. package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
  250. package/src/chain/blocks/importBlock.ts +7 -13
  251. package/src/chain/blocks/importExecutionPayload.ts +106 -103
  252. package/src/chain/blocks/index.ts +44 -13
  253. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +27 -0
  254. package/src/chain/blocks/payloadEnvelopeProcessor.ts +7 -6
  255. package/src/chain/blocks/types.ts +14 -25
  256. package/src/chain/blocks/utils/chainSegment.ts +106 -17
  257. package/src/chain/blocks/verifyBlock.ts +35 -6
  258. package/src/chain/blocks/verifyBlocksSanityChecks.ts +16 -7
  259. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
  260. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +38 -0
  261. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  262. package/src/chain/chain.ts +36 -19
  263. package/src/chain/emitter.ts +15 -3
  264. package/src/chain/errors/blockError.ts +4 -1
  265. package/src/chain/errors/executionPayloadBid.ts +6 -0
  266. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  267. package/src/chain/errors/index.ts +1 -0
  268. package/src/chain/errors/proposerPreferences.ts +39 -0
  269. package/src/chain/forkChoice/index.ts +8 -24
  270. package/src/chain/interface.ts +11 -3
  271. package/src/chain/opPools/payloadAttestationPool.ts +4 -8
  272. package/src/chain/prepareNextSlot.ts +60 -17
  273. package/src/chain/produceBlock/produceBlockBody.ts +77 -23
  274. package/src/chain/regen/interface.ts +1 -0
  275. package/src/chain/seenCache/index.ts +1 -0
  276. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +22 -20
  277. package/src/chain/seenCache/seenProposerPreferences.ts +29 -0
  278. package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
  279. package/src/chain/validation/block.ts +1 -0
  280. package/src/chain/validation/executionPayloadBid.ts +14 -0
  281. package/src/chain/validation/executionPayloadEnvelope.ts +20 -10
  282. package/src/chain/validation/payloadAttestationMessage.ts +5 -3
  283. package/src/chain/validation/proposerPreferences.ts +91 -0
  284. package/src/db/repositories/executionPayloadEnvelopeArchive.ts +1 -1
  285. package/src/execution/engine/http.ts +21 -14
  286. package/src/execution/engine/interface.ts +1 -0
  287. package/src/execution/engine/mock.ts +8 -1
  288. package/src/execution/engine/types.ts +41 -0
  289. package/src/metrics/metrics/lodestar.ts +4 -0
  290. package/src/network/gossip/interface.ts +6 -0
  291. package/src/network/gossip/scoringParameters.ts +14 -1
  292. package/src/network/gossip/topic.ts +6 -0
  293. package/src/network/network.ts +1 -1
  294. package/src/network/processor/gossipHandlers.ts +41 -16
  295. package/src/network/processor/gossipQueues/index.ts +5 -0
  296. package/src/network/processor/index.ts +1 -0
  297. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  298. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  299. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  300. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  301. package/src/node/nodejs.ts +4 -2
  302. package/src/node/notifier.ts +8 -1
  303. package/src/sync/range/batch.ts +90 -35
  304. package/src/sync/range/chain.ts +13 -5
  305. package/src/sync/range/range.ts +18 -6
  306. package/src/sync/types.ts +72 -0
  307. package/src/sync/unknownBlock.ts +810 -57
  308. package/src/sync/utils/downloadByRange.ts +256 -39
  309. package/src/sync/utils/downloadByRoot.ts +12 -2
  310. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  311. package/src/util/sszBytes.ts +21 -3
@@ -19,7 +19,6 @@ import {
19
19
  IBeaconStateView,
20
20
  type IBeaconStateViewBellatrix,
21
21
  computeTimeAtSlot,
22
- isParentBlockFull,
23
22
  isStatePostBellatrix,
24
23
  isStatePostCapella,
25
24
  isStatePostGloas,
@@ -47,9 +46,10 @@ import {
47
46
  electra,
48
47
  fulu,
49
48
  gloas,
49
+ ssz,
50
50
  } from "@lodestar/types";
51
- import {Logger, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
52
- import {ZERO_HASH_HEX} from "../../constants/index.js";
51
+ import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
52
+ import {ZERO_HASH, ZERO_HASH_HEX} from "../../constants/index.js";
53
53
  import {numToQuantity} from "../../execution/engine/utils.js";
54
54
  import {
55
55
  IExecutionBuilder,
@@ -214,15 +214,30 @@ export async function produceBlockBody<T extends BlockType>(
214
214
  });
215
215
 
216
216
  // Get execution payload from EL
217
+ const isExtendingPayload = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot));
218
+ let parentBlockHash = isExtendingPayload
219
+ ? currentState.latestExecutionPayloadBid.blockHash
220
+ : currentState.latestExecutionPayloadBid.parentBlockHash;
221
+ // At gloas genesis the committed bid has no prior EL block to reference
222
+ // (`bid.parentBlockHash` is zero). Fall back to `bid.blockHash` (= eth1 genesis hash) so the
223
+ // FCU to the EL carries a valid head. Post-genesis bids always reference a non-zero parent.
224
+ if (isStatePostGloas(currentState) && byteArrayEquals(parentBlockHash, ZERO_HASH)) {
225
+ parentBlockHash = currentState.latestExecutionPayloadBid.blockHash;
226
+ }
227
+ const parentExecutionRequests = isExtendingPayload
228
+ ? await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot)
229
+ : ssz.electra.ExecutionRequests.defaultValue();
217
230
  const prepareRes = await prepareExecutionPayload(
218
231
  this,
219
232
  this.logger,
220
233
  fork,
221
234
  parentBlockRoot,
235
+ parentBlockHash,
222
236
  safeBlockHash,
223
237
  finalizedBlockHash ?? ZERO_HASH_HEX,
224
238
  currentState,
225
- feeRecipient
239
+ feeRecipient,
240
+ parentExecutionRequests
226
241
  );
227
242
 
228
243
  const {prepType, payloadId} = prepareRes;
@@ -255,8 +270,8 @@ export async function produceBlockBody<T extends BlockType>(
255
270
 
256
271
  // Create self-build execution payload bid
257
272
  const bid: gloas.ExecutionPayloadBid = {
258
- parentBlockHash: currentState.latestBlockHash,
259
- parentBlockRoot: parentBlockRoot,
273
+ parentBlockHash,
274
+ parentBlockRoot,
260
275
  blockHash: executionPayload.blockHash,
261
276
  prevRandao: currentState.getRandaoMix(currentState.epoch),
262
277
  feeRecipient: executionPayload.feeRecipient,
@@ -266,6 +281,7 @@ export async function produceBlockBody<T extends BlockType>(
266
281
  value: 0,
267
282
  executionPayment: 0,
268
283
  blobKzgCommitments: blobsBundle.commitments,
284
+ executionRequestsRoot: ssz.electra.ExecutionRequests.hashTreeRoot(executionRequests),
269
285
  };
270
286
  const signedBid: gloas.SignedExecutionPayloadBid = {
271
287
  message: bid,
@@ -275,8 +291,11 @@ export async function produceBlockBody<T extends BlockType>(
275
291
  const commonBlockBody = await commonBlockBodyPromise;
276
292
  const gloasBody = Object.assign({}, commonBlockBody) as gloas.BeaconBlockBody;
277
293
  gloasBody.signedExecutionPayloadBid = signedBid;
278
- // TODO GLOAS: Get payload attestations from pool for previous slot
279
- gloasBody.payloadAttestations = [];
294
+ gloasBody.payloadAttestations = this.payloadAttestationPool.getPayloadAttestationsForBlock(
295
+ parentBlock.blockRoot,
296
+ blockSlot - 1
297
+ );
298
+ gloasBody.parentExecutionRequests = parentExecutionRequests;
280
299
  blockBody = gloasBody as AssembledBodyType<T>;
281
300
 
282
301
  // Store execution payload data required to construct execution payload envelope later
@@ -334,6 +353,7 @@ export async function produceBlockBody<T extends BlockType>(
334
353
  this.logger,
335
354
  fork,
336
355
  parentBlockRoot,
356
+ currentState.latestExecutionPayloadHeader.blockHash,
337
357
  safeBlockHash,
338
358
  finalizedBlockHash ?? ZERO_HASH_HEX,
339
359
  currentState,
@@ -442,6 +462,7 @@ export async function produceBlockBody<T extends BlockType>(
442
462
  this.logger,
443
463
  fork,
444
464
  parentBlockRoot,
465
+ currentState.latestExecutionPayloadHeader.blockHash,
445
466
  safeBlockHash,
446
467
  finalizedBlockHash ?? ZERO_HASH_HEX,
447
468
  currentState,
@@ -607,17 +628,18 @@ export async function prepareExecutionPayload(
607
628
  logger: Logger,
608
629
  fork: ForkPostBellatrix,
609
630
  parentBlockRoot: Root,
631
+ parentBlockHash: Bytes32,
610
632
  safeBlockHash: RootHex,
611
633
  finalizedBlockHash: RootHex,
612
634
  state: IBeaconStateViewBellatrix,
613
- suggestedFeeRecipient: string
635
+ suggestedFeeRecipient: string,
636
+ parentExecutionRequests?: electra.ExecutionRequests
614
637
  ): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
615
- const parentHash = state.latestBlockHash;
616
638
  const timestamp = computeTimeAtSlot(chain.config, state.slot, state.genesisTime);
617
639
  const prevRandao = state.getRandaoMix(state.epoch);
618
640
 
619
641
  const payloadIdCached = chain.executionEngine.payloadIdCache.get({
620
- headBlockHash: toRootHex(parentHash),
642
+ headBlockHash: toRootHex(parentBlockHash),
621
643
  finalizedBlockHash,
622
644
  timestamp: numToQuantity(timestamp),
623
645
  prevRandao: toHex(prevRandao),
@@ -646,12 +668,14 @@ export async function prepareExecutionPayload(
646
668
  prepareState: state,
647
669
  prepareSlot: state.slot,
648
670
  parentBlockRoot,
671
+ parentBlockHash,
649
672
  feeRecipient: suggestedFeeRecipient,
673
+ parentExecutionRequests,
650
674
  });
651
675
 
652
676
  payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
653
677
  fork,
654
- toRootHex(parentHash),
678
+ toRootHex(parentBlockHash),
655
679
  safeBlockHash,
656
680
  finalizedBlockHash,
657
681
  attributes
@@ -703,20 +727,33 @@ export function getPayloadAttributesForSSE(
703
727
  prepareState,
704
728
  prepareSlot,
705
729
  parentBlockRoot,
730
+ parentBlockHash,
706
731
  feeRecipient,
707
- }: {prepareState: IBeaconStateViewBellatrix; prepareSlot: Slot; parentBlockRoot: Root; feeRecipient: string}
732
+ parentExecutionRequests,
733
+ }: {
734
+ prepareState: IBeaconStateViewBellatrix;
735
+ prepareSlot: Slot;
736
+ parentBlockRoot: Root;
737
+ parentBlockHash: Bytes32;
738
+ feeRecipient: string;
739
+ parentExecutionRequests?: electra.ExecutionRequests;
740
+ }
708
741
  ): SSEPayloadAttributes {
709
- const parentHash = prepareState.latestBlockHash;
710
742
  const payloadAttributes = preparePayloadAttributes(fork, chain, {
711
743
  prepareState,
712
744
  prepareSlot,
713
745
  parentBlockRoot,
746
+ parentBlockHash,
714
747
  feeRecipient,
748
+ parentExecutionRequests,
715
749
  });
716
750
 
717
751
  let parentBlockNumber: number;
718
752
  if (isForkPostGloas(fork)) {
719
- const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(toRootHex(parentBlockRoot), toRootHex(parentHash));
753
+ const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
754
+ toRootHex(parentBlockRoot),
755
+ toRootHex(parentBlockHash)
756
+ );
720
757
  if (parentBlock?.executionPayloadBlockHash == null) {
721
758
  throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
722
759
  }
@@ -730,7 +767,7 @@ export function getPayloadAttributesForSSE(
730
767
  proposalSlot: prepareSlot,
731
768
  parentBlockNumber,
732
769
  parentBlockRoot,
733
- parentBlockHash: parentHash,
770
+ parentBlockHash,
734
771
  payloadAttributes,
735
772
  };
736
773
  return ssePayloadAttributes;
@@ -745,12 +782,16 @@ function preparePayloadAttributes(
745
782
  prepareState,
746
783
  prepareSlot,
747
784
  parentBlockRoot,
785
+ parentBlockHash,
748
786
  feeRecipient,
787
+ parentExecutionRequests,
749
788
  }: {
750
789
  prepareState: IBeaconStateViewBellatrix;
751
790
  prepareSlot: Slot;
752
791
  parentBlockRoot: Root;
792
+ parentBlockHash: Bytes32;
753
793
  feeRecipient: string;
794
+ parentExecutionRequests?: electra.ExecutionRequests;
754
795
  }
755
796
  ): SSEPayloadAttributes["payloadAttributes"] {
756
797
  const timestamp = computeTimeAtSlot(chain.config, prepareSlot, prepareState.genesisTime);
@@ -766,13 +807,22 @@ function preparePayloadAttributes(
766
807
  throw new Error("Expected Capella state for withdrawals");
767
808
  }
768
809
 
769
- if (isStatePostGloas(prepareState) && !isParentBlockFull(prepareState)) {
770
- // When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
771
- // already deducted from CL balances but never credited on the EL (the envelope
772
- // was not delivered). The next payload must carry those same withdrawals to
773
- // restore CL/EL consistency, otherwise validators permanently lose that balance.
774
- (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
775
- prepareState.payloadExpectedWithdrawals;
810
+ if (isStatePostGloas(prepareState)) {
811
+ const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
812
+ if (isExtendingPayload) {
813
+ if (parentExecutionRequests === undefined) {
814
+ throw new Error("parentExecutionRequests required when extending full parent");
815
+ }
816
+ (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
817
+ prepareState.getExpectedWithdrawalsForFullParent(parentExecutionRequests);
818
+ } else {
819
+ // When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
820
+ // already deducted from CL balances but never credited on the EL (the envelope
821
+ // was not delivered). The next payload must carry those same withdrawals to
822
+ // restore CL/EL consistency, otherwise validators permanently lose that balance.
823
+ (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
824
+ prepareState.payloadExpectedWithdrawals;
825
+ }
776
826
  } else {
777
827
  // withdrawals logic is now fork aware as it changes on electra fork post capella
778
828
  (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
@@ -784,6 +834,10 @@ function preparePayloadAttributes(
784
834
  (payloadAttributes as deneb.SSEPayloadAttributes["payloadAttributes"]).parentBeaconBlockRoot = parentBlockRoot;
785
835
  }
786
836
 
837
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
838
+ (payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
839
+ }
840
+
787
841
  return payloadAttributes;
788
842
  }
789
843
 
@@ -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
  }
@@ -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,6 +1,6 @@
1
1
  import {CheckpointWithHex} from "@lodestar/fork-choice";
2
2
  import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
3
- import {RootHex} from "@lodestar/types";
3
+ import {RootHex, Slot} from "@lodestar/types";
4
4
  import {Logger} from "@lodestar/utils";
5
5
  import {Metrics} from "../../metrics/metrics.js";
6
6
  import {SerializedCache} from "../../util/serializedCache.js";
@@ -21,8 +21,15 @@ export type SeenPayloadEnvelopeInputModules = {
21
21
  /**
22
22
  * Cache for tracking PayloadEnvelopeInput instances, keyed by beacon block root.
23
23
  *
24
- * Created during block import when a block is processed.
25
- * Pruned on finalization and after payload is written to DB.
24
+ * Created during block import when a block is processed. Two pruning paths:
25
+ * - `prepareNextSlot` calls `pruneBelow(headParentSlot)` every slot once the head we'll build
26
+ * on is known.
27
+ * - `onFinalized` calls `pruneBelow(finalizedSlot)` on every finalization for bulk cleanup.
28
+ *
29
+ * Steady state (linear chain, healthy progression): the cache holds ~2 entries — the head
30
+ * (parent for next-slot production) and its parent (proposer-boost-reorg fallback). It can
31
+ * transiently hold more during forks, range-sync bursts, or when `prepareNextSlot` skips
32
+ * ticks; subsequent ticks settle it back.
26
33
  */
27
34
  export class SeenPayloadEnvelopeInput {
28
35
  private readonly chainEvents: ChainEventEmitter;
@@ -58,16 +65,7 @@ export class SeenPayloadEnvelopeInput {
58
65
  }
59
66
 
60
67
  private onFinalized = (checkpoint: CheckpointWithHex): void => {
61
- // Prune all entries with slot < finalized slot
62
- const finalizedSlot = computeStartSlotAtEpoch(checkpoint.epoch);
63
- let deletedCount = 0;
64
- for (const [, input] of this.payloadInputs) {
65
- if (input.slot < finalizedSlot) {
66
- this.evictPayloadInput(input);
67
- deletedCount++;
68
- }
69
- }
70
- this.logger?.debug("SeenPayloadEnvelopeInput.onFinalized deleted cached entries", {deletedCount});
68
+ this.pruneBelow(computeStartSlotAtEpoch(checkpoint.epoch));
71
69
  };
72
70
 
73
71
  add(props: CreateFromBlockProps): PayloadEnvelopeInput {
@@ -88,17 +86,21 @@ export class SeenPayloadEnvelopeInput {
88
86
  return this.payloadInputs.get(blockRootHex)?.hasPayloadEnvelope() ?? false;
89
87
  }
90
88
 
91
- prune(blockRootHex: RootHex): void {
92
- const payloadInput = this.payloadInputs.get(blockRootHex);
93
- if (payloadInput) {
94
- this.evictPayloadInput(payloadInput);
95
- }
96
- }
97
-
98
89
  size(): number {
99
90
  return this.payloadInputs.size;
100
91
  }
101
92
 
93
+ pruneBelow(slot: Slot): void {
94
+ let deletedCount = 0;
95
+ for (const [, input] of this.payloadInputs) {
96
+ if (input.slot < slot) {
97
+ this.evictPayloadInput(input);
98
+ deletedCount++;
99
+ }
100
+ }
101
+ this.logger?.debug("SeenPayloadEnvelopeInput.pruneBelow deleted entries", {slot, deletedCount});
102
+ }
103
+
102
104
  private evictPayloadInput(payloadInput: PayloadEnvelopeInput): void {
103
105
  this.serializedCache.delete(payloadInput.getSerializedCacheKeys());
104
106
  this.payloadInputs.delete(payloadInput.blockRootHex);
@@ -0,0 +1,29 @@
1
+ import {Slot, ValidatorIndex} from "@lodestar/types";
2
+ import {MapDef} from "@lodestar/utils";
3
+
4
+ /**
5
+ * Tracks signed proposer preferences we've already seen per (proposal_slot, validator_index).
6
+ */
7
+ export class SeenProposerPreferences {
8
+ private readonly validatorIndexesBySlot = new MapDef<Slot, Set<ValidatorIndex>>(() => new Set<ValidatorIndex>());
9
+
10
+ isKnown(proposalSlot: Slot, validatorIndex: ValidatorIndex): boolean {
11
+ return this.validatorIndexesBySlot.get(proposalSlot)?.has(validatorIndex) === true;
12
+ }
13
+
14
+ add(proposalSlot: Slot, validatorIndex: ValidatorIndex): void {
15
+ this.validatorIndexesBySlot.getOrDefault(proposalSlot).add(validatorIndex);
16
+ }
17
+
18
+ /**
19
+ * Entries are only load-bearing while `proposal_slot > state.slot`. Once the slot has passed the
20
+ * `[IGNORE] proposal_slot > state.slot` gossip rule takes over, so drop them on each slot tick.
21
+ */
22
+ prune(currentSlot: Slot): void {
23
+ for (const slot of this.validatorIndexesBySlot.keys()) {
24
+ if (slot < currentSlot) {
25
+ this.validatorIndexesBySlot.delete(slot);
26
+ }
27
+ }
28
+ }
29
+ }
@@ -226,7 +226,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
226
226
  }
227
227
  sszTimer?.();
228
228
  const timer = this.metrics?.cpStateCache.stateReloadDuration.startTimer();
229
- const newCachedState = seedState.loadOtherState(stateBytes, validatorsBytes);
229
+ // preload validators and balances for faster state transition
230
+ const newCachedState = seedState.loadOtherState(stateBytes, validatorsBytes, {
231
+ preloadValidatorsAndBalances: true,
232
+ });
230
233
  // hashTreeRoot() calls the commit() inside
231
234
  // there is no modification inside the state, it's just that we want to compute and cache all roots
232
235
  const stateRoot = toRootHex(newCachedState.hashTreeRoot());
@@ -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,
@@ -76,6 +77,19 @@ async function validateExecutionPayloadBid(
76
77
  // `SignedProposerPreferences` associated with `bid.slot`.
77
78
  // TODO GLOAS: Implement this along with proposer preference
78
79
 
80
+ // [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
81
+ // consensus layer -- i.e. validate that
82
+ // `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
83
+ const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
84
+ const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
85
+ if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
86
+ throw new ExecutionPayloadBidError(GossipAction.REJECT, {
87
+ code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
88
+ blobKzgCommitmentsLen,
89
+ commitmentLimit: maxBlobsPerBlock,
90
+ });
91
+ }
92
+
79
93
  // [IGNORE] this is the first signed bid seen with a valid signature from the given builder for this slot.
80
94
  if (chain.seenExecutionPayloadBids.isKnown(bid.slot, bid.builderIndex)) {
81
95
  throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
@@ -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";
@@ -53,7 +53,7 @@ async function validateExecutionPayloadEnvelope(
53
53
  throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
54
54
  code: ExecutionPayloadEnvelopeErrorCode.ENVELOPE_ALREADY_KNOWN,
55
55
  blockRoot: blockRootHex,
56
- slot: envelope.slot,
56
+ slot: payload.slotNumber,
57
57
  });
58
58
  }
59
59
 
@@ -65,13 +65,13 @@ async function validateExecutionPayloadEnvelope(
65
65
  });
66
66
  }
67
67
 
68
- // [IGNORE] The envelope is from a slot greater than or equal to the latest finalized slot -- i.e. validate that `envelope.slot >= compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)`
68
+ // [IGNORE] The envelope is from a slot greater than or equal to the latest finalized slot -- i.e. validate that `payload.slotNumber >= compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)`
69
69
  const finalizedCheckpoint = chain.forkChoice.getFinalizedCheckpoint();
70
70
  const finalizedSlot = computeStartSlotAtEpoch(finalizedCheckpoint.epoch);
71
- if (envelope.slot < finalizedSlot) {
71
+ if (payload.slotNumber < finalizedSlot) {
72
72
  throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
73
73
  code: ExecutionPayloadEnvelopeErrorCode.BELONG_TO_FINALIZED_BLOCK,
74
- envelopeSlot: envelope.slot,
74
+ envelopeSlot: payload.slotNumber,
75
75
  finalizedSlot,
76
76
  });
77
77
  }
@@ -80,11 +80,11 @@ async function validateExecutionPayloadEnvelope(
80
80
  // TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
81
81
  // it is possible that the block didn't pass the validation
82
82
 
83
- // [REJECT] `block.slot` equals `envelope.slot`.
84
- if (block.slot !== envelope.slot) {
83
+ // [REJECT] `block.slot` equals `payload.slotNumber`.
84
+ if (block.slot !== payload.slotNumber) {
85
85
  throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
86
86
  code: ExecutionPayloadEnvelopeErrorCode.SLOT_MISMATCH,
87
- envelopeSlot: envelope.slot,
87
+ envelopeSlot: payload.slotNumber,
88
88
  blockSlot: block.slot,
89
89
  });
90
90
  }
@@ -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)
@@ -114,7 +124,7 @@ async function validateExecutionPayloadEnvelope(
114
124
  throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
115
125
  code: ExecutionPayloadEnvelopeErrorCode.UNKNOWN_BLOCK_STATE,
116
126
  blockRoot: blockRootHex,
117
- slot: envelope.slot,
127
+ slot: payload.slotNumber,
118
128
  });
119
129
  });
120
130
  if (!isStatePostGloas(blockState)) {
@@ -18,7 +18,8 @@ export async function validateApiPayloadAttestationMessage(
18
18
  chain: IBeaconChain,
19
19
  payloadAttestationMessage: gloas.PayloadAttestationMessage
20
20
  ): Promise<PayloadAttestationValidationResult> {
21
- return validatePayloadAttestationMessage(chain, payloadAttestationMessage);
21
+ const prioritizeBls = true;
22
+ return validatePayloadAttestationMessage(chain, payloadAttestationMessage, prioritizeBls);
22
23
  }
23
24
 
24
25
  export async function validateGossipPayloadAttestationMessage(
@@ -30,7 +31,8 @@ export async function validateGossipPayloadAttestationMessage(
30
31
 
31
32
  async function validatePayloadAttestationMessage(
32
33
  chain: IBeaconChain,
33
- payloadAttestationMessage: gloas.PayloadAttestationMessage
34
+ payloadAttestationMessage: gloas.PayloadAttestationMessage,
35
+ prioritizeBls = false
34
36
  ): Promise<PayloadAttestationValidationResult> {
35
37
  const {data, validatorIndex} = payloadAttestationMessage;
36
38
  const epoch = computeEpochAtSlot(data.slot);
@@ -102,7 +104,7 @@ async function validatePayloadAttestationMessage(
102
104
  payloadAttestationMessage.signature
103
105
  );
104
106
 
105
- if (!(await chain.bls.verifySignatureSets([signatureSet]))) {
107
+ if (!(await chain.bls.verifySignatureSets([signatureSet], {batchable: true, priority: prioritizeBls}))) {
106
108
  throw new PayloadAttestationError(GossipAction.REJECT, {
107
109
  code: PayloadAttestationErrorCode.INVALID_SIGNATURE,
108
110
  });
@@ -0,0 +1,91 @@
1
+ import {SLOTS_PER_EPOCH} from "@lodestar/params";
2
+ import {
3
+ computeEpochAtSlot,
4
+ createSingleSignatureSetFromComponents,
5
+ getProposerPreferencesSigningRoot,
6
+ isStatePostGloas,
7
+ } from "@lodestar/state-transition";
8
+ import {gloas} from "@lodestar/types";
9
+ import {GossipAction, ProposerPreferencesError, ProposerPreferencesErrorCode} from "../errors/index.js";
10
+ import {IBeaconChain} from "../index.js";
11
+ import {RegenCaller} from "../regen/index.js";
12
+
13
+ /**
14
+ * Validates a gossiped `SignedProposerPreferences` per
15
+ * https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/p2p-interface.md#proposer_preferences
16
+ */
17
+ export async function validateGossipProposerPreferences(
18
+ chain: IBeaconChain,
19
+ signedProposerPreferences: gloas.SignedProposerPreferences
20
+ ): Promise<void> {
21
+ const preferences = signedProposerPreferences.message;
22
+ const {proposalSlot, validatorIndex} = preferences;
23
+ const proposalEpoch = computeEpochAtSlot(proposalSlot);
24
+
25
+ // [IGNORE] `preferences.proposal_slot` is in the current or next epoch.
26
+ const currentEpoch = chain.clock.currentEpoch;
27
+ if (proposalEpoch < currentEpoch || proposalEpoch > currentEpoch + 1) {
28
+ throw new ProposerPreferencesError(GossipAction.IGNORE, {
29
+ code: ProposerPreferencesErrorCode.INVALID_EPOCH,
30
+ proposalSlot,
31
+ currentEpoch,
32
+ });
33
+ }
34
+
35
+ // [IGNORE] `preferences.proposal_slot` has not already passed.
36
+ const currentSlot = chain.clock.currentSlot;
37
+ if (proposalSlot <= currentSlot) {
38
+ throw new ProposerPreferencesError(GossipAction.IGNORE, {
39
+ code: ProposerPreferencesErrorCode.PROPOSAL_SLOT_PASSED,
40
+ proposalSlot,
41
+ currentSlot,
42
+ });
43
+ }
44
+
45
+ const state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.validateGossipProposerPreferences);
46
+ if (!isStatePostGloas(state)) {
47
+ throw new Error(`Expected gloas+ state for proposer preferences validation, got fork=${state.forkName}`);
48
+ }
49
+
50
+ // [REJECT] `preferences.validator_index` is present at the correct slot in the current or next
51
+ // epoch's portion of `state.proposer_lookahead` — i.e. `is_valid_proposal_slot(state, preferences)`
52
+ // returns True.
53
+ const epochOffset = proposalEpoch - state.epoch;
54
+ const proposers = epochOffset === 0 ? state.currentProposers : state.nextProposers;
55
+ const expectedProposer = proposers[proposalSlot % SLOTS_PER_EPOCH];
56
+ if (epochOffset < 0 || epochOffset > 1 || expectedProposer !== validatorIndex) {
57
+ throw new ProposerPreferencesError(GossipAction.REJECT, {
58
+ code: ProposerPreferencesErrorCode.INVALID_PROPOSER,
59
+ proposalSlot,
60
+ validatorIndex,
61
+ });
62
+ }
63
+
64
+ // [IGNORE] The `signed_proposer_preferences` is the first valid message received from the validator
65
+ // with index `preferences.validator_index` and the given slot `preferences.proposal_slot`.
66
+ if (chain.seenProposerPreferences.isKnown(proposalSlot, validatorIndex)) {
67
+ throw new ProposerPreferencesError(GossipAction.IGNORE, {
68
+ code: ProposerPreferencesErrorCode.ALREADY_KNOWN,
69
+ proposalSlot,
70
+ validatorIndex,
71
+ });
72
+ }
73
+
74
+ // [REJECT] `signed_proposer_preferences.signature` is valid with respect to the validator's public key.
75
+ const signatureSet = createSingleSignatureSetFromComponents(
76
+ chain.pubkeyCache.getOrThrow(validatorIndex),
77
+ getProposerPreferencesSigningRoot(chain.config, preferences),
78
+ signedProposerPreferences.signature
79
+ );
80
+
81
+ if (!(await chain.bls.verifySignatureSets([signatureSet], {batchable: true}))) {
82
+ throw new ProposerPreferencesError(GossipAction.REJECT, {
83
+ code: ProposerPreferencesErrorCode.INVALID_SIGNATURE,
84
+ proposalSlot,
85
+ validatorIndex,
86
+ });
87
+ }
88
+
89
+ // Valid
90
+ chain.seenProposerPreferences.add(proposalSlot, validatorIndex);
91
+ }
@@ -19,7 +19,7 @@ export class ExecutionPayloadEnvelopeArchiveRepository extends Repository<Slot,
19
19
  * Id is the slot from the envelope
20
20
  */
21
21
  getId(value: gloas.SignedExecutionPayloadEnvelope): Slot {
22
- return value.message.slot;
22
+ return value.message.payload.slotNumber;
23
23
  }
24
24
 
25
25
  encodeKey(id: Slot): Uint8Array {