@lodestar/beacon-node 1.43.0-dev.ca1fc40294 → 1.43.0-dev.d901f86f98

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 (301) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +16 -5
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +45 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/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 +68 -2
  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 +32 -14
  23. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  24. package/lib/chain/blocks/importExecutionPayload.js +100 -82
  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 -26
  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 +15 -20
  39. package/lib/chain/blocks/types.d.ts.map +1 -1
  40. package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
  41. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  42. package/lib/chain/blocks/utils/chainSegment.js +89 -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 +24 -0
  57. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
  58. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +80 -0
  59. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
  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/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
  64. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
  65. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
  66. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  67. package/lib/chain/chain.d.ts +5 -3
  68. package/lib/chain/chain.d.ts.map +1 -1
  69. package/lib/chain/chain.js +42 -12
  70. package/lib/chain/chain.js.map +1 -1
  71. package/lib/chain/emitter.d.ts +0 -11
  72. package/lib/chain/emitter.d.ts.map +1 -1
  73. package/lib/chain/emitter.js +0 -4
  74. package/lib/chain/emitter.js.map +1 -1
  75. package/lib/chain/errors/blockError.d.ts +8 -1
  76. package/lib/chain/errors/blockError.d.ts.map +1 -1
  77. package/lib/chain/errors/blockError.js +2 -0
  78. package/lib/chain/errors/blockError.js.map +1 -1
  79. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  80. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  81. package/lib/chain/errors/executionPayloadBid.js +1 -0
  82. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  83. package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
  84. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  85. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  86. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  87. package/lib/chain/errors/index.d.ts +1 -0
  88. package/lib/chain/errors/index.d.ts.map +1 -1
  89. package/lib/chain/errors/index.js +1 -0
  90. package/lib/chain/errors/index.js.map +1 -1
  91. package/lib/chain/errors/proposerPreferences.d.ts +40 -0
  92. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  93. package/lib/chain/errors/proposerPreferences.js +14 -0
  94. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  95. package/lib/chain/forkChoice/index.js +2 -2
  96. package/lib/chain/forkChoice/index.js.map +1 -1
  97. package/lib/chain/initState.d.ts.map +1 -1
  98. package/lib/chain/initState.js +6 -1
  99. package/lib/chain/initState.js.map +1 -1
  100. package/lib/chain/interface.d.ts +5 -3
  101. package/lib/chain/interface.d.ts.map +1 -1
  102. package/lib/chain/interface.js.map +1 -1
  103. package/lib/chain/opPools/payloadAttestationPool.d.ts +3 -2
  104. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  105. package/lib/chain/opPools/payloadAttestationPool.js +26 -4
  106. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  107. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  108. package/lib/chain/prepareNextSlot.js +31 -13
  109. package/lib/chain/prepareNextSlot.js.map +1 -1
  110. package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -1
  111. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  112. package/lib/chain/produceBlock/produceBlockBody.js +47 -14
  113. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  114. package/lib/chain/regen/interface.d.ts +1 -0
  115. package/lib/chain/regen/interface.d.ts.map +1 -1
  116. package/lib/chain/regen/interface.js +1 -0
  117. package/lib/chain/regen/interface.js.map +1 -1
  118. package/lib/chain/regen/queued.d.ts.map +1 -1
  119. package/lib/chain/regen/queued.js +1 -4
  120. package/lib/chain/regen/queued.js.map +1 -1
  121. package/lib/chain/regen/regen.d.ts.map +1 -1
  122. package/lib/chain/regen/regen.js +1 -4
  123. package/lib/chain/regen/regen.js.map +1 -1
  124. package/lib/chain/seenCache/index.d.ts +1 -0
  125. package/lib/chain/seenCache/index.d.ts.map +1 -1
  126. package/lib/chain/seenCache/index.js +1 -0
  127. package/lib/chain/seenCache/index.js.map +1 -1
  128. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +24 -7
  129. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  130. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +69 -17
  131. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  132. package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
  133. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  134. package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
  135. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  136. package/lib/chain/validation/block.d.ts.map +1 -1
  137. package/lib/chain/validation/block.js +1 -0
  138. package/lib/chain/validation/block.js.map +1 -1
  139. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  140. package/lib/chain/validation/executionPayloadBid.js +24 -9
  141. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  142. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  143. package/lib/chain/validation/executionPayloadEnvelope.js +11 -1
  144. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  145. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  146. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  147. package/lib/chain/validation/proposerPreferences.js +91 -0
  148. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  149. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  150. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  151. package/lib/metrics/metrics/lodestar.js +4 -0
  152. package/lib/metrics/metrics/lodestar.js.map +1 -1
  153. package/lib/network/gossip/interface.d.ts +7 -1
  154. package/lib/network/gossip/interface.d.ts.map +1 -1
  155. package/lib/network/gossip/interface.js +1 -0
  156. package/lib/network/gossip/interface.js.map +1 -1
  157. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  158. package/lib/network/gossip/scoringParameters.js +12 -1
  159. package/lib/network/gossip/scoringParameters.js.map +1 -1
  160. package/lib/network/gossip/topic.d.ts +10 -0
  161. package/lib/network/gossip/topic.d.ts.map +1 -1
  162. package/lib/network/gossip/topic.js +6 -0
  163. package/lib/network/gossip/topic.js.map +1 -1
  164. package/lib/network/interface.d.ts +1 -0
  165. package/lib/network/interface.d.ts.map +1 -1
  166. package/lib/network/network.d.ts +1 -0
  167. package/lib/network/network.d.ts.map +1 -1
  168. package/lib/network/network.js +5 -0
  169. package/lib/network/network.js.map +1 -1
  170. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  171. package/lib/network/processor/gossipHandlers.js +38 -16
  172. package/lib/network/processor/gossipHandlers.js.map +1 -1
  173. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  174. package/lib/network/processor/gossipQueues/index.js +5 -0
  175. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  176. package/lib/network/processor/index.d.ts.map +1 -1
  177. package/lib/network/processor/index.js +6 -5
  178. package/lib/network/processor/index.js.map +1 -1
  179. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  180. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  181. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  182. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  183. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  184. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  185. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  186. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  187. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  188. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  189. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  190. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  191. package/lib/node/nodejs.js +2 -2
  192. package/lib/node/nodejs.js.map +1 -1
  193. package/lib/sync/constants.d.ts +3 -1
  194. package/lib/sync/constants.d.ts.map +1 -1
  195. package/lib/sync/constants.js +3 -4
  196. package/lib/sync/constants.js.map +1 -1
  197. package/lib/sync/range/batch.d.ts +35 -5
  198. package/lib/sync/range/batch.d.ts.map +1 -1
  199. package/lib/sync/range/batch.js +240 -59
  200. package/lib/sync/range/batch.js.map +1 -1
  201. package/lib/sync/range/chain.d.ts +19 -4
  202. package/lib/sync/range/chain.d.ts.map +1 -1
  203. package/lib/sync/range/chain.js +64 -11
  204. package/lib/sync/range/chain.js.map +1 -1
  205. package/lib/sync/range/range.d.ts.map +1 -1
  206. package/lib/sync/range/range.js +31 -9
  207. package/lib/sync/range/range.js.map +1 -1
  208. package/lib/sync/sync.d.ts.map +1 -1
  209. package/lib/sync/sync.js +13 -0
  210. package/lib/sync/sync.js.map +1 -1
  211. package/lib/sync/types.d.ts +34 -0
  212. package/lib/sync/types.d.ts.map +1 -1
  213. package/lib/sync/types.js +34 -0
  214. package/lib/sync/types.js.map +1 -1
  215. package/lib/sync/unknownBlock.d.ts +29 -1
  216. package/lib/sync/unknownBlock.d.ts.map +1 -1
  217. package/lib/sync/unknownBlock.js +738 -61
  218. package/lib/sync/unknownBlock.js.map +1 -1
  219. package/lib/sync/utils/downloadByRange.d.ts +67 -10
  220. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  221. package/lib/sync/utils/downloadByRange.js +211 -26
  222. package/lib/sync/utils/downloadByRange.js.map +1 -1
  223. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  224. package/lib/sync/utils/downloadByRoot.js +16 -2
  225. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  226. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  227. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  228. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  229. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  230. package/lib/util/sszBytes.d.ts.map +1 -1
  231. package/lib/util/sszBytes.js +8 -6
  232. package/lib/util/sszBytes.js.map +1 -1
  233. package/package.json +17 -16
  234. package/src/api/impl/beacon/blocks/index.ts +21 -5
  235. package/src/api/impl/beacon/pool/index.ts +83 -1
  236. package/src/api/impl/debug/index.ts +0 -1
  237. package/src/api/impl/lodestar/index.ts +1 -1
  238. package/src/api/impl/validator/index.ts +82 -1
  239. package/src/chain/blocks/blockInput/blockInput.ts +4 -1
  240. package/src/chain/blocks/importBlock.ts +16 -48
  241. package/src/chain/blocks/importExecutionPayload.ts +126 -100
  242. package/src/chain/blocks/index.ts +71 -23
  243. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +37 -3
  244. package/src/chain/blocks/payloadEnvelopeInput/types.ts +18 -0
  245. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  246. package/src/chain/blocks/types.ts +15 -25
  247. package/src/chain/blocks/utils/chainSegment.ts +114 -17
  248. package/src/chain/blocks/verifyBlock.ts +70 -9
  249. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  250. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  251. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +137 -0
  252. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  253. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  254. package/src/chain/chain.ts +55 -10
  255. package/src/chain/emitter.ts +0 -11
  256. package/src/chain/errors/blockError.ts +4 -1
  257. package/src/chain/errors/executionPayloadBid.ts +6 -0
  258. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  259. package/src/chain/errors/index.ts +1 -0
  260. package/src/chain/errors/proposerPreferences.ts +47 -0
  261. package/src/chain/forkChoice/index.ts +2 -2
  262. package/src/chain/initState.ts +9 -1
  263. package/src/chain/interface.ts +9 -1
  264. package/src/chain/opPools/payloadAttestationPool.ts +29 -8
  265. package/src/chain/prepareNextSlot.ts +36 -14
  266. package/src/chain/produceBlock/produceBlockBody.ts +57 -13
  267. package/src/chain/regen/interface.ts +1 -0
  268. package/src/chain/regen/queued.ts +2 -7
  269. package/src/chain/regen/regen.ts +2 -7
  270. package/src/chain/seenCache/index.ts +1 -0
  271. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +89 -21
  272. package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
  273. package/src/chain/validation/block.ts +1 -0
  274. package/src/chain/validation/executionPayloadBid.ts +25 -8
  275. package/src/chain/validation/executionPayloadEnvelope.ts +12 -2
  276. package/src/chain/validation/proposerPreferences.ts +110 -0
  277. package/src/metrics/metrics/lodestar.ts +4 -0
  278. package/src/network/gossip/interface.ts +6 -0
  279. package/src/network/gossip/scoringParameters.ts +14 -1
  280. package/src/network/gossip/topic.ts +6 -0
  281. package/src/network/interface.ts +1 -0
  282. package/src/network/network.ts +11 -0
  283. package/src/network/processor/gossipHandlers.ts +53 -17
  284. package/src/network/processor/gossipQueues/index.ts +5 -0
  285. package/src/network/processor/index.ts +6 -5
  286. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  287. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  288. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  289. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  290. package/src/node/nodejs.ts +2 -2
  291. package/src/sync/constants.ts +4 -4
  292. package/src/sync/range/batch.ts +320 -67
  293. package/src/sync/range/chain.ts +89 -14
  294. package/src/sync/range/range.ts +34 -9
  295. package/src/sync/sync.ts +13 -1
  296. package/src/sync/types.ts +72 -0
  297. package/src/sync/unknownBlock.ts +928 -65
  298. package/src/sync/utils/downloadByRange.ts +378 -39
  299. package/src/sync/utils/downloadByRoot.ts +24 -2
  300. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  301. package/src/util/sszBytes.ts +8 -6
