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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +16 -5
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +86 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/debug/index.d.ts.map +1 -1
  8. package/lib/api/impl/debug/index.js +0 -1
  9. package/lib/api/impl/debug/index.js.map +1 -1
  10. package/lib/api/impl/lodestar/index.js +1 -1
  11. package/lib/api/impl/lodestar/index.js.map +1 -1
  12. package/lib/api/impl/validator/index.d.ts.map +1 -1
  13. package/lib/api/impl/validator/index.js +85 -12
  14. package/lib/api/impl/validator/index.js.map +1 -1
  15. package/lib/chain/blocks/blockInput/blockInput.d.ts +3 -0
  16. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  17. package/lib/chain/blocks/blockInput/blockInput.js +4 -1
  18. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  19. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  20. package/lib/chain/blocks/importBlock.js +16 -28
  21. package/lib/chain/blocks/importBlock.js.map +1 -1
  22. package/lib/chain/blocks/importExecutionPayload.d.ts +23 -6
  23. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  24. package/lib/chain/blocks/importExecutionPayload.js +57 -24
  25. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  26. package/lib/chain/blocks/index.d.ts +5 -3
  27. package/lib/chain/blocks/index.d.ts.map +1 -1
  28. package/lib/chain/blocks/index.js +58 -25
  29. package/lib/chain/blocks/index.js.map +1 -1
  30. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +12 -1
  31. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  32. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +28 -2
  33. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  34. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +17 -0
  35. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  36. package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
  37. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  38. package/lib/chain/blocks/types.d.ts +4 -3
  39. package/lib/chain/blocks/types.d.ts.map +1 -1
  40. package/lib/chain/blocks/utils/chainSegment.d.ts +21 -2
  41. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  42. package/lib/chain/blocks/utils/chainSegment.js +92 -12
  43. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  44. package/lib/chain/blocks/verifyBlock.d.ts +5 -3
  45. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  46. package/lib/chain/blocks/verifyBlock.js +50 -7
  47. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  48. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
  49. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  50. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
  51. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  52. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
  53. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  54. package/lib/chain/blocks/verifyBlocksSanityChecks.js +25 -5
  55. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  56. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  57. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  58. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +12 -8
  59. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  60. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  61. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
  62. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  63. package/lib/chain/chain.d.ts +5 -3
  64. package/lib/chain/chain.d.ts.map +1 -1
  65. package/lib/chain/chain.js +38 -13
  66. package/lib/chain/chain.js.map +1 -1
  67. package/lib/chain/emitter.d.ts +0 -11
  68. package/lib/chain/emitter.d.ts.map +1 -1
  69. package/lib/chain/emitter.js +0 -4
  70. package/lib/chain/emitter.js.map +1 -1
  71. package/lib/chain/errors/blockError.d.ts +8 -1
  72. package/lib/chain/errors/blockError.d.ts.map +1 -1
  73. package/lib/chain/errors/blockError.js +2 -0
  74. package/lib/chain/errors/blockError.js.map +1 -1
  75. package/lib/chain/errors/executionPayloadBid.d.ts +19 -1
  76. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  77. package/lib/chain/errors/executionPayloadBid.js +3 -0
  78. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  79. package/lib/chain/errors/index.d.ts +1 -0
  80. package/lib/chain/errors/index.d.ts.map +1 -1
  81. package/lib/chain/errors/index.js +1 -0
  82. package/lib/chain/errors/index.js.map +1 -1
  83. package/lib/chain/errors/proposerPreferences.d.ts +40 -0
  84. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  85. package/lib/chain/errors/proposerPreferences.js +14 -0
  86. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  87. package/lib/chain/initState.d.ts.map +1 -1
  88. package/lib/chain/initState.js +6 -1
  89. package/lib/chain/initState.js.map +1 -1
  90. package/lib/chain/interface.d.ts +5 -3
  91. package/lib/chain/interface.d.ts.map +1 -1
  92. package/lib/chain/interface.js.map +1 -1
  93. package/lib/chain/lightClient/index.d.ts.map +1 -1
  94. package/lib/chain/lightClient/index.js +1 -1
  95. package/lib/chain/lightClient/index.js.map +1 -1
  96. package/lib/chain/opPools/index.d.ts +1 -0
  97. package/lib/chain/opPools/index.d.ts.map +1 -1
  98. package/lib/chain/opPools/index.js +1 -0
  99. package/lib/chain/opPools/index.js.map +1 -1
  100. package/lib/chain/opPools/payloadAttestationPool.d.ts +4 -3
  101. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  102. package/lib/chain/opPools/payloadAttestationPool.js +56 -14
  103. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  104. package/lib/chain/opPools/proposerPreferencesPool.d.ts +29 -0
  105. package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -0
  106. package/lib/chain/opPools/proposerPreferencesPool.js +56 -0
  107. package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -0
  108. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  109. package/lib/chain/prepareNextSlot.js +16 -18
  110. package/lib/chain/prepareNextSlot.js.map +1 -1
  111. package/lib/chain/produceBlock/produceBlockBody.d.ts +12 -3
  112. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  113. package/lib/chain/produceBlock/produceBlockBody.js +35 -17
  114. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  115. package/lib/chain/regen/interface.d.ts +1 -0
  116. package/lib/chain/regen/interface.d.ts.map +1 -1
  117. package/lib/chain/regen/interface.js +1 -0
  118. package/lib/chain/regen/interface.js.map +1 -1
  119. package/lib/chain/regen/queued.d.ts.map +1 -1
  120. package/lib/chain/regen/queued.js +1 -4
  121. package/lib/chain/regen/queued.js.map +1 -1
  122. package/lib/chain/regen/regen.d.ts.map +1 -1
  123. package/lib/chain/regen/regen.js +1 -4
  124. package/lib/chain/regen/regen.js.map +1 -1
  125. package/lib/chain/seenCache/index.d.ts +1 -0
  126. package/lib/chain/seenCache/index.d.ts.map +1 -1
  127. package/lib/chain/seenCache/index.js +1 -0
  128. package/lib/chain/seenCache/index.js.map +1 -1
  129. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +21 -11
  130. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  131. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +70 -20
  132. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  133. package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
  134. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  135. package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
  136. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  137. package/lib/chain/validation/block.d.ts.map +1 -1
  138. package/lib/chain/validation/block.js +1 -0
  139. package/lib/chain/validation/block.js.map +1 -1
  140. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  141. package/lib/chain/validation/executionPayloadBid.js +68 -17
  142. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  143. package/lib/chain/validation/payloadAttestationMessage.d.ts +1 -1
  144. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  145. package/lib/chain/validation/payloadAttestationMessage.js +5 -3
  146. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  147. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  148. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  149. package/lib/chain/validation/proposerPreferences.js +91 -0
  150. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  151. package/lib/metrics/metrics/lodestar.d.ts +5 -0
  152. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  153. package/lib/metrics/metrics/lodestar.js +9 -0
  154. package/lib/metrics/metrics/lodestar.js.map +1 -1
  155. package/lib/network/gossip/interface.d.ts +7 -1
  156. package/lib/network/gossip/interface.d.ts.map +1 -1
  157. package/lib/network/gossip/interface.js +1 -0
  158. package/lib/network/gossip/interface.js.map +1 -1
  159. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  160. package/lib/network/gossip/scoringParameters.js +12 -1
  161. package/lib/network/gossip/scoringParameters.js.map +1 -1
  162. package/lib/network/gossip/topic.d.ts +29 -766
  163. package/lib/network/gossip/topic.d.ts.map +1 -1
  164. package/lib/network/gossip/topic.js +6 -0
  165. package/lib/network/gossip/topic.js.map +1 -1
  166. package/lib/network/interface.d.ts +3 -0
  167. package/lib/network/interface.d.ts.map +1 -1
  168. package/lib/network/network.d.ts +3 -0
  169. package/lib/network/network.d.ts.map +1 -1
  170. package/lib/network/network.js +13 -0
  171. package/lib/network/network.js.map +1 -1
  172. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  173. package/lib/network/processor/gossipHandlers.js +77 -20
  174. package/lib/network/processor/gossipHandlers.js.map +1 -1
  175. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  176. package/lib/network/processor/gossipQueues/index.js +5 -0
  177. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  178. package/lib/network/processor/index.d.ts.map +1 -1
  179. package/lib/network/processor/index.js +6 -5
  180. package/lib/network/processor/index.js.map +1 -1
  181. package/lib/network/reqresp/ReqRespBeaconNode.d.ts.map +1 -1
  182. package/lib/network/reqresp/ReqRespBeaconNode.js +1 -1
  183. package/lib/network/reqresp/ReqRespBeaconNode.js.map +1 -1
  184. package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts +9 -0
  185. package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts.map +1 -0
  186. package/lib/network/reqresp/handlers/beaconBlocksByHead.js +61 -0
  187. package/lib/network/reqresp/handlers/beaconBlocksByHead.js.map +1 -0
  188. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  189. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  190. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  191. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  192. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  193. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  194. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  195. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  196. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  197. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  198. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  199. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  200. package/lib/network/reqresp/handlers/index.d.ts.map +1 -1
  201. package/lib/network/reqresp/handlers/index.js +5 -0
  202. package/lib/network/reqresp/handlers/index.js.map +1 -1
  203. package/lib/network/reqresp/interface.d.ts +1 -1
  204. package/lib/network/reqresp/interface.js +1 -1
  205. package/lib/network/reqresp/protocols.d.ts +1 -0
  206. package/lib/network/reqresp/protocols.d.ts.map +1 -1
  207. package/lib/network/reqresp/protocols.js +5 -0
  208. package/lib/network/reqresp/protocols.js.map +1 -1
  209. package/lib/network/reqresp/rateLimit.d.ts.map +1 -1
  210. package/lib/network/reqresp/rateLimit.js +4 -0
  211. package/lib/network/reqresp/rateLimit.js.map +1 -1
  212. package/lib/network/reqresp/score.d.ts.map +1 -1
  213. package/lib/network/reqresp/score.js +1 -0
  214. package/lib/network/reqresp/score.js.map +1 -1
  215. package/lib/network/reqresp/types.d.ts +3 -0
  216. package/lib/network/reqresp/types.d.ts.map +1 -1
  217. package/lib/network/reqresp/types.js +3 -0
  218. package/lib/network/reqresp/types.js.map +1 -1
  219. package/lib/node/nodejs.js +2 -2
  220. package/lib/node/nodejs.js.map +1 -1
  221. package/lib/sync/constants.d.ts +7 -1
  222. package/lib/sync/constants.d.ts.map +1 -1
  223. package/lib/sync/constants.js +7 -4
  224. package/lib/sync/constants.js.map +1 -1
  225. package/lib/sync/range/batch.d.ts +55 -8
  226. package/lib/sync/range/batch.d.ts.map +1 -1
  227. package/lib/sync/range/batch.js +291 -66
  228. package/lib/sync/range/batch.js.map +1 -1
  229. package/lib/sync/range/chain.d.ts +22 -4
  230. package/lib/sync/range/chain.d.ts.map +1 -1
  231. package/lib/sync/range/chain.js +103 -11
  232. package/lib/sync/range/chain.js.map +1 -1
  233. package/lib/sync/range/range.d.ts.map +1 -1
  234. package/lib/sync/range/range.js +71 -11
  235. package/lib/sync/range/range.js.map +1 -1
  236. package/lib/sync/range/utils/peerBalancer.d.ts +2 -1
  237. package/lib/sync/range/utils/peerBalancer.d.ts.map +1 -1
  238. package/lib/sync/range/utils/peerBalancer.js +8 -4
  239. package/lib/sync/range/utils/peerBalancer.js.map +1 -1
  240. package/lib/sync/sync.d.ts.map +1 -1
  241. package/lib/sync/sync.js +13 -0
  242. package/lib/sync/sync.js.map +1 -1
  243. package/lib/sync/types.d.ts +34 -0
  244. package/lib/sync/types.d.ts.map +1 -1
  245. package/lib/sync/types.js +34 -0
  246. package/lib/sync/types.js.map +1 -1
  247. package/lib/sync/unknownBlock.d.ts +29 -1
  248. package/lib/sync/unknownBlock.d.ts.map +1 -1
  249. package/lib/sync/unknownBlock.js +727 -61
  250. package/lib/sync/unknownBlock.js.map +1 -1
  251. package/lib/sync/utils/downloadByRange.d.ts +73 -10
  252. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  253. package/lib/sync/utils/downloadByRange.js +213 -26
  254. package/lib/sync/utils/downloadByRange.js.map +1 -1
  255. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  256. package/lib/sync/utils/downloadByRoot.js +16 -2
  257. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  258. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  259. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  260. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  261. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  262. package/lib/sync/utils/rateLimit.d.ts +2 -0
  263. package/lib/sync/utils/rateLimit.d.ts.map +1 -0
  264. package/lib/sync/utils/rateLimit.js +15 -0
  265. package/lib/sync/utils/rateLimit.js.map +1 -0
  266. package/lib/util/dependentRoot.d.ts +6 -2
  267. package/lib/util/dependentRoot.d.ts.map +1 -1
  268. package/lib/util/dependentRoot.js +20 -16
  269. package/lib/util/dependentRoot.js.map +1 -1
  270. package/lib/util/sszBytes.d.ts.map +1 -1
  271. package/lib/util/sszBytes.js +8 -6
  272. package/lib/util/sszBytes.js.map +1 -1
  273. package/package.json +15 -16
  274. package/src/api/impl/beacon/blocks/index.ts +21 -5
  275. package/src/api/impl/beacon/pool/index.ts +136 -1
  276. package/src/api/impl/debug/index.ts +0 -1
  277. package/src/api/impl/lodestar/index.ts +1 -1
  278. package/src/api/impl/validator/index.ts +100 -11
  279. package/src/chain/blocks/blockInput/blockInput.ts +4 -1
  280. package/src/chain/blocks/importBlock.ts +16 -48
  281. package/src/chain/blocks/importExecutionPayload.ts +76 -30
  282. package/src/chain/blocks/index.ts +71 -22
  283. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +37 -3
  284. package/src/chain/blocks/payloadEnvelopeInput/types.ts +18 -0
  285. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  286. package/src/chain/blocks/types.ts +4 -3
  287. package/src/chain/blocks/utils/chainSegment.ts +117 -17
  288. package/src/chain/blocks/verifyBlock.ts +70 -9
  289. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  290. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  291. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +16 -8
  292. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  293. package/src/chain/chain.ts +46 -10
  294. package/src/chain/emitter.ts +0 -11
  295. package/src/chain/errors/blockError.ts +4 -1
  296. package/src/chain/errors/executionPayloadBid.ts +22 -1
  297. package/src/chain/errors/index.ts +1 -0
  298. package/src/chain/errors/proposerPreferences.ts +47 -0
  299. package/src/chain/initState.ts +9 -1
  300. package/src/chain/interface.ts +9 -1
  301. package/src/chain/lightClient/index.ts +6 -6
  302. package/src/chain/opPools/index.ts +1 -0
  303. package/src/chain/opPools/payloadAttestationPool.ts +63 -18
  304. package/src/chain/opPools/proposerPreferencesPool.ts +59 -0
  305. package/src/chain/prepareNextSlot.ts +21 -29
  306. package/src/chain/produceBlock/produceBlockBody.ts +46 -22
  307. package/src/chain/regen/interface.ts +1 -0
  308. package/src/chain/regen/queued.ts +2 -7
  309. package/src/chain/regen/regen.ts +2 -7
  310. package/src/chain/seenCache/index.ts +1 -0
  311. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +90 -24
  312. package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
  313. package/src/chain/validation/block.ts +1 -0
  314. package/src/chain/validation/executionPayloadBid.ts +71 -18
  315. package/src/chain/validation/payloadAttestationMessage.ts +6 -4
  316. package/src/chain/validation/proposerPreferences.ts +110 -0
  317. package/src/metrics/metrics/lodestar.ts +10 -0
  318. package/src/network/gossip/interface.ts +6 -0
  319. package/src/network/gossip/scoringParameters.ts +14 -1
  320. package/src/network/gossip/topic.ts +6 -0
  321. package/src/network/interface.ts +3 -0
  322. package/src/network/network.ts +34 -0
  323. package/src/network/processor/gossipHandlers.ts +96 -20
  324. package/src/network/processor/gossipQueues/index.ts +5 -0
  325. package/src/network/processor/index.ts +6 -5
  326. package/src/network/reqresp/ReqRespBeaconNode.ts +1 -0
  327. package/src/network/reqresp/handlers/beaconBlocksByHead.ts +91 -0
  328. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  329. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  330. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  331. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  332. package/src/network/reqresp/handlers/index.ts +5 -0
  333. package/src/network/reqresp/interface.ts +1 -1
  334. package/src/network/reqresp/protocols.ts +6 -0
  335. package/src/network/reqresp/rateLimit.ts +4 -0
  336. package/src/network/reqresp/score.ts +1 -0
  337. package/src/network/reqresp/types.ts +5 -0
  338. package/src/node/nodejs.ts +2 -2
  339. package/src/sync/constants.ts +8 -4
  340. package/src/sync/range/batch.ts +388 -75
  341. package/src/sync/range/chain.ts +131 -14
  342. package/src/sync/range/range.ts +86 -11
  343. package/src/sync/range/utils/peerBalancer.ts +9 -3
  344. package/src/sync/sync.ts +13 -1
  345. package/src/sync/types.ts +72 -0
  346. package/src/sync/unknownBlock.ts +915 -65
  347. package/src/sync/utils/downloadByRange.ts +386 -39
  348. package/src/sync/utils/downloadByRoot.ts +24 -2
  349. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  350. package/src/sync/utils/rateLimit.ts +16 -0
  351. package/src/util/dependentRoot.ts +22 -18
  352. package/src/util/sszBytes.ts +8 -6
