@lodestar/beacon-node 1.47.0-dev.f591cb177e → 1.48.0-dev.67344272c0

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 (342) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +44 -12
  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 +21 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +2 -1
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  10. package/lib/api/impl/events/index.d.ts.map +1 -1
  11. package/lib/api/impl/events/index.js +2 -0
  12. package/lib/api/impl/events/index.js.map +1 -1
  13. package/lib/api/impl/lodestar/index.js +1 -1
  14. package/lib/api/impl/lodestar/index.js.map +1 -1
  15. package/lib/api/impl/validator/index.d.ts.map +1 -1
  16. package/lib/api/impl/validator/index.js +237 -49
  17. package/lib/api/impl/validator/index.js.map +1 -1
  18. package/lib/api/impl/validator/utils.js +1 -1
  19. package/lib/api/impl/validator/utils.js.map +1 -1
  20. package/lib/api/rest/base.d.ts.map +1 -1
  21. package/lib/api/rest/base.js +7 -0
  22. package/lib/api/rest/base.js.map +1 -1
  23. package/lib/chain/archiveStore/archiveStore.js +1 -1
  24. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  25. package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
  26. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  27. package/lib/chain/blocks/importExecutionPayload.js +11 -9
  28. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  29. package/lib/chain/blocks/index.d.ts.map +1 -1
  30. package/lib/chain/blocks/index.js +21 -13
  31. package/lib/chain/blocks/index.js.map +1 -1
  32. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
  33. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  34. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
  35. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  36. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
  37. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  38. package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
  39. package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -1
  40. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  41. package/lib/chain/blocks/verifyBlock.js +5 -2
  42. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  43. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  44. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
  45. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  46. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  47. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  48. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  49. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  50. package/lib/chain/bls/index.d.ts +1 -1
  51. package/lib/chain/bls/index.d.ts.map +1 -1
  52. package/lib/chain/bls/interface.d.ts +5 -5
  53. package/lib/chain/bls/interface.d.ts.map +1 -1
  54. package/lib/chain/bls/multithread/index.d.ts +5 -11
  55. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  56. package/lib/chain/bls/multithread/index.js +116 -101
  57. package/lib/chain/bls/multithread/index.js.map +1 -1
  58. package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
  59. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  60. package/lib/chain/bls/multithread/jobItem.js +10 -65
  61. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  62. package/lib/chain/bls/multithread/types.d.ts +29 -8
  63. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  64. package/lib/chain/bls/multithread/types.js +12 -0
  65. package/lib/chain/bls/multithread/types.js.map +1 -1
  66. package/lib/chain/bls/multithread/utils.d.ts +4 -0
  67. package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
  68. package/lib/chain/bls/multithread/utils.js +10 -0
  69. package/lib/chain/bls/multithread/utils.js.map +1 -1
  70. package/lib/chain/bls/multithread/worker.js +49 -23
  71. package/lib/chain/bls/multithread/worker.js.map +1 -1
  72. package/lib/chain/bls/singleThread.d.ts +4 -10
  73. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  74. package/lib/chain/bls/singleThread.js +8 -45
  75. package/lib/chain/bls/singleThread.js.map +1 -1
  76. package/lib/chain/bls/utils.d.ts +4 -4
  77. package/lib/chain/bls/utils.d.ts.map +1 -1
  78. package/lib/chain/bls/utils.js +18 -19
  79. package/lib/chain/bls/utils.js.map +1 -1
  80. package/lib/chain/chain.d.ts +9 -4
  81. package/lib/chain/chain.d.ts.map +1 -1
  82. package/lib/chain/chain.js +22 -8
  83. package/lib/chain/chain.js.map +1 -1
  84. package/lib/chain/errors/blockError.d.ts +1 -0
  85. package/lib/chain/errors/blockError.d.ts.map +1 -1
  86. package/lib/chain/errors/blockError.js +6 -1
  87. package/lib/chain/errors/blockError.js.map +1 -1
  88. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  89. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  90. package/lib/chain/errors/executionPayloadBid.js +1 -0
  91. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  92. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  93. package/lib/chain/forkChoice/index.js +4 -0
  94. package/lib/chain/forkChoice/index.js.map +1 -1
  95. package/lib/chain/interface.d.ts +8 -4
  96. package/lib/chain/interface.d.ts.map +1 -1
  97. package/lib/chain/interface.js.map +1 -1
  98. package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
  99. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  100. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  101. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  102. package/lib/chain/opPools/attestationPool.js +1 -1
  103. package/lib/chain/opPools/attestationPool.js.map +1 -1
  104. package/lib/chain/opPools/deferredVoluntaryExitPool.d.ts +16 -0
  105. package/lib/chain/opPools/deferredVoluntaryExitPool.d.ts.map +1 -0
  106. package/lib/chain/opPools/deferredVoluntaryExitPool.js +57 -0
  107. package/lib/chain/opPools/deferredVoluntaryExitPool.js.map +1 -0
  108. package/lib/chain/opPools/executionPayloadBidPool.d.ts +7 -2
  109. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
  110. package/lib/chain/opPools/executionPayloadBidPool.js +4 -4
  111. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
  112. package/lib/chain/opPools/index.d.ts +2 -1
  113. package/lib/chain/opPools/index.d.ts.map +1 -1
  114. package/lib/chain/opPools/index.js +1 -0
  115. package/lib/chain/opPools/index.js.map +1 -1
  116. package/lib/chain/opPools/payloadAttestationPool.js +3 -3
  117. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  118. package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
  119. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  120. package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
  121. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  122. package/lib/chain/opPools/utils.d.ts +1 -1
  123. package/lib/chain/opPools/utils.d.ts.map +1 -1
  124. package/lib/chain/opPools/utils.js +1 -1
  125. package/lib/chain/opPools/utils.js.map +1 -1
  126. package/lib/chain/prepareNextSlot.d.ts +5 -0
  127. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  128. package/lib/chain/prepareNextSlot.js +47 -6
  129. package/lib/chain/prepareNextSlot.js.map +1 -1
  130. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  131. package/lib/chain/produceBlock/computeNewStateRoot.js +3 -25
  132. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  133. package/lib/chain/produceBlock/produceBlockBody.js +1 -1
  134. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  135. package/lib/chain/regen/interface.d.ts +5 -2
  136. package/lib/chain/regen/interface.d.ts.map +1 -1
  137. package/lib/chain/regen/interface.js +3 -0
  138. package/lib/chain/regen/interface.js.map +1 -1
  139. package/lib/chain/regen/queued.d.ts +2 -2
  140. package/lib/chain/regen/queued.d.ts.map +1 -1
  141. package/lib/chain/regen/queued.js +5 -5
  142. package/lib/chain/regen/queued.js.map +1 -1
  143. package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
  144. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  145. package/lib/chain/seenCache/seenAttesters.js +25 -4
  146. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  147. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +28 -1
  148. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  149. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
  150. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  151. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +5 -1
  152. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  153. package/lib/chain/stateCache/fifoBlockStateCache.js +6 -0
  154. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  155. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +47 -5
  156. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  157. package/lib/chain/stateCache/persistentCheckpointsCache.js +117 -7
  158. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  159. package/lib/chain/stateCache/types.d.ts +3 -3
  160. package/lib/chain/stateCache/types.d.ts.map +1 -1
  161. package/lib/chain/validation/attestation.d.ts.map +1 -1
  162. package/lib/chain/validation/attestation.js +1 -4
  163. package/lib/chain/validation/attestation.js.map +1 -1
  164. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  165. package/lib/chain/validation/attesterSlashing.js +1 -1
  166. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  167. package/lib/chain/validation/block.d.ts.map +1 -1
  168. package/lib/chain/validation/block.js +40 -10
  169. package/lib/chain/validation/block.js.map +1 -1
  170. package/lib/chain/validation/executionPayloadBid.d.ts +15 -3
  171. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  172. package/lib/chain/validation/executionPayloadBid.js +166 -12
  173. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  174. package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
  175. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  176. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  177. package/lib/chain/validation/payloadAttestationMessage.js +5 -14
  178. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  179. package/lib/chain/validation/proposerPreferences.js +2 -2
  180. package/lib/chain/validation/proposerPreferences.js.map +1 -1
  181. package/lib/chain/validation/proposerSlashing.js +1 -1
  182. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  183. package/lib/chain/validation/voluntaryExit.d.ts +9 -1
  184. package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
  185. package/lib/chain/validation/voluntaryExit.js +46 -1
  186. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  187. package/lib/execution/builder/apiClient.d.ts +70 -0
  188. package/lib/execution/builder/apiClient.d.ts.map +1 -0
  189. package/lib/execution/builder/apiClient.js +202 -0
  190. package/lib/execution/builder/apiClient.js.map +1 -0
  191. package/lib/execution/builder/validateBid.d.ts +23 -0
  192. package/lib/execution/builder/validateBid.d.ts.map +1 -0
  193. package/lib/execution/builder/validateBid.js +119 -0
  194. package/lib/execution/builder/validateBid.js.map +1 -0
  195. package/lib/metrics/metrics/lodestar.d.ts +84 -23
  196. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  197. package/lib/metrics/metrics/lodestar.js +161 -55
  198. package/lib/metrics/metrics/lodestar.js.map +1 -1
  199. package/lib/network/gossip/topic.d.ts +13 -0
  200. package/lib/network/gossip/topic.d.ts.map +1 -1
  201. package/lib/network/gossip/topic.js +37 -0
  202. package/lib/network/gossip/topic.js.map +1 -1
  203. package/lib/network/network.d.ts.map +1 -1
  204. package/lib/network/network.js +23 -43
  205. package/lib/network/network.js.map +1 -1
  206. package/lib/network/processor/constants.d.ts +7 -0
  207. package/lib/network/processor/constants.d.ts.map +1 -0
  208. package/lib/network/processor/constants.js +7 -0
  209. package/lib/network/processor/constants.js.map +1 -0
  210. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  211. package/lib/network/processor/gossipHandlers.js +6 -2
  212. package/lib/network/processor/gossipHandlers.js.map +1 -1
  213. package/lib/network/processor/gossipQueues/indexed.d.ts.map +1 -1
  214. package/lib/network/processor/gossipQueues/indexed.js +0 -1
  215. package/lib/network/processor/gossipQueues/indexed.js.map +1 -1
  216. package/lib/network/processor/index.d.ts +3 -0
  217. package/lib/network/processor/index.d.ts.map +1 -1
  218. package/lib/network/processor/index.js +52 -23
  219. package/lib/network/processor/index.js.map +1 -1
  220. package/lib/network/reqresp/score.d.ts.map +1 -1
  221. package/lib/network/reqresp/score.js +5 -11
  222. package/lib/network/reqresp/score.js.map +1 -1
  223. package/lib/network/util.d.ts +0 -1
  224. package/lib/network/util.d.ts.map +1 -1
  225. package/lib/network/util.js +0 -4
  226. package/lib/network/util.js.map +1 -1
  227. package/lib/node/deferredVoluntaryExitPublisher.d.ts +15 -0
  228. package/lib/node/deferredVoluntaryExitPublisher.d.ts.map +1 -0
  229. package/lib/node/deferredVoluntaryExitPublisher.js +38 -0
  230. package/lib/node/deferredVoluntaryExitPublisher.js.map +1 -0
  231. package/lib/node/nodejs.d.ts +2 -1
  232. package/lib/node/nodejs.d.ts.map +1 -1
  233. package/lib/node/nodejs.js +7 -0
  234. package/lib/node/nodejs.js.map +1 -1
  235. package/lib/sync/range/batch.d.ts +23 -5
  236. package/lib/sync/range/batch.d.ts.map +1 -1
  237. package/lib/sync/range/batch.js +61 -22
  238. package/lib/sync/range/batch.js.map +1 -1
  239. package/lib/sync/range/chain.d.ts +2 -1
  240. package/lib/sync/range/chain.d.ts.map +1 -1
  241. package/lib/sync/range/chain.js +32 -12
  242. package/lib/sync/range/chain.js.map +1 -1
  243. package/lib/sync/range/range.js +1 -1
  244. package/lib/sync/range/range.js.map +1 -1
  245. package/lib/sync/types.d.ts +32 -0
  246. package/lib/sync/types.d.ts.map +1 -1
  247. package/lib/sync/types.js +33 -0
  248. package/lib/sync/types.js.map +1 -1
  249. package/lib/sync/unknownBlock.d.ts +6 -2
  250. package/lib/sync/unknownBlock.d.ts.map +1 -1
  251. package/lib/sync/unknownBlock.js +143 -68
  252. package/lib/sync/unknownBlock.js.map +1 -1
  253. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  254. package/lib/sync/utils/downloadByRange.js +16 -11
  255. package/lib/sync/utils/downloadByRange.js.map +1 -1
  256. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  257. package/lib/sync/utils/downloadByRoot.js +3 -1
  258. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  259. package/package.json +35 -35
  260. package/src/api/impl/beacon/blocks/index.ts +51 -15
  261. package/src/api/impl/beacon/pool/index.ts +22 -2
  262. package/src/api/impl/beacon/state/utils.ts +2 -1
  263. package/src/api/impl/events/index.ts +3 -1
  264. package/src/api/impl/lodestar/index.ts +1 -1
  265. package/src/api/impl/validator/index.ts +290 -49
  266. package/src/api/impl/validator/utils.ts +1 -1
  267. package/src/api/rest/base.ts +7 -0
  268. package/src/chain/archiveStore/archiveStore.ts +1 -1
  269. package/src/chain/blocks/importExecutionPayload.ts +12 -11
  270. package/src/chain/blocks/index.ts +25 -13
  271. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
  272. package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
  273. package/src/chain/blocks/verifyBlock.ts +5 -2
  274. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
  275. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
  276. package/src/chain/bls/index.ts +1 -1
  277. package/src/chain/bls/interface.ts +7 -3
  278. package/src/chain/bls/multithread/index.ts +148 -120
  279. package/src/chain/bls/multithread/jobItem.ts +12 -82
  280. package/src/chain/bls/multithread/types.ts +33 -8
  281. package/src/chain/bls/multithread/utils.ts +11 -0
  282. package/src/chain/bls/multithread/worker.ts +85 -27
  283. package/src/chain/bls/singleThread.ts +11 -55
  284. package/src/chain/bls/utils.ts +23 -24
  285. package/src/chain/chain.ts +25 -7
  286. package/src/chain/errors/blockError.ts +8 -2
  287. package/src/chain/errors/executionPayloadBid.ts +6 -0
  288. package/src/chain/forkChoice/index.ts +4 -0
  289. package/src/chain/interface.ts +8 -3
  290. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  291. package/src/chain/opPools/attestationPool.ts +1 -1
  292. package/src/chain/opPools/deferredVoluntaryExitPool.ts +65 -0
  293. package/src/chain/opPools/executionPayloadBidPool.ts +13 -7
  294. package/src/chain/opPools/index.ts +2 -1
  295. package/src/chain/opPools/payloadAttestationPool.ts +3 -3
  296. package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
  297. package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
  298. package/src/chain/opPools/utils.ts +1 -1
  299. package/src/chain/prepareNextSlot.ts +49 -6
  300. package/src/chain/produceBlock/computeNewStateRoot.ts +3 -38
  301. package/src/chain/produceBlock/produceBlockBody.ts +1 -1
  302. package/src/chain/regen/interface.ts +5 -2
  303. package/src/chain/regen/queued.ts +5 -5
  304. package/src/chain/seenCache/seenAttesters.ts +31 -5
  305. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
  306. package/src/chain/stateCache/fifoBlockStateCache.ts +8 -1
  307. package/src/chain/stateCache/persistentCheckpointsCache.ts +133 -8
  308. package/src/chain/stateCache/types.ts +3 -3
  309. package/src/chain/validation/attestation.ts +1 -7
  310. package/src/chain/validation/attesterSlashing.ts +1 -8
  311. package/src/chain/validation/block.ts +43 -10
  312. package/src/chain/validation/executionPayloadBid.ts +193 -14
  313. package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
  314. package/src/chain/validation/payloadAttestationMessage.ts +6 -17
  315. package/src/chain/validation/proposerPreferences.ts +3 -3
  316. package/src/chain/validation/proposerSlashing.ts +1 -1
  317. package/src/chain/validation/voluntaryExit.ts +59 -2
  318. package/src/execution/builder/apiClient.ts +264 -0
  319. package/src/execution/builder/validateBid.ts +181 -0
  320. package/src/metrics/metrics/lodestar.ts +176 -61
  321. package/src/network/gossip/topic.ts +38 -0
  322. package/src/network/network.ts +29 -54
  323. package/src/network/processor/constants.ts +6 -0
  324. package/src/network/processor/gossipHandlers.ts +6 -2
  325. package/src/network/processor/gossipQueues/indexed.ts +0 -1
  326. package/src/network/processor/index.ts +67 -30
  327. package/src/network/reqresp/score.ts +5 -11
  328. package/src/network/util.ts +0 -5
  329. package/src/node/deferredVoluntaryExitPublisher.ts +54 -0
  330. package/src/node/nodejs.ts +10 -1
  331. package/src/sync/range/batch.ts +83 -28
  332. package/src/sync/range/chain.ts +35 -13
  333. package/src/sync/range/range.ts +1 -1
  334. package/src/sync/types.ts +33 -0
  335. package/src/sync/unknownBlock.ts +167 -73
  336. package/src/sync/utils/downloadByRange.ts +21 -12
  337. package/src/sync/utils/downloadByRoot.ts +3 -1
  338. package/lib/chain/bls/maybeBatch.d.ts +0 -12
  339. package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
  340. package/lib/chain/bls/maybeBatch.js +0 -35
  341. package/lib/chain/bls/maybeBatch.js.map +0 -1
  342. package/src/chain/bls/maybeBatch.ts +0 -45