@@ -23,6 +23,7 @@ import {
23
23
  getEffectiveBalancesFromStateBytes,
24
24
  isStatePostAltair,
25
25
  isStatePostElectra,
26
+ isStatePostGloas,
26
27
  } from "@lodestar/state-transition";
27
28
  import {
28
29
  BeaconBlock,
@@ -39,6 +40,7 @@ import {
39
40
  ValidatorIndex,
40
41
  Wei,
41
42
  deneb,
43
+ electra,
42
44
  gloas,
43
45
  isBlindedBeaconBlock,
44
46
  phase0,
@@ -105,6 +107,7 @@ import {
105
107
  SeenExecutionPayloadBids,
106
108
  SeenPayloadAttesters,
107
109
  SeenPayloadEnvelopeInput,
110
+ SeenProposerPreferences,
108
111
  SeenSyncCommitteeMessages,
109
112
  } from "./seenCache/index.js";
110
113
  import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
@@ -185,6 +188,7 @@ export class BeaconChain implements IBeaconChain {
185
188
  readonly seenPayloadAttesters = new SeenPayloadAttesters();
186
189
  readonly seenAggregatedAttestations: SeenAggregatedAttestations;
187
190
  readonly seenExecutionPayloadBids = new SeenExecutionPayloadBids();
191
+ readonly seenProposerPreferences = new SeenProposerPreferences();
188
192
  readonly seenBlockProposers = new SeenBlockProposers();
189
193
  readonly seenSyncCommitteeMessages = new SeenSyncCommitteeMessages();
190
194
  readonly seenContributionAndProof: SeenContributionAndProof;
@@ -332,13 +336,6 @@ export class BeaconChain implements IBeaconChain {
332
336
  metrics,
333
337
  logger,
334
338
  });
335
- this.seenPayloadEnvelopeInputCache = new SeenPayloadEnvelopeInput({
336
- chainEvents: emitter,
337
- signal,
338
- serializedCache: this.serializedCache,
339
- metrics,
340
- logger,
341
- });
342
339
 
343
340
  this._earliestAvailableSlot = anchorState.slot;
344
341
 
@@ -394,6 +391,7 @@ export class BeaconChain implements IBeaconChain {
394
391
  metrics,
395
392
  logger
396
393
  );
394
+
397
395
  const regen = new QueuedStateRegenerator({
398
396
  config,
399
397
  forkChoice,
@@ -418,6 +416,33 @@ export class BeaconChain implements IBeaconChain {
418
416
  this.payloadEnvelopeProcessor = new PayloadEnvelopeProcessor(this, metrics, signal);
419
417
 
420
418
  this.forkChoice = forkChoice;
419
+
420
+ this.seenPayloadEnvelopeInputCache = new SeenPayloadEnvelopeInput({
421
+ config,
422
+ clock,
423
+ forkChoice,
424
+ chainEvents: emitter,
425
+ signal,
426
+ serializedCache: this.serializedCache,
427
+ metrics,
428
+ logger,
429
+ });
430
+
431
+ const anchorBlockSlot = anchorState.latestBlockHeader.slot;
432
+ if (isStatePostGloas(anchorState) && anchorBlockSlot > 0) {
433
+ const anchorBid = anchorState.latestExecutionPayloadBid;
434
+ this.seenPayloadEnvelopeInputCache.addFromBid({
435
+ blockRootHex: toRootHex(checkpoint.root),
436
+ slot: anchorBlockSlot,
437
+ forkName: anchorState.forkName,
438
+ proposerIndex: anchorState.latestBlockHeader.proposerIndex,
439
+ bid: anchorBid,
440
+ sampledColumns: this.custodyConfig.sampledColumns,
441
+ custodyColumns: this.custodyConfig.custodyColumns,
442
+ timeCreatedSec: Math.floor(Date.now() / 1000),
443
+ });
444
+ }
445
+
421
446
  this.clock = clock;
422
447
  this.regen = regen;
423
448
  this.bls = bls;
@@ -886,6 +911,21 @@ export class BeaconChain implements IBeaconChain {
886
911
  );
887
912
  }
888
913
 
914
+ async getParentExecutionRequests(
915
+ parentBlockSlot: Slot,
916
+ parentBlockRootHex: RootHex
917
+ ): Promise<electra.ExecutionRequests> {
918
+ // at the fork boundary, parent is pre-gloas
919
+ if (!isForkPostGloas(this.config.getForkName(parentBlockSlot))) {
920
+ return ssz.electra.ExecutionRequests.defaultValue();
921
+ }
922
+ const envelope = await this.getExecutionPayloadEnvelope(parentBlockSlot, parentBlockRootHex);
923
+ if (envelope === null) {
924
+ throw Error(`Parent execution payload envelope not found slot=${parentBlockSlot}, root=${parentBlockRootHex}`);
925
+ }
926
+ return envelope.message.executionRequests;
927
+ }
928
+
889
929
  async getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<DataColumnSidecar[]> {
890
930
  const fork = this.config.getForkName(blockSlot);
891
931
 
@@ -1082,11 +1122,15 @@ export class BeaconChain implements IBeaconChain {
1082
1122
  }
1083
1123
 
1084
1124
  async processBlock(block: IBlockInput, opts?: ImportBlockOpts): Promise<void> {
1085
- return this.blockProcessor.processBlocksJob([block], opts);
1125
+ return this.blockProcessor.processBlocksJob([block], null, opts);
1086
1126
  }
1087
1127
 
1088
- async processChainSegment(blocks: IBlockInput[], opts?: ImportBlockOpts): Promise<void> {
1089
- return this.blockProcessor.processBlocksJob(blocks, opts);
1128
+ async processChainSegment(
1129
+ blocks: IBlockInput[],
1130
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
1131
+ opts?: ImportBlockOpts
1132
+ ): Promise<void> {
1133
+ await this.blockProcessor.processBlocksJob(blocks, payloadEnvelopes, opts);
1090
1134
  }
1091
1135
 
1092
1136
  async processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void> {
@@ -1417,6 +1461,7 @@ export class BeaconChain implements IBeaconChain {
1417
1461
  this.payloadAttestationPool.prune(slot);
1418
1462
  this.executionPayloadBidPool.prune(slot);
1419
1463
  this.seenExecutionPayloadBids.prune(slot);
1464
+ this.seenProposerPreferences.prune(slot);
1420
1465
  this.seenAttestationDatas.onSlot(slot);
1421
1466
  this.reprocessController.onSlot(slot);
1422
1467
 
@@ -4,7 +4,6 @@ import {routes} from "@lodestar/api";
4
4
  import {CheckpointWithHex} from "@lodestar/fork-choice";
5
5
  import {IBeaconStateView} from "@lodestar/state-transition";
6
6
  import {DataColumnSidecar, RootHex, deneb, phase0} from "@lodestar/types";
7
- import {SignedExecutionPayloadEnvelope} from "@lodestar/types/gloas";
8
7
  import {PeerIdStr} from "../util/peerId.js";
9
8
  import {BlockInputSource, IBlockInput} from "./blocks/blockInput/types.js";
10
9
  import {PayloadEnvelopeInput} from "./blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
@@ -60,10 +59,6 @@ export enum ChainEvent {
60
59
  * Post-gloas, missing parent could be a SignedBeaconBlock and/or a SignedExecutionPayloadEnvelope
61
60
  */
62
61
  blockUnknownParent = "blockUnknownParent",
63
- /**
64
- * Trigger BlockInputSync to find a SignedBeaconBlock given a SignedExecutionPayloadEnvelop received
65
- */
66
- envelopeUnknownBlock = "envelopeUnknownBlock",
67
62
  /**
68
63
  * Trigger BlockInputSync to find a SignedBeaconBlock with specified block root.
69
64
  */
@@ -92,11 +87,6 @@ type ApiEvents = {[K in routes.events.EventType]: (data: routes.events.EventData
92
87
 
93
88
  export type ChainEventData = {
94
89
  [ChainEvent.blockUnknownParent]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
95
- [ChainEvent.envelopeUnknownBlock]: {
96
- envelope: SignedExecutionPayloadEnvelope;
97
- peer?: PeerIdStr;
98
- source: BlockInputSource;
99
- };
100
90
  [ChainEvent.unknownBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
101
91
  [ChainEvent.incompleteBlockInput]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
102
92
  [ChainEvent.incompletePayloadEnvelope]: {
@@ -124,7 +114,6 @@ export type IChainEvents = ApiEvents & {
124
114
  // Sync events that are chain->chain. Initiated from network requests but do not cross the network
125
115
  // barrier so are considered ChainEvent(s).
126
116
  [ChainEvent.blockUnknownParent]: (data: ChainEventData[ChainEvent.blockUnknownParent]) => void;
127
- [ChainEvent.envelopeUnknownBlock]: (data: ChainEventData[ChainEvent.envelopeUnknownBlock]) => void;
128
117
  [ChainEvent.unknownBlockRoot]: (data: ChainEventData[ChainEvent.unknownBlockRoot]) => void;
129
118
  [ChainEvent.incompleteBlockInput]: (data: ChainEventData[ChainEvent.incompleteBlockInput]) => void;
130
119
  [ChainEvent.incompletePayloadEnvelope]: (data: ChainEventData[ChainEvent.incompletePayloadEnvelope]) => void;
@@ -74,6 +74,8 @@ export enum BlockErrorCode {
74
74
  PARENT_EXECUTION_INVALID = "BLOCK_ERROR_PARENT_EXECUTION_INVALID",
75
75
  /** The block's parent execution payload (defined by bid.parent_block_hash) has not been seen */
76
76
  PARENT_PAYLOAD_UNKNOWN = "BLOCK_ERROR_PARENT_PAYLOAD_UNKNOWN",
77
+ /** An execution payload envelope in the chain segment references a block root that does not match its slot's block */
78
+ ENVELOPE_BLOCK_ROOT_MISMATCH = "BLOCK_ERROR_ENVELOPE_BLOCK_ROOT_MISMATCH",
77
79
  }
78
80
 
79
81
  type ExecutionErrorStatus = Exclude<
@@ -107,6 +109,7 @@ export type BlockErrorType =
107
109
  | {code: BlockErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot}
108
110
  | {code: BlockErrorCode.NON_LINEAR_PARENT_ROOTS}
109
111
  | {code: BlockErrorCode.NON_LINEAR_SLOTS}
112
+ | {code: BlockErrorCode.ENVELOPE_BLOCK_ROOT_MISMATCH; envelopeBlockRoot: RootHex; blockRoot: RootHex}
110
113
  | {code: BlockErrorCode.PER_BLOCK_PROCESSING_ERROR; error: Error}
111
114
  | {code: BlockErrorCode.BEACON_CHAIN_ERROR; error: Error}
112
115
  | {code: BlockErrorCode.KNOWN_BAD_BLOCK}
@@ -120,7 +123,7 @@ export type BlockErrorType =
120
123
  | {code: BlockErrorCode.TOO_MANY_KZG_COMMITMENTS; blobKzgCommitmentsLen: number; commitmentLimit: number}
121
124
  | {code: BlockErrorCode.BID_PARENT_ROOT_MISMATCH; bidParentRoot: RootHex; blockParentRoot: RootHex}
122
125
  | {code: BlockErrorCode.PARENT_EXECUTION_INVALID; parentRoot: RootHex}
123
- | {code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN; parentBlockHash: RootHex};
126
+ | {code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN; parentRoot: RootHex; parentBlockHash: RootHex};
124
127
 
125
128
  export class BlockGossipError extends GossipActionError<BlockErrorType> {}
126
129
 
@@ -7,6 +7,7 @@ export enum ExecutionPayloadBidErrorCode {
7
7
  BID_ALREADY_KNOWN = "EXECUTION_PAYLOAD_BID_ERROR_BID_ALREADY_KNOWN",
8
8
  BID_TOO_LOW = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_LOW",
9
9
  BID_TOO_HIGH = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_HIGH",
10
+ TOO_MANY_KZG_COMMITMENTS = "EXECUTION_PAYLOAD_BID_ERROR_TOO_MANY_KZG_COMMITMENTS",
10
11
  UNKNOWN_BLOCK_ROOT = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_BLOCK_ROOT",
11
12
  INVALID_SLOT = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SLOT",
12
13
  INVALID_SIGNATURE = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SIGNATURE",
@@ -28,6 +29,11 @@ export type ExecutionPayloadBidErrorType =
28
29
  }
29
30
  | {code: ExecutionPayloadBidErrorCode.BID_TOO_LOW; bidValue: number; currentHighestBid: number}
30
31
  | {code: ExecutionPayloadBidErrorCode.BID_TOO_HIGH; bidValue: number; builderBalance: number}
32
+ | {
33
+ code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS;
34
+ blobKzgCommitmentsLen: number;
35
+ commitmentLimit: number;
36
+ }
31
37
  | {code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT; parentBlockRoot: RootHex}
32
38
  | {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
33
39
  | {code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE; builderIndex: BuilderIndex; slot: Slot};
@@ -11,6 +11,7 @@ export enum ExecutionPayloadEnvelopeErrorCode {
11
11
  SLOT_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_SLOT_MISMATCH",
12
12
  BUILDER_INDEX_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BUILDER_INDEX_MISMATCH",
13
13
  BLOCK_HASH_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BLOCK_HASH_MISMATCH",
14
+ EXECUTION_REQUESTS_ROOT_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_EXECUTION_REQUESTS_ROOT_MISMATCH",
14
15
  INVALID_SIGNATURE = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_INVALID_SIGNATURE",
15
16
  PAYLOAD_ENVELOPE_INPUT_MISSING = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_PAYLOAD_ENVELOPE_INPUT_MISSING",
16
17
  }
@@ -36,6 +37,11 @@ export type ExecutionPayloadEnvelopeErrorType =
36
37
  envelopeBlockHash: RootHex;
37
38
  bidBlockHash: RootHex | null;
38
39
  }
40
+ | {
41
+ code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_ROOT_MISMATCH;
42
+ envelopeRequestsRoot: RootHex;
43
+ bidRequestsRoot: RootHex;
44
+ }
39
45
  | {code: ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE}
40
46
  | {code: ExecutionPayloadEnvelopeErrorCode.PAYLOAD_ENVELOPE_INPUT_MISSING; blockRoot: RootHex};
41
47
 
@@ -8,6 +8,7 @@ export * from "./executionPayloadBid.js";
8
8
  export * from "./executionPayloadEnvelope.js";
9
9
  export * from "./gossipValidation.js";
10
10
  export * from "./payloadAttestation.js";
11
+ export * from "./proposerPreferences.js";
11
12
  export * from "./proposerSlashingError.js";
12
13
  export * from "./syncCommitteeError.js";
13
14
  export * from "./voluntaryExitError.js";
@@ -0,0 +1,47 @@
1
+ import {RootHex, Slot, ValidatorIndex} from "@lodestar/types";
2
+ import {GossipActionError} from "./gossipValidation.js";
3
+
4
+ export enum ProposerPreferencesErrorCode {
5
+ INVALID_EPOCH = "PROPOSER_PREFERENCES_ERROR_INVALID_EPOCH",
6
+ PROPOSAL_SLOT_PASSED = "PROPOSER_PREFERENCES_ERROR_PROPOSAL_SLOT_PASSED",
7
+ UNKNOWN_DEPENDENT_ROOT = "PROPOSER_PREFERENCES_ERROR_UNKNOWN_DEPENDENT_ROOT",
8
+ INVALID_PROPOSER = "PROPOSER_PREFERENCES_ERROR_INVALID_PROPOSER",
9
+ ALREADY_KNOWN = "PROPOSER_PREFERENCES_ERROR_ALREADY_KNOWN",
10
+ INVALID_SIGNATURE = "PROPOSER_PREFERENCES_ERROR_INVALID_SIGNATURE",
11
+ }
12
+
13
+ export type ProposerPreferencesErrorType =
14
+ | {
15
+ code: ProposerPreferencesErrorCode.INVALID_EPOCH;
16
+ proposalSlot: Slot;
17
+ currentEpoch: number;
18
+ }
19
+ | {
20
+ code: ProposerPreferencesErrorCode.PROPOSAL_SLOT_PASSED;
21
+ proposalSlot: Slot;
22
+ currentSlot: Slot;
23
+ }
24
+ | {
25
+ code: ProposerPreferencesErrorCode.UNKNOWN_DEPENDENT_ROOT;
26
+ proposalSlot: Slot;
27
+ dependentRoot: RootHex;
28
+ }
29
+ | {
30
+ code: ProposerPreferencesErrorCode.INVALID_PROPOSER;
31
+ proposalSlot: Slot;
32
+ validatorIndex: ValidatorIndex;
33
+ dependentRoot: RootHex;
34
+ }
35
+ | {
36
+ code: ProposerPreferencesErrorCode.ALREADY_KNOWN;
37
+ proposalSlot: Slot;
38
+ validatorIndex: ValidatorIndex;
39
+ dependentRoot: RootHex;
40
+ }
41
+ | {
42
+ code: ProposerPreferencesErrorCode.INVALID_SIGNATURE;
43
+ proposalSlot: Slot;
44
+ validatorIndex: ValidatorIndex;
45
+ };
46
+
47
+ export class ProposerPreferencesError extends GossipActionError<ProposerPreferencesErrorType> {}
@@ -148,7 +148,7 @@ export function initializeForkChoiceFromFinalizedState(
148
148
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
149
149
 
150
150
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
151
- payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
151
+ payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
152
152
  parentBlockHash: isStatePostGloas(state) ? toRootHex(state.latestBlockHash) : null,
153
153
  },
154
154
  currentSlot
@@ -240,7 +240,7 @@ export function initializeForkChoiceFromUnfinalizedState(
240
240
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
241
241
 
242
242
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
243
- payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
243
+ payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
244
244
  parentBlockHash: isStatePostGloas(unfinalizedState) ? toRootHex(unfinalizedState.latestBlockHash) : null,
245
245
  };
246
246
 
@@ -1,7 +1,8 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
- import {ZERO_HASH} from "@lodestar/params";
2
+ import {ForkPostGloas, ForkSeq, ZERO_HASH} from "@lodestar/params";
3
3
  import {
4
4
  BeaconStateAllForks,
5
+ BeaconStateGloas,
5
6
  IBeaconStateView,
6
7
  computeEpochAtSlot,
7
8
  computeStartSlotAtEpoch,
@@ -52,6 +53,13 @@ export function createGenesisBlock(config: ChainForkConfig, genesisState: Beacon
52
53
  const genesisBlock = types.SignedBeaconBlock.defaultValue();
53
54
  const stateRoot = genesisState.hashTreeRoot();
54
55
  genesisBlock.message.stateRoot = stateRoot;
56
+
57
+ if (config.getForkSeq(GENESIS_SLOT) >= ForkSeq.gloas) {
58
+ const gloasBlock = genesisBlock as SignedBeaconBlock<ForkPostGloas>;
59
+ const gloasState = genesisState as BeaconStateGloas;
60
+ gloasBlock.message.body.signedExecutionPayloadBid.message = gloasState.latestExecutionPayloadBid.toValue();
61
+ }
62
+
55
63
  return genesisBlock;
56
64
  }
57
65
 
@@ -18,6 +18,7 @@ import {
18
18
  altair,
19
19
  capella,
20
20
  deneb,
21
+ electra,
21
22
  gloas,
22
23
  phase0,
23
24
  rewards,
@@ -60,6 +61,7 @@ import {
60
61
  SeenContributionAndProof,
61
62
  SeenExecutionPayloadBids,
62
63
  SeenPayloadAttesters,
64
+ SeenProposerPreferences,
63
65
  SeenSyncCommitteeMessages,
64
66
  } from "./seenCache/index.js";
65
67
  import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
@@ -130,6 +132,7 @@ export interface IBeaconChain {
130
132
  readonly seenPayloadAttesters: SeenPayloadAttesters;
131
133
  readonly seenAggregatedAttestations: SeenAggregatedAttestations;
132
134
  readonly seenExecutionPayloadBids: SeenExecutionPayloadBids;
135
+ readonly seenProposerPreferences: SeenProposerPreferences;
133
136
  readonly seenBlockProposers: SeenBlockProposers;
134
137
  readonly seenSyncCommitteeMessages: SeenSyncCommitteeMessages;
135
138
  readonly seenContributionAndProof: SeenContributionAndProof;
@@ -231,6 +234,7 @@ export interface IBeaconChain {
231
234
  blockSlot: Slot,
232
235
  blockRootHex: string
233
236
  ): Promise<gloas.SignedExecutionPayloadEnvelope | null>;
237
+ getParentExecutionRequests(parentBlockSlot: Slot, parentBlockRootHex: RootHex): Promise<electra.ExecutionRequests>;
234
238
 
235
239
  produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody>;
236
240
  produceBlock(blockAttributes: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}): Promise<{
@@ -248,7 +252,11 @@ export interface IBeaconChain {
248
252
  /** Process a block until complete */
249
253
  processBlock(block: IBlockInput, opts?: ImportBlockOpts): Promise<void>;
250
254
  /** Process a chain of blocks until complete */
251
- processChainSegment(blocks: IBlockInput[], opts?: ImportBlockOpts): Promise<void>;
255
+ processChainSegment(
256
+ blocks: IBlockInput[],
257
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
258
+ opts?: ImportBlockOpts
259
+ ): Promise<void>;
252
260
 
253
261
  /** Process execution payload envelope: verify, import to fork choice, and persist to DB */
254
262
  processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  import {Signature, aggregateSignatures} from "@chainsafe/blst";
2
2
  import {BitArray} from "@chainsafe/ssz";
3
3
  import {ChainForkConfig} from "@lodestar/config";
4
- import {MAX_COMMITTEES_PER_SLOT, PTC_SIZE} from "@lodestar/params";
4
+ import {MAX_COMMITTEES_PER_SLOT, MAX_PAYLOAD_ATTESTATIONS, PTC_SIZE} from "@lodestar/params";
5
5
  import {RootHex, Slot, gloas} from "@lodestar/types";
6
6
  import {MapDef, toRootHex} from "@lodestar/utils";
7
7
  import {Metrics} from "../../metrics/metrics.js";
@@ -95,13 +95,9 @@ export class PayloadAttestationPool {
95
95
 
96
96
  /**
97
97
  * Get payload attestations to be included in a block.
98
- * Pick the top `maxAttestation` number of attestations with the most votes
98
+ * Pick the top `MAX_PAYLOAD_ATTESTATIONS` aggregates with the most votes.
99
99
  */
100
- getPayloadAttestationsForBlock(
101
- beaconBlockRoot: BlockRootHex,
102
- slot: Slot,
103
- maxAttestation: number
104
- ): gloas.PayloadAttestation[] {
100
+ getPayloadAttestationsForBlock(beaconBlockRoot: BlockRootHex, slot: Slot): gloas.PayloadAttestation[] {
105
101
  const aggregateByDataRootByBlockRoot = this.aggregateByDataRootByBlockRootBySlot.get(slot);
106
102
 
107
103
  if (!aggregateByDataRootByBlockRoot) {
@@ -119,7 +115,32 @@ export class PayloadAttestationPool {
119
115
  return Array.from(aggregateByDataRoot.values())
120
116
  .slice()
121
117
  .sort((a, b) => b.aggregationBits.getTrueBitIndexes().length - a.aggregationBits.getTrueBitIndexes().length)
122
- .slice(0, maxAttestation)
118
+ .slice(0, MAX_PAYLOAD_ATTESTATIONS)
119
+ .map(fastToPayloadAttestation);
120
+ }
121
+
122
+ getAll(slot?: Slot): gloas.PayloadAttestation[] {
123
+ const aggregates: AggregateFast[] = [];
124
+
125
+ const addAggregates = (aggregateByDataRootByBlockRoot: Map<BlockRootHex, Map<DataRootHex, AggregateFast>>) => {
126
+ for (const aggregateByDataRoot of aggregateByDataRootByBlockRoot.values()) {
127
+ aggregates.push(...aggregateByDataRoot.values());
128
+ }
129
+ };
130
+
131
+ if (slot !== undefined) {
132
+ const aggregateByDataRootByBlockRoot = this.aggregateByDataRootByBlockRootBySlot.get(slot);
133
+ if (aggregateByDataRootByBlockRoot) {
134
+ addAggregates(aggregateByDataRootByBlockRoot);
135
+ }
136
+ } else {
137
+ for (const aggregateByDataRootByBlockRoot of this.aggregateByDataRootByBlockRootBySlot.values()) {
138
+ addAggregates(aggregateByDataRootByBlockRoot);
139
+ }
140
+ }
141
+
142
+ return aggregates
143
+ .sort((a, b) => b.aggregationBits.getTrueBitIndexes().length - a.aggregationBits.getTrueBitIndexes().length)
123
144
  .map(fastToPayloadAttestation);
124
145
  }
125
146
 
@@ -4,6 +4,7 @@ import {getSafeExecutionBlockHash} from "@lodestar/fork-choice";
4
4
  import {ForkPostBellatrix, ForkSeq, SLOTS_PER_EPOCH, isForkPostBellatrix} from "@lodestar/params";
5
5
  import {
6
6
  IBeaconStateView,
7
+ IBeaconStateViewBellatrix,
7
8
  StateHashTreeRootSource,
8
9
  computeEpochAtSlot,
9
10
  computeTimeAtSlot,
@@ -83,7 +84,7 @@ export class PrepareNextSlotScheduler {
83
84
  const headBlock = this.chain.recomputeForkChoiceHead(ForkchoiceCaller.prepareNextSlot);
84
85
  const {slot: headSlot, blockRoot: headRoot} = headBlock;
85
86
  // may be updated below if we predict a proposer-boost-reorg
86
- let updatedHeadRoot = headRoot;
87
+ let updatedHead = headBlock;
87
88
 
88
89
  // PS: previously this was comparing slots, but that gave no leway on the skipped
89
90
  // slots on epoch bounday. Making it more fluid.
@@ -148,7 +149,7 @@ export class PrepareNextSlotScheduler {
148
149
  {dontTransferCache: !isEpochTransition},
149
150
  RegenCaller.predictProposerHead
150
151
  );
151
- updatedHeadRoot = proposerHeadRoot;
152
+ updatedHead = proposerHead;
152
153
  }
153
154
 
154
155
  // Update the builder status, if enabled shoot an api call to check status
@@ -165,10 +166,22 @@ export class PrepareNextSlotScheduler {
165
166
  }
166
167
 
167
168
  let parentBlockHash: Bytes32;
169
+ // Apply parent payload once here as it's reused by EL prep and SSE emit below
170
+ let stateAfterParentPayload: IBeaconStateViewBellatrix = updatedPrepareState;
168
171
  if (isStatePostGloas(updatedPrepareState)) {
169
- parentBlockHash = this.chain.forkChoice.shouldExtendPayload(updatedHeadRoot)
170
- ? updatedPrepareState.latestExecutionPayloadBid.blockHash
171
- : updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
172
+ if (this.chain.forkChoice.shouldExtendPayload(updatedHead.blockRoot)) {
173
+ parentBlockHash = updatedPrepareState.latestExecutionPayloadBid.blockHash;
174
+ // Skip applying parent payload unless we're proposing the next slot or have to emit payload_attributes events
175
+ if (feeRecipient !== undefined || this.chain.opts.emitPayloadAttributes === true) {
176
+ const parentExecutionRequests = await this.chain.getParentExecutionRequests(
177
+ updatedHead.slot,
178
+ updatedHead.blockRoot
179
+ );
180
+ stateAfterParentPayload = updatedPrepareState.withParentPayloadApplied(parentExecutionRequests);
181
+ }
182
+ } else {
183
+ parentBlockHash = updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
184
+ }
172
185
  } else {
173
186
  parentBlockHash = updatedPrepareState.latestExecutionPayloadHeader.blockHash;
174
187
  }
@@ -189,11 +202,11 @@ export class PrepareNextSlotScheduler {
189
202
  this.chain,
190
203
  this.logger,
191
204
  fork as ForkPostBellatrix, // State is of execution type
192
- fromHex(updatedHeadRoot),
205
+ fromHex(updatedHead.blockRoot),
193
206
  parentBlockHash,
194
207
  safeBlockHash,
195
208
  finalizedBlockHash,
196
- updatedPrepareState,
209
+ stateAfterParentPayload,
197
210
  feeRecipient
198
211
  );
199
212
  this.logger.verbose("PrepareNextSlotScheduler prepared new payload", {
@@ -203,21 +216,30 @@ export class PrepareNextSlotScheduler {
203
216
  });
204
217
  }
205
218
 
219
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
220
+ // Cutoff = slot of the parent of the block we'll actually build on (post-reorg).
221
+ // Steady state: cache holds just 2 entries — head (parent for next-slot production)
222
+ // and head.parent (proposer-boost-reorg fallback). Anything older is evicted.
223
+ const updatedHeadParent = this.chain.forkChoice.getBlockHexDefaultStatus(updatedHead.parentRoot);
224
+ if (updatedHeadParent) {
225
+ this.chain.seenPayloadEnvelopeInputCache.pruneBelowParent(updatedHeadParent);
226
+ }
227
+ }
228
+
206
229
  this.computeStateHashTreeRoot(updatedPrepareState, isEpochTransition);
207
230
 
208
- // If emitPayloadAttributes is true emit a SSE payloadAttributes event
231
+ // If emitPayloadAttributes is true emit a SSE payloadAttributes event for
232
+ // every slot. Without the flag, only emit the event if we are proposing in the next slot.
209
233
  if (
210
- this.chain.opts.emitPayloadAttributes === true &&
234
+ (feeRecipient || this.chain.opts.emitPayloadAttributes === true) &&
211
235
  this.chain.emitter.listenerCount(routes.events.EventType.payloadAttributes)
212
236
  ) {
213
237
  const data = getPayloadAttributesForSSE(fork as ForkPostBellatrix, this.chain, {
214
- prepareState: updatedPrepareState,
238
+ prepareState: stateAfterParentPayload,
215
239
  prepareSlot,
216
- parentBlockRoot: fromHex(headRoot),
240
+ parentBlockRoot: fromHex(updatedHead.blockRoot),
217
241
  parentBlockHash,
218
- // The likely consumers of this API are builders and will anyway ignore the
219
- // feeRecipient, so just pass zero hash for now till a real use case arises
220
- feeRecipient: "0x0000000000000000000000000000000000000000000000000000000000000000",
242
+ feeRecipient: feeRecipient ?? "0x0000000000000000000000000000000000000000",
221
243
  });
222
244
  this.chain.emitter.emit(routes.events.EventType.payloadAttributes, {data, version: fork});
223
245
  }