@@ -4,13 +4,14 @@ import {getSafeExecutionBlockHash} from "@lodestar/fork-choice";
4
4
  import {ForkPostBellatrix, ForkSeq, SLOTS_PER_EPOCH, isForkPostBellatrix} from "@lodestar/params";
5
5
  import {
6
6
  IBeaconStateView,
7
+ IBeaconStateViewBellatrix,
7
8
  StateHashTreeRootSource,
8
9
  computeEpochAtSlot,
9
10
  computeTimeAtSlot,
10
11
  isStatePostBellatrix,
11
12
  isStatePostGloas,
12
13
  } from "@lodestar/state-transition";
13
- import {Bytes32, Slot, electra} from "@lodestar/types";
14
+ import {Bytes32, Slot} from "@lodestar/types";
14
15
  import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils";
15
16
  import {GENESIS_SLOT, ZERO_HASH_HEX} from "../constants/constants.js";
16
17
  import {BuilderStatus} from "../execution/builder/http.js";
@@ -165,19 +166,26 @@ export class PrepareNextSlotScheduler {
165
166
  }
166
167
 
167
168
  let parentBlockHash: Bytes32;
168
- let isExtendingPayload = false;
169
+ // Apply parent payload once here as it's reused by EL prep and SSE emit below
170
+ let stateAfterParentPayload: IBeaconStateViewBellatrix = updatedPrepareState;
169
171
  if (isStatePostGloas(updatedPrepareState)) {
170
- isExtendingPayload = this.chain.forkChoice.shouldExtendPayload(updatedHead.blockRoot);
171
- parentBlockHash = isExtendingPayload
172
- ? updatedPrepareState.latestExecutionPayloadBid.blockHash
173
- : updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
172
+ if (this.chain.forkChoice.shouldExtendPayload(updatedHead.blockRoot)) {
173
+ parentBlockHash = updatedPrepareState.latestExecutionPayloadBid.blockHash;
174
+ // Skip applying parent payload unless we're proposing the next slot or have to emit payload_attributes events
175
+ if (feeRecipient !== undefined || this.chain.opts.emitPayloadAttributes === true) {
176
+ const parentExecutionRequests = await this.chain.getParentExecutionRequests(
177
+ updatedHead.slot,
178
+ updatedHead.blockRoot
179
+ );
180
+ stateAfterParentPayload = updatedPrepareState.withParentPayloadApplied(parentExecutionRequests);
181
+ }
182
+ } else {
183
+ parentBlockHash = updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
184
+ }
174
185
  } else {
175
186
  parentBlockHash = updatedPrepareState.latestExecutionPayloadHeader.blockHash;
176
187
  }