@@ -52,12 +52,16 @@ import {
52
52
  import {
53
53
  GWEI_TO_WEI,
54
54
  TimeoutError,
55
+ byteArrayEquals,
55
56
  defer,
56
57
  formatWeiToEth,
57
58
  fromHex,
59
+ prettyGweiToEth,
58
60
  prettyWeiToEth,
59
61
  resolveOrRacePromises,
62
+ sleep,
60
63
  toHex,
64
+ toPrintableUrl,
61
65
  toRootHex,
62
66
  } from "@lodestar/utils";
63
67
  import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator";
@@ -72,6 +76,7 @@ import {
72
76
  SyncCommitteeErrorCode,
73
77
  } from "../../../chain/errors/index.js";
74
78
  import {ChainEvent, CommonBlockBody} from "../../../chain/index.js";
79
+ import {PooledExecutionPayloadBid} from "../../../chain/opPools/index.js";
75
80
  import {PREPARE_NEXT_SLOT_BPS} from "../../../chain/prepareNextSlot.js";
76
81
  import {BlockType, ProduceFullDeneb, ProduceFullGloas} from "../../../chain/produceBlock/index.js";
77
82
  import {RegenCaller} from "../../../chain/regen/index.js";
@@ -80,7 +85,9 @@ import {validateApiAggregateAndProof} from "../../../chain/validation/index.js";
80
85
  import {validateGossipProposerPreferences} from "../../../chain/validation/proposerPreferences.js";
81
86
  import {validateSyncCommitteeGossipContributionAndProof} from "../../../chain/validation/syncCommitteeContributionAndProof.js";
82
87
  import {ZERO_HASH} from "../../../constants/index.js";
88
+ import {BUILDER_BID_DEADLINE_MS, BuilderApiBid, decodeBuilderUrl} from "../../../execution/builder/apiClient.js";
83
89
  import {BuilderStatus, NoBidReceived} from "../../../execution/builder/http.js";
90
+ import {getBuilderBidTotalGwei, validateBuilderApiExecutionPayloadBid} from "../../../execution/builder/validateBid.js";
84
91
  import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossipHandlers.js";
85
92
  import {CommitteeSubscription} from "../../../network/subnets/index.js";
86
93
  import {callInNextEventLoop} from "../../../util/eventLoop.js";
@@ -112,6 +119,55 @@ import {
112
119
  const BLOCK_PRODUCTION_RACE_CUTOFF_MS = 2_000;
113
120
  /** Overall timeout for execution and block production apis */
114
121
  const BLOCK_PRODUCTION_RACE_TIMEOUT_MS = 12_000;
122
+ /** Rejection message of the bid block branch when there is no viable bid to commit to */
123
+ const NO_BID_AVAILABLE = "No builder bid available";
124
+
125
+ type BidCandidate = {
126
+ signedBid: gloas.SignedExecutionPayloadBid;
127
+ /** Total payment in Gwei, counting the execution payment at most at the entry's cap */
128
+ totalGwei: bigint;
129
+ boostFactor: bigint;
130
+ url?: string;
131
+ /** Time in milliseconds from the slot start when the bid was received */
132
+ receivedMs: number;
133
+ };
134
+
135
+ /**
136
+ * Return the best bid by boosted total payment. A candidate with the max boost factor is
137
+ * preferred over any other regardless of value, ties prefer a builder api bid over the
138
+ * p2p bid, and the earlier received bid between builder api bids.
139
+ */
140
+ function selectBestBid(candidates: BidCandidate[]): BidCandidate | null {
141
+ const boostedValue = ({totalGwei, boostFactor}: BidCandidate): bigint => boostFactor * totalGwei;
142
+ let best: BidCandidate | null = null;
143
+ for (const candidate of candidates) {
144
+ if (best === null) {
145
+ best = candidate;
146
+ continue;
147
+ }
148
+ // Preserve max boost preference before comparing bid values
149
+ const candidateIsMaxBoost = candidate.boostFactor === MAX_BUILDER_BOOST_FACTOR;
150
+ const bestIsMaxBoost = best.boostFactor === MAX_BUILDER_BOOST_FACTOR;
151
+ if (candidateIsMaxBoost !== bestIsMaxBoost) {
152
+ if (candidateIsMaxBoost) {
153
+ best = candidate;
154
+ }
155
+ continue;
156
+ }
157
+ const candidateValue = boostedValue(candidate);
158
+ const bestValue = boostedValue(best);
159
+ if (candidateValue > bestValue) {
160
+ best = candidate;
161
+ } else if (
162
+ candidateValue === bestValue &&
163
+ // A tie prefers a builder api bid over the p2p bid, and the earlier received bid otherwise
164
+ (best.url === undefined || (candidate.url !== undefined && candidate.receivedMs < best.receivedMs))
165
+ ) {
166
+ best = candidate;
167
+ }
168
+ }
169
+ return best;
170
+ }
115
171
 
116
172
  type ProduceBlockContentsRes = {executionPayloadValue: Wei; consensusBlockValue: Wei} & {
117
173
  data: BlockContents;
@@ -857,7 +913,7 @@ export function getValidatorApi(
857
913
  feeRecipient,
858
914
  strictFeeRecipientCheck,
859
915
  includePayload,
860
- builderBoostFactor,
916
+ builderConfig,
861
917
  }) {
862
918
  const fork = config.getForkName(slot);
863
919
 
@@ -865,7 +921,7 @@ export function getValidatorApi(
865
921
  throw new ApiError(400, `produceBlockV4 not supported for pre-gloas fork=${fork}`);
866
922
  }
867
923
 
868
- builderBoostFactor = builderBoostFactor ?? BigInt(100);
924
+ const builderBoostFactor = builderConfig.builderBoostFactor;
869
925
  if (builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) {
870
926
  throw new ApiError(400, `Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR`);
871
927
  }
@@ -892,32 +948,122 @@ export function getValidatorApi(
892
948
  })
893
949
  );
894
950
 
895
- // TODO GLOAS: add external builder api support when it is implemented
896
951
  const isBuildingOnFull = chain.forkChoice.shouldBuildOnFull(parentBlock, slot);
897
952
  const bidParentBlockHash = isBuildingOnFull ? parentBlock.executionPayloadBlockHash : parentBlock.parentBlockHash;
953
+ // Post-gloas every proposal parent has an execution payload hash
954
+ if (bidParentBlockHash === null) {
955
+ throw new ApiError(500, `Unknown parent block hash for proposal parent ${parentBlockRootHex}`);
956
+ }
898
957
  const circuitBreakerActive = chain.builderCircuitBreaker.isActive(slot, parentBlock);
899
- // Keep a builder bid as fallback unless the circuit breaker is active
900
- const builderBid = circuitBreakerActive
901
- ? null
902
- : chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
903
958
 
904
- const logCtx = {
905
- slot,
906
- parentSlot,
907
- parentBlockRoot: parentBlockRootHex,
908
- parentBlockHash: parentBlock.executionPayloadBlockHash,
909
- fork,
910
- builderBoostFactor,
911
- strictFeeRecipientCheck,
912
- circuitBreakerActive,
913
- ...(builderBid !== null
914
- ? {
915
- bidValue: builderBid.message.value,
916
- builderIndex: builderBid.message.builderIndex,
917
- bidBlockHash: toRootHex(builderBid.message.blockHash),
959
+ // Fire builder API bid requests while the local payload is built, one request per entry.
960
+ // Any entry failure yields no bid and never fails block production.
961
+ let builderApiBidsPromise: Promise<BuilderApiBid[]> = Promise.resolve([]);
962
+ if (builderConfig.builders.length > 0 && !circuitBreakerActive) {
963
+ try {
964
+ const proposerIndex = chain.getHeadState().getBeaconProposer(slot);
965
+ const proposerPubkey = chain.pubkeyCache.getOrThrow(proposerIndex).toBytes();
966
+ builderApiBidsPromise = chain.builderApiClient.getExecutionPayloadBids(
967
+ builderConfig.builders,
968
+ slot,
969
+ fromHex(bidParentBlockHash),
970
+ parentBlockRoot,
971
+ proposerPubkey
972
+ );
973
+ } catch (e) {
974
+ logger.warn("Unable to request builder API bids", {slot}, e as Error);
975
+ }
976
+ }
977
+
978
+ // A builder bid is expected if builders are configured or a p2p bid was already received.
979
+ // Used by the censorship override which may run before the bid deadline
980
+ const builderBidExpected =
981
+ builderConfig.builders.length > 0 ||
982
+ (!circuitBreakerActive &&
983
+ chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex) !== null);
984
+
985
+ // Select the p2p bid once builders had time to bid up, matching the deadline advertised
986
+ // on builder API bid requests, unless the circuit breaker is active
987
+ const p2pBidPromise: Promise<PooledExecutionPayloadBid | null> = circuitBreakerActive
988
+ ? Promise.resolve(null)
989
+ : sleep(Math.max(0, BUILDER_BID_DEADLINE_MS - chain.clock.msFromSlot(slot))).then(() => {
990
+ const p2pBid = chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
991
+ // Discard p2p bids below the proposer's configured floor on the total payment.
992
+ // A p2p bid's total is just its value since gossip validation enforces executionPayment=0.
993
+ if (p2pBid !== null && BigInt(p2pBid.signedBid.message.value) < builderConfig.minBid) {
994
+ logger.info("Best p2p bid below configured minimum", {
995
+ slot,
996
+ bidValue: prettyGweiToEth(p2pBid.signedBid.message.value),
997
+ minBid: prettyGweiToEth(builderConfig.minBid),
998
+ });
999
+ return null;
918
1000
  }
919
- : {}),
920
- };
1001
+ return p2pBid;
1002
+ });
1003
+
1004
+ // Candidates are ranked by their boosted counted total payment, the p2p bid is governed
1005
+ // by the top-level factors and each builder API bid by its own entry. Ties prefer the
1006
+ // earliest received builder API bid, so the signed block can be routed back to its
1007
+ // builder directly.
1008
+ const bestBidPromise: Promise<BidCandidate | null> = (async () => {
1009
+ const [builderApiBids, p2pBid] = await Promise.all([builderApiBidsPromise, p2pBidPromise]);
1010
+ let parentExecutionRequestsPromise: Promise<gloas.ExecutionRequests> | null = null;
1011
+
1012
+ const candidates = (
1013
+ await Promise.all(
1014
+ builderApiBids.map(async ({url, entry, signedBid, receivedMs}): Promise<BidCandidate | null> => {
1015
+ try {
1016
+ await validateBuilderApiExecutionPayloadBid(chain, signedBid, {
1017
+ slot,
1018
+ parentBlock,
1019
+ parentBlockHash: bidParentBlockHash,
1020
+ parentBlockRoot: parentBlockRootHex,
1021
+ entry,
1022
+ getParentExecutionRequests: () => {
1023
+ parentExecutionRequestsPromise ??= chain.getParentExecutionRequests(parentSlot, parentBlockRootHex);
1024
+ return parentExecutionRequestsPromise;
1025
+ },
1026
+ });
1027
+ return {
1028
+ signedBid,
1029
+ totalGwei: getBuilderBidTotalGwei(signedBid.message, entry.maxExecutionPayment),
1030
+ boostFactor: entry.builderBoostFactor,
1031
+ url,
1032
+ receivedMs,
1033
+ };
1034
+ } catch (e) {
1035
+ metrics?.builderApi.bidsDiscarded.inc();
1036
+ logger.warn("Ignoring invalid builder API bid", {slot, builder: toPrintableUrl(url)}, e as Error);
1037
+ return null;
1038
+ }
1039
+ })
1040
+ )
1041
+ ).filter((candidate): candidate is BidCandidate => candidate !== null);
1042
+
1043
+ if (p2pBid !== null) {
1044
+ candidates.push({
1045
+ signedBid: p2pBid.signedBid,
1046
+ totalGwei: BigInt(p2pBid.signedBid.message.value),
1047
+ boostFactor: builderConfig.builderBoostFactor,
1048
+ receivedMs: p2pBid.receivedMs,
1049
+ });
1050
+ }
1051
+
1052
+ const best = selectBestBid(candidates);
1053
+ if (candidates.length > 0) {
1054
+ logger.debug("Ranked builder bid candidates", {
1055
+ slot,
1056
+ candidates: candidates
1057
+ .map(
1058
+ (candidate) =>
1059
+ `${candidate.url ?? "p2p"}:total=${prettyGweiToEth(candidate.totalGwei)}:boost=${candidate.boostFactor}:received=${candidate.receivedMs}ms`
1060
+ )
1061
+ .join(","),
1062
+ bidSource: best?.url ?? "p2p",
1063
+ });
1064
+ }
1065
+ return best;
1066
+ })();
921
1067
 
922
1068
  const commonBlockBodyPromise = chain.produceCommonBlockBody({
923
1069
  slot,
@@ -937,9 +1083,6 @@ export function getValidatorApi(
937
1083
  };
938
1084
 
939
1085
  metrics?.blockProductionRequests.inc({source: ProducedBlockSource.engine});
940
- if (builderBid !== null) {
941
- metrics?.blockProductionRequests.inc({source: ProducedBlockSource.builder});
942
- }
943
1086
 
944
1087
  const timed = <T>(source: ProducedBlockSource, fn: () => Promise<T>): Promise<T> => {
945
1088
  const t = metrics?.blockProductionTime.startTimer();
@@ -956,19 +1099,25 @@ export function getValidatorApi(
956
1099
  const enginePromise: ReturnType<typeof chain.produceBlock> = timed(ProducedBlockSource.engine, () =>
957
1100
  chain.produceBlock(baseAttrs)
958
1101
  ).then((engineBlock) => {
959
- // No need to wait for the bid block if the engine block will always be selected due to
960
- // suspected builder censorship or a builder boost factor of 0
961
- if (engineBlock.shouldOverrideBuilder || builderBoostFactor === BigInt(0)) {
1102
+ // No need to wait for the bid block if the engine block will always be selected, either
1103
+ // due to suspected builder censorship, or because no builders are configured and the
1104
+ // boost factor of 0 always prefers the local block over p2p bids
1105
+ if (engineBlock.shouldOverrideBuilder || (builderConfig.builders.length === 0 && builderBoostFactor === 0n)) {
962
1106
  controller.abort();
963
1107
  }
964
1108
  return engineBlock;
965
1109
  });
966
- const bidPromise: ReturnType<typeof chain.produceBlock> =
967
- builderBid !== null
968
- ? timed(ProducedBlockSource.builder, () => chain.produceBlock({...baseAttrs, builderBid}))
969
- : Promise.reject(new Error("No builder bid available"));
1110
+ const bidBlockPromise: ReturnType<typeof chain.produceBlock> = bestBidPromise.then((candidate) => {
1111
+ if (candidate === null) {
1112
+ throw new Error(NO_BID_AVAILABLE);
1113
+ }
1114
+ metrics?.blockProductionRequests.inc({source: ProducedBlockSource.builder});
1115
+ return timed(ProducedBlockSource.builder, () =>
1116
+ chain.produceBlock({...baseAttrs, builderBid: candidate.signedBid})
1117
+ );
1118
+ });
970
1119
 
971
- const [engineResult, bidResult] = await resolveOrRacePromises([enginePromise, bidPromise], {
1120
+ const [engineResult, bidBlockResult] = await resolveOrRacePromises([enginePromise, bidBlockPromise], {
972
1121
  resolveTimeoutMs: cutoffMs,
973
1122
  raceTimeoutMs: BLOCK_PRODUCTION_RACE_TIMEOUT_MS,
974
1123
  signal: controller.signal,
@@ -977,29 +1126,74 @@ export function getValidatorApi(
977
1126
  let bestResult: typeof engineResult | null = null;
978
1127
  let source: ProducedBlockSource = ProducedBlockSource.engine;
979
1128
 
1129
+ // Resolved instantly whenever the bid branch produced a block
1130
+ const bestBid = bidBlockResult.status === "fulfilled" ? await bestBidPromise : null;
1131
+
1132
+ const logCtx = {
1133
+ slot,
1134
+ parentSlot,
1135
+ parentBlockRoot: parentBlockRootHex,
1136
+ parentBlockHash: parentBlock.executionPayloadBlockHash,
1137
+ fork,
1138
+ builderBoostFactor,
1139
+ strictFeeRecipientCheck,
1140
+ circuitBreakerActive,
1141
+ builderEntries: builderConfig.builders.length,
1142
+ ...(bestBid !== null
1143
+ ? {
1144
+ bidSource: bestBid.url !== undefined ? toPrintableUrl(bestBid.url) : "p2p",
1145
+ bidValue: prettyGweiToEth(bestBid.signedBid.message.value),
1146
+ bidExecutionPayment: prettyGweiToEth(bestBid.signedBid.message.executionPayment),
1147
+ // The full bid total and the counted total used during bid selection
1148
+ bidTotal: prettyGweiToEth(
1149
+ BigInt(bestBid.signedBid.message.value) + bestBid.signedBid.message.executionPayment
1150
+ ),
1151
+ bidCountedTotal: prettyGweiToEth(bestBid.totalGwei),
1152
+ bidBoostFactor: bestBid.boostFactor,
1153
+ builderIndex: bestBid.signedBid.message.builderIndex,
1154
+ bidBlockHash: toRootHex(bestBid.signedBid.message.blockHash),
1155
+ bidReceivedMs: bestBid.receivedMs,
1156
+ }
1157
+ : {}),
1158
+ };
1159
+
980
1160
  // handle shouldOverrideBuilder separately
981
- if (engineResult.status === "fulfilled" && engineResult.value.shouldOverrideBuilder && builderBid !== null) {
1161
+ if (
1162
+ engineResult.status === "fulfilled" &&
1163
+ engineResult.value.shouldOverrideBuilder &&
1164
+ (builderBidExpected || bidBlockResult.status === "fulfilled")
1165
+ ) {
982
1166
  source = ProducedBlockSource.engine;
983
1167
  bestResult = engineResult;
984
1168
  metrics?.blockProductionSelectionResults.inc({
985
1169
  source: ProducedBlockSource.engine,
986
1170
  reason: EngineBlockSelectionReason.BuilderCensorship,
987
1171
  });
988
- logger.warn("Selected local block: censorship suspected in builder bid", logCtx);
989
- } else if (engineResult.status === "fulfilled" && bidResult.status === "fulfilled") {
1172
+ logger.warn("Selected local block: censorship suspected in builder bid", {
1173
+ ...logCtx,
1174
+ durationMs: engineResult.durationMs,
1175
+ ...getBlockValueLogInfo(engineResult.value),
1176
+ });
1177
+ } else if (engineResult.status === "fulfilled" && bidBlockResult.status === "fulfilled") {
990
1178
  const result = selectBlockProductionSourceByBoostFactor({
991
- builderBoostFactor,
1179
+ builderBoostFactor: bestBid?.boostFactor ?? builderBoostFactor,
992
1180
  engineExecutionPayloadValue: engineResult.value.executionPayloadValue,
993
- // The bid value is the payment to the proposer, in Gwei
994
- builderExecutionPayloadValue: BigInt(builderBid?.message.value ?? 0) * GWEI_TO_WEI,
1181
+ // The bid total payment is its value plus its counted executionPayment, in Gwei
1182
+ builderExecutionPayloadValue: (bestBid?.totalGwei ?? 0n) * GWEI_TO_WEI,
995
1183
  });
996
1184
  source = result.source;
997
1185
  metrics?.blockProductionSelectionResults.inc(result);
998
- logger.info(`Selected ${source} block`, {reason: result.reason, ...logCtx});
999
- bestResult = source === ProducedBlockSource.builder ? bidResult : engineResult;
1000
- } else if (bidResult.status === "fulfilled") {
1186
+ logger.info(`Selected ${source} block`, {
1187
+ reason: result.reason,
1188
+ ...logCtx,
1189
+ engineDurationMs: engineResult.durationMs,
1190
+ ...getBlockValueLogInfo(engineResult.value, ProducedBlockSource.engine),
1191
+ builderDurationMs: bidBlockResult.durationMs,
1192
+ });
1193
+ bestResult = source === ProducedBlockSource.builder ? bidBlockResult : engineResult;
1194
+ } else if (bidBlockResult.status === "fulfilled") {
1001
1195
  source = ProducedBlockSource.builder;
1002
- bestResult = bidResult;
1196
+ bestResult = bidBlockResult;
1003
1197
  const reason =
1004
1198
  engineResult.status === "pending"
1005
1199
  ? BuilderBlockSelectionReason.EnginePending
@@ -1008,28 +1202,32 @@ export function getValidatorApi(
1008
1202
  logger.info("Selected builder bid block: no local block produced", {
1009
1203
  reason,
1010
1204
  ...logCtx,
1205
+ durationMs: bidBlockResult.durationMs,
1206
+ ...getBlockValueLogInfo(bidBlockResult.value),
1011
1207
  error: engineResult.status === "rejected" ? (engineResult.reason as Error).message : undefined,
1012
1208
  });
1013
1209
  } else if (engineResult.status === "fulfilled") {
1014
1210
  source = ProducedBlockSource.engine;
1015
1211
  bestResult = engineResult;
1016
1212
  const reason =
1017
- builderBid === null
1213
+ bidBlockResult.status === "rejected" && (bidBlockResult.reason as Error).message === NO_BID_AVAILABLE
1018
1214
  ? EngineBlockSelectionReason.BuilderNoBid
1019
- : bidResult.status === "pending"
1215
+ : bidBlockResult.status === "pending"
1020
1216
  ? EngineBlockSelectionReason.BuilderPending
1021
1217
  : EngineBlockSelectionReason.BuilderError;
1022
1218
  metrics?.blockProductionSelectionResults.inc({source: ProducedBlockSource.engine, reason});
1023
1219
  logger.info("Selected local block: no builder bid block produced", {
1024
1220
  reason,
1025
1221
  ...logCtx,
1026
- error: bidResult.status === "rejected" ? (bidResult.reason as Error).message : undefined,
1222
+ durationMs: engineResult.durationMs,
1223
+ ...getBlockValueLogInfo(engineResult.value),
1224
+ error: bidBlockResult.status === "rejected" ? (bidBlockResult.reason as Error).message : undefined,
1027
1225
  });
1028
1226
  }
1029
1227
 
1030
1228
  if (bestResult === null || bestResult.status !== "fulfilled") {
1031
1229
  const engineReason = engineResult.status === "rejected" ? engineResult.reason : engineResult.status;
1032
- const bidReason = bidResult.status === "rejected" ? bidResult.reason : bidResult.status;
1230
+ const bidReason = bidBlockResult.status === "rejected" ? bidBlockResult.reason : bidBlockResult.status;
1033
1231
  logger.error("Block production failed", {
1034
1232
  ...logCtx,
1035
1233
  engineReason: String(engineReason),
@@ -1093,7 +1291,13 @@ export function getValidatorApi(
1093
1291
 
1094
1292
  return {
1095
1293
  data: block as gloas.BeaconBlock,
1096
- meta: {version: fork, consensusBlockValue, executionPayloadValue, executionPayloadIncluded: false},
1294
+ meta: {
1295
+ version: fork,
1296
+ consensusBlockValue,
1297
+ executionPayloadValue,
1298
+ executionPayloadIncluded: false,
1299
+ builderUrl: source === ProducedBlockSource.builder ? bestBid?.url : undefined,
1300
+ },
1097
1301
  };
1098
1302
  },
1099
1303
 
@@ -1877,6 +2081,43 @@ export function getValidatorApi(
1877
2081
  }
1878
2082
  },
1879
2083
 
2084
+ async submitBuilderPreferences({builderPreferences}) {
2085
+ const failures: FailureList = [];
2086
+
2087
+ await Promise.all(
2088
+ builderPreferences.map(async (entry, i) => {
2089
+ let builder = Buffer.from(entry.url).toString("utf8");
2090
+ try {
2091
+ const url = decodeBuilderUrl(entry.url);
2092
+ builder = toPrintableUrl(url);
2093
+ const proposerIndex = chain.getHeadState().getBeaconProposer(entry.auth.message.slot);
2094
+ const expectedProposerPubkey = chain.pubkeyCache.getOrThrow(proposerIndex).toBytes();
2095
+ if (!byteArrayEquals(entry.proposerPubkey, expectedProposerPubkey)) {
2096
+ throw new ApiError(
2097
+ 400,
2098
+ `Invalid proposer pubkey for builder preferences slot=${entry.auth.message.slot}`
2099
+ );
2100
+ }
2101
+ await chain.builderApiClient.submitBuilderPreferences(url, entry.proposerPubkey, {
2102
+ preferences: {maxExecutionPayment: entry.maxExecutionPayment},
2103
+ auth: entry.auth,
2104
+ });
2105
+ } catch (e) {
2106
+ failures.push({index: i, message: (e as Error).message});
2107
+ logger.verbose(
2108
+ `Error on submitBuilderPreferences [${i}]`,
2109
+ {slot: entry.auth.message.slot, builder},
2110
+ e as Error
2111
+ );
2112
+ }
2113
+ })
2114
+ );
2115
+
2116
+ if (failures.length > 0) {
2117
+ throw new IndexedError("Error submitting builder preferences", failures);
2118
+ }
2119
+ },
2120
+
1880
2121
  async getExecutionPayloadEnvelope({slot, beaconBlockRoot}) {
1881
2122
  const fork = config.getForkName(slot);
1882
2123
 
@@ -89,7 +89,7 @@ export function selectBlockProductionSourceByBoostFactor({
89
89
  return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BuilderPreferred};
90
90
  }
91
91
 
92
- if (engineExecutionPayloadValue >= (builderExecutionPayloadValue * builderBoostFactor) / BigInt(100)) {
92
+ if (engineExecutionPayloadValue * 100n >= builderExecutionPayloadValue * builderBoostFactor) {
93
93
  return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.BlockValue};
94
94
  }
95
95
 
@@ -104,6 +104,13 @@ export class RestApiServer {
104
104
 
105
105
  // To parse our ApiError -> statusCode
106
106
  server.setErrorHandler<FastifyError | Error>((err, _req, res) => {
107
+ if (res.raw.headersSent) {
108
+ // A status code can no longer be written, e.g. if a long-lived SSE stream failed mid-flight.
109
+ // End the response instead, else the socket is left open and the client never notices.
110
+ if (!res.raw.writableEnded && !res.raw.destroyed) res.raw.end();
111
+ return;
112
+ }
113
+
107
114
  const stacktraces = opts.stacktraces ? err.stack?.split("\n") : undefined;
108
115
  if ("validation" in err && err.validation) {
109
116
  const {instancePath = "unknown", message} = err.validation?.[0] ?? {};
@@ -192,7 +192,7 @@ export class ArchiveStore {
192
192
 
193
193
  private onCheckpoint = (): void => {
194
194
  const headStateRoot = this.chain.forkChoice.getHead().stateRoot;
195
- this.chain.regen.pruneOnCheckpoint(
195
+ this.chain.regen.onCheckpoint(
196
196
  this.chain.forkChoice.getFinalizedCheckpoint().epoch,
197
197
  this.chain.forkChoice.getJustifiedCheckpoint().epoch,
198
198
  headStateRoot
@@ -58,11 +58,12 @@ export type PayloadErrorType =
58
58
  };
59
59
 
60
60
  export class PayloadError extends Error {
61
- type: PayloadErrorType;
62
-
63
- constructor(type: PayloadErrorType, message?: string) {
61
+ constructor(
62
+ readonly payloadInput: PayloadEnvelopeInput,
63
+ readonly type: PayloadErrorType,
64
+ message?: string
65
+ ) {
64
66
  super(message ?? type.code);
65
- this.type = type;
66
67
  }
67
68
  }
68
69
 
@@ -125,7 +126,7 @@ export async function importExecutionPayload(
125
126
  // 2. Get ProtoBlock for parent root lookup
126
127
  const protoBlock = this.forkChoice.getBlockHexDefaultStatus(blockRootHex);
127
128
  if (!protoBlock) {
128
- throw new PayloadError({
129
+ throw new PayloadError(payloadInput, {
129
130
  code: PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE,
130
131
  blockRootHex,
131
132
  });
@@ -140,13 +141,13 @@ export async function importExecutionPayload(
140
141
  );
141
142
 
142
143
  if (blockState == null) {
143
- throw new PayloadError({
144
+ throw new PayloadError(payloadInput, {
144
145
  code: PayloadErrorCode.MISS_BLOCK_STATE,
145
146
  blockRootHex: protoBlock.blockRoot,
146
147
  });
147
148
  }
148
149
  if (!isStatePostGloas(blockState)) {
149
- throw new PayloadError({
150
+ throw new PayloadError(payloadInput, {
150
151
  code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
151
152
  message: `Expected gloas+ state for payload import, got fork=${blockState.forkName}`,
152
153
  });
@@ -161,6 +162,7 @@ export async function importExecutionPayload(
161
162
  });
162
163
  } catch (e) {
163
164
  throw new PayloadError(
165
+ payloadInput,
164
166
  {
165
167
  code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
166
168
  message: (e as Error).message,
@@ -184,7 +186,6 @@ export async function importExecutionPayload(
184
186
  : verifyExecutionPayloadEnvelopeSignature(
185
187
  this.config,
186
188
  blockState,
187
- this.pubkeyCache,
188
189
  signedEnvelope,
189
190
  payloadInput.proposerIndex,
190
191
  this.bls
@@ -193,7 +194,7 @@ export async function importExecutionPayload(
193
194
 
194
195
  // 4b. Check signature verification result
195
196
  if (!signatureValid) {
196
- throw new PayloadError({code: PayloadErrorCode.INVALID_SIGNATURE});
197
+ throw new PayloadError(payloadInput, {code: PayloadErrorCode.INVALID_SIGNATURE});
197
198
  }
198
199
 
199
200
  // 4c. Handle EL response
@@ -202,7 +203,7 @@ export async function importExecutionPayload(
202
203
  break;
203
204
 
204
205
  case ExecutionPayloadStatus.INVALID:
205
- throw new PayloadError({
206
+ throw new PayloadError(payloadInput, {
206
207
  code: PayloadErrorCode.EXECUTION_ENGINE_INVALID,
207
208
  execStatus: execResult.status,
208
209
  errorMessage: execResult.validationError ?? "",
@@ -215,7 +216,7 @@ export async function importExecutionPayload(
215
216
  case ExecutionPayloadStatus.INVALID_BLOCK_HASH:
216
217
  case ExecutionPayloadStatus.ELERROR:
217
218
  case ExecutionPayloadStatus.UNAVAILABLE:
218
- throw new PayloadError({
219
+ throw new PayloadError(payloadInput, {
219
220
  code: PayloadErrorCode.EXECUTION_ENGINE_ERROR,
220
221
  execStatus: execResult.status,
221
222
  errorMessage: execResult.validationError ?? "",
@@ -8,7 +8,7 @@ import {BlockError, BlockErrorCode, isBlockErrorAborted} from "../errors/index.j
8
8
  import {BlockProcessOpts} from "../options.js";
9
9
  import {IBlockInput} from "./blockInput/types.js";
10
10
  import {importBlock} from "./importBlock.js";
11
- import {importExecutionPayload} from "./importExecutionPayload.js";
11
+ import {PayloadError, importExecutionPayload} from "./importExecutionPayload.js";
12
12
  import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
13
13
  import {FullyVerifiedBlock, ImportBlockOpts} from "./types.js";
14
14
  import {assertLinearChainSegment} from "./utils/chainSegment.js";
@@ -143,17 +143,17 @@ export async function processBlocks(
143
143
  await importBlock.call(this, fullyVerifiedBlock, opts);
144
144
  }
145
145
 
146
- const payloadInput = payloadEnvelopes?.get(slot);
147
- if (payloadInput?.hasPayloadEnvelope()) {
146
+ // PayloadEnvelopeInput is shared and may receive an envelope after the DA snapshot was taken.
147
+ const payloadDA = payloadDAStatuses.get(slot);
148
+ if (payloadDA !== undefined) {
149
+ const payloadInput = payloadEnvelopes?.get(slot);
150
+ if (payloadInput === undefined) {
151
+ throw new Error(`Missing payload input for slot ${slot} after DA verification`);
152
+ }
148
153
  if (!payloadInput.isComplete()) {
149
154
  // we validated DA before reaching this
150
155
  throw new Error(`Payload envelope for slot ${slot} not complete after DA verification`);
151
156
  }
152
- // we already awaited DA in verifyBlocksInEpoch for this segment
153
- const payloadDA = payloadDAStatuses.get(slot);
154
- if (payloadDA === undefined) {
155
- throw new Error(`Missing payload DA status for slot ${slot}`);
156
- }
157
157
  await importExecutionPayload.call(this, payloadInput, payloadDA, {validSignature: false});
158
158
  }
159
159
 
@@ -164,13 +164,21 @@ export async function processBlocks(
164
164
  return; // Ignore
165
165
  }
166
166
 
167
- // above functions should only throw BlockError
168
- const err = getBlockError(e, blocks[0].getBlock());
167
+ // above functions should only throw BlockError, or PayloadError from the gloas payload import
168
+ const err = getBlockOrPayloadError(e, blocks[0].getBlock());
169
169
 
170
170
  // TODO: De-duplicate with logic above
171
171
  // ChainEvent.errorBlock
172
- if (!(err instanceof BlockError)) {
173
- this.logger.debug("Non BlockError received", {}, err);
172
+ if (!(err instanceof BlockError) && !(err instanceof PayloadError)) {
173
+ this.logger.debug("Neither BlockError nor PayloadError received", {}, err);
174
+ } else if (err instanceof PayloadError) {
175
+ if (!opts.disableOnBlockError) {
176
+ this.logger.debug(
177
+ "Payload error",
178
+ {slot: err.payloadInput.slot, blockRoot: err.payloadInput.blockRootHex},
179
+ err
180
+ );
181
+ }
174
182
  } else if (!opts.disableOnBlockError) {
175
183
  this.logger.debug("Block error", {slot: err.signedBlock.message.slot}, err);
176
184
 
@@ -201,11 +209,15 @@ export async function processBlocks(
201
209
  }
202
210
  }
203
211
 
204
- function getBlockError(e: unknown, block: SignedBeaconBlock): BlockError {
212
+ function getBlockOrPayloadError(e: unknown, block: SignedBeaconBlock): BlockError | PayloadError {
205
213
  if (e instanceof BlockError) {
206
214
  return e;
207
215
  }
208
216
 
217
+ if (e instanceof PayloadError) {
218
+ return e;
219
+ }
220
+
209
221
  if (e instanceof Error) {
210
222
  const blockError = new BlockError(block, {code: BlockErrorCode.BEACON_CHAIN_ERROR, error: e});
211
223
  blockError.stack = e.stack;