177
188
 
178
- // Reused by the SSE emit below to avoid a second DB lookup on cache miss
179
- let parentExecutionRequests: electra.ExecutionRequests | undefined;
180
-
181
189
  if (feeRecipient) {
182
190
  const preparationTime =
183
191
  computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
@@ -187,13 +195,6 @@ export class PrepareNextSlotScheduler {
187
195
  const finalizedBlockHash =
188
196
  this.chain.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
189
197
 
190
- if (isExtendingPayload) {
191
- parentExecutionRequests = await this.chain.getParentExecutionRequests(
192
- updatedHead.slot,
193
- updatedHead.blockRoot
194
- );
195
- }
196
-
197
198
  // awaiting here instead of throwing an async call because there is no other task
198
199
  // left for scheduler and this gives nice semantics to catch and log errors in the
199
200
  // try/catch wrapper here.
@@ -205,9 +206,8 @@ export class PrepareNextSlotScheduler {
205
206
  parentBlockHash,
206
207
  safeBlockHash,
207
208
  finalizedBlockHash,
208
- updatedPrepareState,
209
- feeRecipient,
210
- parentExecutionRequests
209
+ stateAfterParentPayload,
210
+ feeRecipient
211
211
  );
212
212
  this.logger.verbose("PrepareNextSlotScheduler prepared new payload", {
213
213
  prepareSlot,
@@ -222,7 +222,7 @@ export class PrepareNextSlotScheduler {
222
222
  // and head.parent (proposer-boost-reorg fallback). Anything older is evicted.
223
223
  const updatedHeadParent = this.chain.forkChoice.getBlockHexDefaultStatus(updatedHead.parentRoot);
224
224
  if (updatedHeadParent) {
225
- this.chain.seenPayloadEnvelopeInputCache.pruneBelow(updatedHeadParent.slot);
225
+ this.chain.seenPayloadEnvelopeInputCache.pruneBelowParent(updatedHeadParent);
226
226
  }
227
227
  }
228
228
 
@@ -234,20 +234,12 @@ export class PrepareNextSlotScheduler {
234
234
  (feeRecipient || this.chain.opts.emitPayloadAttributes === true) &&
235
235
  this.chain.emitter.listenerCount(routes.events.EventType.payloadAttributes)
236
236
  ) {
237
- // if we didn't fetch above (not proposing), SSE still needs it here
238
- if (!parentExecutionRequests && isExtendingPayload) {
239
- parentExecutionRequests = await this.chain.getParentExecutionRequests(
240
- updatedHead.slot,
241
- updatedHead.blockRoot
242
- );
243
- }
244
237
  const data = getPayloadAttributesForSSE(fork as ForkPostBellatrix, this.chain, {
245
- prepareState: updatedPrepareState,
238
+ prepareState: stateAfterParentPayload,
246
239
  prepareSlot,
247
240
  parentBlockRoot: fromHex(updatedHead.blockRoot),
248
241
  parentBlockHash,
249
242
  feeRecipient: feeRecipient ?? "0x0000000000000000000000000000000000000000",
250
- parentExecutionRequests,
251
243
  });
252
244
  this.chain.emitter.emit(routes.events.EventType.payloadAttributes, {data, version: fork});
253
245
  }
@@ -111,6 +111,7 @@ export type ProduceFullGloas = {
111
111
  executionRequests: electra.ExecutionRequests;
112
112
  blobsBundle: BlobsBundle<ForkPostGloas>;
113
113
  cells: fulu.Cell[][];
114
+ parentBlockRoot: Root;
114
115
  };
115
116
  export type ProduceFullFulu = {
116
117
  type: BlockType.Full;
@@ -214,13 +215,19 @@ export async function produceBlockBody<T extends BlockType>(
214
215
  });
215
216
 
216
217
  // Get execution payload from EL
218
+ let parentBlockHash: Bytes32;
219
+ let parentExecutionRequests: electra.ExecutionRequests;
220
+ // Apply parent payload once here as it's reused by EL prep and voluntary exit filtering below
221
+ let stateAfterParentPayload: IBeaconStateViewBellatrix = currentState;
217
222
  const isExtendingPayload = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot));
218
- const parentBlockHash = isExtendingPayload
219
- ? currentState.latestExecutionPayloadBid.blockHash
220
- : currentState.latestExecutionPayloadBid.parentBlockHash;
221
- const parentExecutionRequests = isExtendingPayload
222
- ? await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot)
223
- : ssz.electra.ExecutionRequests.defaultValue();
223
+ if (isExtendingPayload) {
224
+ parentBlockHash = currentState.latestExecutionPayloadBid.blockHash;
225
+ parentExecutionRequests = await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot);
226
+ stateAfterParentPayload = currentState.withParentPayloadApplied(parentExecutionRequests);
227
+ } else {
228
+ parentBlockHash = currentState.latestExecutionPayloadBid.parentBlockHash;
229
+ parentExecutionRequests = ssz.electra.ExecutionRequests.defaultValue();
230
+ }
224
231
  const prepareRes = await prepareExecutionPayload(
225
232
  this,
226
233
  this.logger,
@@ -229,9 +236,8 @@ export async function produceBlockBody<T extends BlockType>(
229
236
  parentBlockHash,
230
237
  safeBlockHash,
231
238
  finalizedBlockHash ?? ZERO_HASH_HEX,
232
- currentState,
233
- feeRecipient,
234
- parentExecutionRequests
239
+ stateAfterParentPayload,
240
+ feeRecipient
235
241
  );
236
242
 
237
243
  const {prepType, payloadId} = prepareRes;
@@ -285,9 +291,19 @@ export async function produceBlockBody<T extends BlockType>(
285
291
  const commonBlockBody = await commonBlockBodyPromise;
286
292
  const gloasBody = Object.assign({}, commonBlockBody) as gloas.BeaconBlockBody;
287
293
  gloasBody.signedExecutionPayloadBid = signedBid;
288
- // TODO GLOAS: Get payload attestations from pool for previous slot
289
- gloasBody.payloadAttestations = [];
294
+ gloasBody.payloadAttestations = this.payloadAttestationPool.getPayloadAttestationsForBlock(
295
+ parentBlock.blockRoot,
296
+ blockSlot - 1
297
+ );
290
298
  gloasBody.parentExecutionRequests = parentExecutionRequests;
299
+ // Drop voluntary exits that parent_execution_requests have invalidated (e.g. a withdrawal
300
+ // request initiating an exit on the same validator). Op pool selected against the unapplied
301
+ // state, so re-validate against the post-apply state to avoid producing an invalid block.
302
+ if (isExtendingPayload && commonBlockBody.voluntaryExits.length > 0) {
303
+ gloasBody.voluntaryExits = commonBlockBody.voluntaryExits.filter((signedVoluntaryExit) =>
304
+ stateAfterParentPayload.isValidVoluntaryExit(signedVoluntaryExit, false)
305
+ );
306
+ }
291
307
  blockBody = gloasBody as AssembledBodyType<T>;
292
308
 
293
309
  // Store execution payload data required to construct execution payload envelope later
@@ -296,6 +312,7 @@ export async function produceBlockBody<T extends BlockType>(
296
312
  gloasResult.executionRequests = executionRequests;
297
313
  gloasResult.blobsBundle = blobsBundle;
298
314
  gloasResult.cells = cells;
315
+ gloasResult.parentBlockRoot = fromHex(parentBlock.blockRoot);
299
316
 
300
317
  const fetchedTime = Date.now() / 1000 - computeTimeAtSlot(this.config, blockSlot, this.genesisTime);
301
318
  this.metrics?.blockPayload.payloadFetchedTime.observe({prepType}, fetchedTime);
@@ -623,9 +640,12 @@ export async function prepareExecutionPayload(
623
640
  parentBlockHash: Bytes32,
624
641
  safeBlockHash: RootHex,
625
642
  finalizedBlockHash: RootHex,
643
+ /**
644
+ * Post-gloas, when extending a full parent, callers must apply
645
+ * parent execution payload first (see `withParentPayloadApplied`).
646
+ */
626
647
  state: IBeaconStateViewBellatrix,
627
- suggestedFeeRecipient: string,
628
- parentExecutionRequests?: electra.ExecutionRequests
648
+ suggestedFeeRecipient: string
629
649
  ): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
630
650
  const timestamp = computeTimeAtSlot(chain.config, state.slot, state.genesisTime);
631
651
  const prevRandao = state.getRandaoMix(state.epoch);
@@ -662,7 +682,6 @@ export async function prepareExecutionPayload(
662
682
  parentBlockRoot,
663
683
  parentBlockHash,
664
684
  feeRecipient: suggestedFeeRecipient,
665
- parentExecutionRequests,
666
685
  });
667
686
 
668
687
  payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
@@ -721,14 +740,16 @@ export function getPayloadAttributesForSSE(
721
740
  parentBlockRoot,
722
741
  parentBlockHash,
723
742
  feeRecipient,
724
- parentExecutionRequests,
725
743
  }: {
744
+ /**
745
+ * Post-gloas, when extending a full parent, callers must apply
746
+ * parent execution payload first (see `withParentPayloadApplied`).
747
+ */
726
748
  prepareState: IBeaconStateViewBellatrix;
727
749
  prepareSlot: Slot;
728
750
  parentBlockRoot: Root;
729
751
  parentBlockHash: Bytes32;
730
752
  feeRecipient: string;
731
- parentExecutionRequests?: electra.ExecutionRequests;
732
753
  }
733
754
  ): SSEPayloadAttributes {
734
755
  const payloadAttributes = preparePayloadAttributes(fork, chain, {
@@ -737,7 +758,6 @@ export function getPayloadAttributesForSSE(
737
758
  parentBlockRoot,
738
759
  parentBlockHash,
739
760
  feeRecipient,
740
- parentExecutionRequests,
741
761
  });
742
762
 
743
763
  let parentBlockNumber: number;
@@ -776,14 +796,16 @@ function preparePayloadAttributes(
776
796
  parentBlockRoot,
777
797
  parentBlockHash,
778
798
  feeRecipient,
779
- parentExecutionRequests,
780
799
  }: {
800
+ /**
801
+ * Post-gloas, when extending a full parent, callers must apply
802
+ * parent execution payload first (see `withParentPayloadApplied`).
803
+ */
781
804
  prepareState: IBeaconStateViewBellatrix;
782
805
  prepareSlot: Slot;
783
806
  parentBlockRoot: Root;
784
807
  parentBlockHash: Bytes32;
785
808
  feeRecipient: string;
786
- parentExecutionRequests?: electra.ExecutionRequests;
787
809
  }
788
810
  ): SSEPayloadAttributes["payloadAttributes"] {
789
811
  const timestamp = computeTimeAtSlot(chain.config, prepareSlot, prepareState.genesisTime);
@@ -802,11 +824,13 @@ function preparePayloadAttributes(
802
824
  if (isStatePostGloas(prepareState)) {
803
825
  const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
804
826
  if (isExtendingPayload) {
805
- if (parentExecutionRequests === undefined) {
806
- throw new Error("parentExecutionRequests required when extending full parent");
827
+ // applyParentExecutionPayload sets latestBlockHash = parentBid.blockHash, so a mismatch
828
+ // here means the caller did not apply parent payload to prepareState
829
+ if (!byteArrayEquals(prepareState.latestBlockHash, prepareState.latestExecutionPayloadBid.blockHash)) {
830
+ throw new Error("Expected state with parent execution payload applied for withdrawals");
807
831
  }
808
832
  (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
809
- prepareState.getExpectedWithdrawalsForFullParent(parentExecutionRequests);
833
+ prepareState.getExpectedWithdrawals().expectedWithdrawals;
810
834
  } else {
811
835
  // When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
812
836
  // already deducted from CL balances but never credited on the EL (the envelope
@@ -21,6 +21,7 @@ export enum RegenCaller {
21
21
  validateGossipAttestation = "validateGossipAttestation",
22
22
  validateGossipVoluntaryExit = "validateGossipVoluntaryExit",
23
23
  validateGossipExecutionPayloadBid = "validateGossipExecutionPayloadBid",
24
+ validateGossipProposerPreferences = "validateGossipProposerPreferences",
24
25
  onForkChoiceFinalized = "onForkChoiceFinalized",
25
26
  restApi = "restApi",
26
27
  }
@@ -1,7 +1,7 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
3
3
  import {IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
4
- import {BeaconBlock, Epoch, RootHex, Slot, isGloasBeaconBlock, phase0} from "@lodestar/types";
4
+ import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
5
5
  import {Logger, toRootHex} from "@lodestar/utils";
6
6
  import {Metrics} from "../../metrics/index.js";
7
7
  import {JobItemQueue} from "../../util/queue/index.js";
@@ -88,12 +88,7 @@ export class QueuedStateRegenerator implements IStateRegenerator {
88
88
  */
89
89
  getPreStateSync(block: BeaconBlock): IBeaconStateView | null {
90
90
  const parentRoot = toRootHex(block.parentRoot);
91
- const parentBlock = isGloasBeaconBlock(block)
92
- ? this.forkChoice.getBlockHexAndBlockHash(
93
- parentRoot,
94
- toRootHex(block.body.signedExecutionPayloadBid.message.parentBlockHash)
95
- )
96
- : this.forkChoice.getBlockHexDefaultStatus(parentRoot);
91
+ const parentBlock = this.forkChoice.getBlockHexDefaultStatus(parentRoot);
97
92
  if (!parentBlock) {
98
93
  throw new RegenError({
99
94
  code: RegenErrorCode.BLOCK_NOT_IN_FORKCHOICE,
@@ -9,7 +9,7 @@ import {
9
9
  computeEpochAtSlot,
10
10
  computeStartSlotAtEpoch,
11
11
  } from "@lodestar/state-transition";
12
- import {BeaconBlock, RootHex, SignedBeaconBlock, Slot, isGloasBeaconBlock} from "@lodestar/types";
12
+ import {BeaconBlock, RootHex, SignedBeaconBlock, Slot} from "@lodestar/types";
13
13
  import {Logger, fromHex, toRootHex} from "@lodestar/utils";
14
14
  import {IBeaconDb} from "../../db/index.js";
15
15
  import {Metrics} from "../../metrics/index.js";
@@ -57,12 +57,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
57
57
  regenCaller: RegenCaller
58
58
  ): Promise<IBeaconStateView> {
59
59
  const parentRoot = toRootHex(block.parentRoot);
60
- const parentBlock = isGloasBeaconBlock(block)
61
- ? this.modules.forkChoice.getBlockHexAndBlockHash(
62
- parentRoot,
63
- toRootHex(block.body.signedExecutionPayloadBid.message.parentBlockHash)
64
- )
65
- : this.modules.forkChoice.getBlockHexDefaultStatus(parentRoot);
60
+ const parentBlock = this.modules.forkChoice.getBlockHexDefaultStatus(parentRoot);
66
61
  if (!parentBlock) {
67
62
  throw new RegenError({
68
63
  code: RegenErrorCode.BLOCK_NOT_IN_FORKCHOICE,
@@ -5,3 +5,4 @@ export {SeenContributionAndProof} from "./seenCommitteeContribution.js";
5
5
  export {SeenExecutionPayloadBids} from "./seenExecutionPayloadBids.js";
6
6
  export {SeenBlockInput} from "./seenGossipBlockInput.js";
7
7
  export {PayloadEnvelopeInput, SeenPayloadEnvelopeInput} from "./seenPayloadEnvelopeInput.js";
8
+ export {SeenProposerPreferences} from "./seenProposerPreferences.js";
@@ -1,16 +1,22 @@
1
- import {CheckpointWithHex} from "@lodestar/fork-choice";
1
+ import {ChainForkConfig} from "@lodestar/config";
2
+ import {CheckpointWithHex, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
2
3
  import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
3
- import {RootHex, Slot} from "@lodestar/types";
4
+ import {RootHex} from "@lodestar/types";
4
5
  import {Logger} from "@lodestar/utils";
5
6
  import {Metrics} from "../../metrics/metrics.js";
7
+ import {IClock} from "../../util/clock.js";
6
8
  import {SerializedCache} from "../../util/serializedCache.js";
7
- import {CreateFromBlockProps, PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
9
+ import {isDaOutOfRange} from "../blocks/blockInput/index.js";
10
+ import {CreateFromBidProps, CreateFromBlockProps, PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
8
11
  import {ChainEvent, ChainEventEmitter} from "../emitter.js";
9
12
 
10
13
  export type {PayloadEnvelopeInputState} from "../blocks/payloadEnvelopeInput/index.js";
11
14
  export {PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
12
15
 
13
16
  export type SeenPayloadEnvelopeInputModules = {
17
+ config: ChainForkConfig;
18
+ clock: IClock;
19
+ forkChoice: IForkChoice;
14
20
  chainEvents: ChainEventEmitter;
15
21
  signal: AbortSignal;
16
22
  serializedCache: SerializedCache;
@@ -21,17 +27,16 @@ export type SeenPayloadEnvelopeInputModules = {
21
27
  /**
22
28
  * Cache for tracking PayloadEnvelopeInput instances, keyed by beacon block root.
23
29
  *
24
- * Created during block import when a block is processed. 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
- *
30
+ * Created whenever we have a block because it needs block bid.
29
31
  * Steady state (linear chain, healthy progression): the cache holds ~2 entries — the head
30
32
  * (parent for next-slot production) and its parent (proposer-boost-reorg fallback). It can
31
33
  * transiently hold more during forks, range-sync bursts, or when `prepareNextSlot` skips
32
34
  * ticks; subsequent ticks settle it back.
33
35
  */
34
36
  export class SeenPayloadEnvelopeInput {
37
+ private readonly config: ChainForkConfig;
38
+ private readonly clock: IClock;
39
+ private readonly forkChoice: IForkChoice;
35
40
  private readonly chainEvents: ChainEventEmitter;
36
41
  private readonly signal: AbortSignal;
37
42
  private readonly serializedCache: SerializedCache;
@@ -39,7 +44,19 @@ export class SeenPayloadEnvelopeInput {
39
44
  private readonly logger?: Logger;
40
45
  private payloadInputs = new Map<RootHex, PayloadEnvelopeInput>();
41
46
 
42
- constructor({chainEvents, signal, serializedCache, metrics, logger}: SeenPayloadEnvelopeInputModules) {
47
+ constructor({
48
+ config,
49
+ clock,
50
+ forkChoice,
51
+ chainEvents,
52
+ signal,
53
+ serializedCache,
54
+ metrics,
55
+ logger,
56
+ }: SeenPayloadEnvelopeInputModules) {
57
+ this.config = config;
58
+ this.clock = clock;
59
+ this.forkChoice = forkChoice;
43
60
  this.chainEvents = chainEvents;
44
61
  this.signal = signal;
45
62
  this.serializedCache = serializedCache;
@@ -58,23 +75,68 @@ export class SeenPayloadEnvelopeInput {
58
75
  });
59
76
  }
60
77
 
61
- this.chainEvents.on(ChainEvent.forkChoiceFinalized, this.onFinalized);
78
+ this.chainEvents.on(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
62
79
  this.signal.addEventListener("abort", () => {
63
- this.chainEvents.off(ChainEvent.forkChoiceFinalized, this.onFinalized);
80
+ this.chainEvents.off(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
64
81
  });
65
82
  }
66
83
 
67
- private onFinalized = (checkpoint: CheckpointWithHex): void => {
68
- this.pruneBelow(computeStartSlotAtEpoch(checkpoint.epoch));
84
+ private pruneFinalized = (checkpoint: CheckpointWithHex): void => {
85
+ const finalizedSlot = computeStartSlotAtEpoch(checkpoint.epoch);
86
+ let deletedCount = 0;
87
+ for (const [, input] of this.payloadInputs) {
88
+ if (input.slot < finalizedSlot) {
89
+ this.evictPayloadInput(input);
90
+ deletedCount++;
91
+ }
92
+ }
93
+
94
+ this.logger?.debug("SeenPayloadEnvelopeInput.pruneFinalized deleted entries", {
95
+ finalizedSlot,
96
+ finalizedRoot: checkpoint.rootHex,
97
+ deletedCount,
98
+ });
69
99
  };
70
100
 
71
- add(props: CreateFromBlockProps): PayloadEnvelopeInput {
72
- if (this.payloadInputs.has(props.blockRootHex)) {
73
- throw new Error(`PayloadEnvelopeInput already exists for block ${props.blockRootHex}`);
101
+ add(props: Omit<CreateFromBlockProps, "daOutOfRange">): PayloadEnvelopeInput {
102
+ const existing = this.payloadInputs.get(props.blockRootHex);
103
+ if (existing !== undefined) {
104
+ this.logger?.verbose("SeenPayloadEnvelopeInput.add reused existing entry", {
105
+ slot: existing.slot,
106
+ root: props.blockRootHex,
107
+ });
108
+ return existing;
109
+ }
110
+ const daOutOfRange = isDaOutOfRange(this.config, props.forkName, props.block.message.slot, this.clock.currentEpoch);
111
+ const input = PayloadEnvelopeInput.createFromBlock({...props, daOutOfRange});
112
+ this.payloadInputs.set(props.blockRootHex, input);
113
+ this.metrics?.seenCache.payloadEnvelopeInput.created.inc();
114
+ this.logger?.verbose("SeenPayloadEnvelopeInput.add created new entry", {
115
+ slot: input.slot,
116
+ root: props.blockRootHex,
117
+ daOutOfRange,
118
+ });
119
+ return input;
120
+ }
121
+
122
+ /**
123
+ * Used at chain initialization to seed the anchor block's PayloadEnvelopeInput from
124
+ * `state.latestExecutionPayloadBid`.
125
+ */
126
+ addFromBid(props: Omit<CreateFromBidProps, "daOutOfRange">): PayloadEnvelopeInput {
127
+ const existing = this.payloadInputs.get(props.blockRootHex);
128
+ if (existing !== undefined) {
129
+ return existing;
74
130
  }
75
- const input = PayloadEnvelopeInput.createFromBlock(props);
131
+ const daOutOfRange = isDaOutOfRange(this.config, props.forkName, props.slot, this.clock.currentEpoch);
132
+ const input = PayloadEnvelopeInput.createFromBid({...props, daOutOfRange});
76
133
  this.payloadInputs.set(props.blockRootHex, input);
77
134
  this.metrics?.seenCache.payloadEnvelopeInput.created.inc();
135
+ this.logger?.verbose("SeenPayloadEnvelopeInput.addFromBid created new entry", {
136
+ slot: input.slot,
137
+ root: props.blockRootHex,
138
+ daOutOfRange,
139
+ });
78
140
  return input;
79
141
  }
80
142
 
@@ -90,15 +152,19 @@ export class SeenPayloadEnvelopeInput {
90
152
  return this.payloadInputs.size;
91
153
  }
92
154
 
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++;
155
+ pruneBelowParent(parentBlock: ProtoBlock): void {
156
+ for (const block of this.forkChoice.getAllAncestorBlocks(parentBlock.blockRoot, parentBlock.payloadStatus)) {
157
+ if (block.slot < parentBlock.slot) {
158
+ const input = this.payloadInputs.get(block.blockRoot);
159
+ if (input) {
160
+ this.evictPayloadInput(input);
161
+ this.logger?.verbose("SeenPayloadEnvelopeInput.pruneBelowParent deleted", {
162
+ slot: block.slot,
163
+ root: block.blockRoot,
164
+ });
165
+ }
99
166
  }
100
167
  }
101
- this.logger?.debug("SeenPayloadEnvelopeInput.pruneBelow deleted entries", {slot, deletedCount});
102
168
  }
103
169
 
104
170
  private evictPayloadInput(payloadInput: PayloadEnvelopeInput): void {
@@ -0,0 +1,32 @@
1
+ import {RootHex, Slot, ValidatorIndex} from "@lodestar/types";
2
+ import {MapDef} from "@lodestar/utils";
3
+
4
+ /**
5
+ * Tracks signed proposer preferences we've already seen per (dependent_root, proposal_slot, validator_index).
6
+ */
7
+ export class SeenProposerPreferences {
8
+ private readonly validatorByDependentRootBySlot = new MapDef<Slot, Map<RootHex, ValidatorIndex>>(
9
+ () => new Map<RootHex, ValidatorIndex>()
10
+ );
11
+
12
+ isKnown(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): boolean {
13
+ return this.validatorByDependentRootBySlot.get(proposalSlot)?.get(dependentRoot) === validatorIndex;
14
+ }
15
+
16
+ add(dependentRoot: RootHex, proposalSlot: Slot, validatorIndex: ValidatorIndex): void {
17
+ this.validatorByDependentRootBySlot.getOrDefault(proposalSlot).set(dependentRoot, validatorIndex);
18
+ }
19
+
20
+ /**
21
+ * Entries are only load-bearing while `proposal_slot > current_slot`. Once the slot has
22
+ * passed the `[IGNORE] proposal_slot > current_slot` gossip rule takes over, so drop them
23
+ * on each slot tick.
24
+ */
25
+ prune(currentSlot: Slot): void {
26
+ for (const slot of this.validatorByDependentRootBySlot.keys()) {
27
+ if (slot < currentSlot) {
28
+ this.validatorByDependentRootBySlot.delete(slot);
29
+ }
30
+ }
31
+ }
32
+ }
@@ -103,6 +103,7 @@ export async function validateGossipBlock(
103
103
  if (chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHashHex) === null) {
104
104
  throw new BlockGossipError(GossipAction.IGNORE, {
105
105
  code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN,
106
+ parentRoot,
106
107
  parentBlockHash: parentBlockHashHex,
107
108
  });
108
109
  }
@@ -7,7 +7,8 @@ import {
7
7
  isStatePostGloas,
8
8
  } from "@lodestar/state-transition";
9
9
  import {gloas} from "@lodestar/types";
10
- import {toRootHex} from "@lodestar/utils";
10
+ import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
11
+ import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
11
12
  import {ExecutionPayloadBidError, ExecutionPayloadBidErrorCode, GossipAction} from "../errors/index.js";
12
13
  import {IBeaconChain} from "../index.js";
13
14
  import {RegenCaller} from "../regen/index.js";
@@ -48,9 +49,55 @@ async function validateExecutionPayloadBid(
48
49
  });
49
50
  }
50
51
 
51
- // [IGNORE] the `SignedProposerPreferences` where `preferences.proposal_slot`
52
- // is equal to `bid.slot` has been seen.
53
- // TODO GLOAS: Implement this along with proposer preference
52
+ // [IGNORE] `bid.parent_block_root` is the hash tree root of a known beacon block in fork choice.
53
+ // Moved earlier than the spec ordering so we can derive the proposer dependent root for the
54
+ // proposer-preferences lookup below from a known fork-choice block.
55
+ const parentBlock = chain.forkChoice.getBlockHexDefaultStatus(parentBlockRootHex);
56
+ if (parentBlock === null) {
57
+ throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
58
+ code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
59
+ parentBlockRoot: parentBlockRootHex,
60
+ });
61
+ }
62
+
63
+ // [IGNORE] A `SignedProposerPreferences` matching `bid.slot` and the bid's branch has been
64
+ // seen — i.e. `proposal_slot == bid.slot` AND `dependent_root ==
65
+ // get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))`.
66
+ const bidEpoch = computeEpochAtSlot(bid.slot);
67
+ // gloas is always post-Fulu, so `get_proposer_dependent_root` is the post-Fulu (deterministic
68
+ // proposer lookahead) form `block_root_at(start_slot(epoch - MIN_SEED_LOOKAHEAD) - 1)` with
69
+ // `MIN_SEED_LOOKAHEAD == 1` — identical to the attester-shuffling dependent root for the same
70
+ // epoch (both 1-epoch lookahead), hence `getShufflingDependentRoot`. `null` on a
71
+ // unknown/finalized-pruned ancestor or genesis edge → degrade to IGNORE below instead of
72
+ // letting a raw `ForkChoiceError` escape the `GossipActionError` contract.
73
+ const dependentRootHex = (() => {
74
+ try {
75
+ return getShufflingDependentRoot(chain.forkChoice, bidEpoch, computeEpochAtSlot(parentBlock.slot), parentBlock);
76
+ } catch {
77
+ return null;
78
+ }
79
+ })();
80
+
81
+ if (dependentRootHex === null) {
82
+ // Could not derive the dependent root for this branch (unknown/finalized-pruned ancestor,
83
+ // genesis edge, etc.) → definitionally no matching `SignedProposerPreferences`.
84
+ throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
85
+ code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES,
86
+ slot: bid.slot,
87
+ parentBlockRoot: parentBlockRootHex,
88
+ dependentRoot: "unknown",
89
+ });
90
+ }
91
+
92
+ const proposerPreferences = chain.proposerPreferencesPool.get(bid.slot, dependentRootHex);
93
+ if (proposerPreferences === null) {
94
+ throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
95
+ code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES,
96
+ slot: bid.slot,
97
+ parentBlockRoot: parentBlockRootHex,
98
+ dependentRoot: dependentRootHex,
99
+ });
100
+ }
54
101
 
55
102
  // [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
56
103
  // `is_active_builder(state, bid.builder_index)` returns `True`.
@@ -71,11 +118,26 @@ async function validateExecutionPayloadBid(
71
118
  });
72
119
  }
73
120
 
74
- // [REJECT] `bid.fee_recipient` matches the `fee_recipient` from the proposer's
75
- // `SignedProposerPreferences` associated with `bid.slot`.
76
- // [REJECT] `bid.gas_limit` matches the `gas_limit` from the proposer's
77
- // `SignedProposerPreferences` associated with `bid.slot`.
78
- // TODO GLOAS: Implement this along with proposer preference
121
+ // [REJECT] `bid.fee_recipient == proposer_preferences.fee_recipient`.
122
+ if (!byteArrayEquals(bid.feeRecipient, proposerPreferences.message.feeRecipient)) {
123
+ throw new ExecutionPayloadBidError(GossipAction.REJECT, {
124
+ code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH,
125
+ builderIndex: bid.builderIndex,
126
+ bidFeeRecipient: toHex(bid.feeRecipient),
127
+ expectedFeeRecipient: toHex(proposerPreferences.message.feeRecipient),
128
+ });
129
+ }
130
+
131
+ // [REJECT] `bid.gas_limit == proposer_preferences.gas_limit`.
132
+ const bidGasLimit = Number(bid.gasLimit);
133
+ if (bidGasLimit !== proposerPreferences.message.gasLimit) {
134
+ throw new ExecutionPayloadBidError(GossipAction.REJECT, {
135
+ code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH,
136
+ builderIndex: bid.builderIndex,
137
+ bidGasLimit,
138
+ expectedGasLimit: proposerPreferences.message.gasLimit,
139
+ });
140
+ }
79
141
 
80
142
  // [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
81
143
  // consensus layer -- i.e. validate that
@@ -125,15 +187,6 @@ async function validateExecutionPayloadBid(
125
187
  // payload in fork choice.
126
188
  // TODO GLOAS: implement this
127
189
 
128
- // [IGNORE] `bid.parent_block_root` is the hash tree root of a known beacon
129
- // block in fork choice.
130
- if (!chain.forkChoice.hasBlock(bid.parentBlockRoot)) {
131
- throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
132
- code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
133
- parentBlockRoot: parentBlockRootHex,
134
- });
135
- }
136
-
137
190
  // [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
138
191
  const signatureSet = createSingleSignatureSetFromComponents(
139
192
  PublicKey.fromBytes(builder.pubkey),