@lodestar/beacon-node 1.47.0-dev.d2f4b96574 → 1.47.0-dev.d79d81f994

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 (377) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +47 -18
  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 +25 -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 +1 -1
  11. package/lib/api/impl/events/index.d.ts.map +1 -1
  12. package/lib/api/impl/events/index.js +12 -3
  13. package/lib/api/impl/events/index.js.map +1 -1
  14. package/lib/api/impl/lodestar/index.d.ts.map +1 -1
  15. package/lib/api/impl/lodestar/index.js +12 -13
  16. package/lib/api/impl/lodestar/index.js.map +1 -1
  17. package/lib/api/impl/validator/index.d.ts.map +1 -1
  18. package/lib/api/impl/validator/index.js +238 -65
  19. package/lib/api/impl/validator/index.js.map +1 -1
  20. package/lib/api/impl/validator/utils.d.ts +5 -0
  21. package/lib/api/impl/validator/utils.d.ts.map +1 -1
  22. package/lib/api/impl/validator/utils.js +18 -12
  23. package/lib/api/impl/validator/utils.js.map +1 -1
  24. package/lib/api/rest/base.d.ts.map +1 -1
  25. package/lib/api/rest/base.js +7 -0
  26. package/lib/api/rest/base.js.map +1 -1
  27. package/lib/chain/archiveStore/archiveStore.js +1 -1
  28. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  29. package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
  30. package/lib/chain/archiveStore/historicalState/metrics.js +21 -0
  31. package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
  32. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  33. package/lib/chain/blocks/importBlock.js +2 -7
  34. package/lib/chain/blocks/importBlock.js.map +1 -1
  35. package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
  36. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  37. package/lib/chain/blocks/importExecutionPayload.js +11 -9
  38. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  39. package/lib/chain/blocks/index.d.ts.map +1 -1
  40. package/lib/chain/blocks/index.js +15 -7
  41. package/lib/chain/blocks/index.js.map +1 -1
  42. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
  43. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  44. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
  45. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  46. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
  47. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  48. package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
  49. package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -1
  50. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  51. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
  52. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  53. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  54. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  55. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  56. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  57. package/lib/chain/bls/index.d.ts +1 -1
  58. package/lib/chain/bls/index.d.ts.map +1 -1
  59. package/lib/chain/bls/interface.d.ts +5 -5
  60. package/lib/chain/bls/interface.d.ts.map +1 -1
  61. package/lib/chain/bls/multithread/index.d.ts +5 -11
  62. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  63. package/lib/chain/bls/multithread/index.js +116 -101
  64. package/lib/chain/bls/multithread/index.js.map +1 -1
  65. package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
  66. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  67. package/lib/chain/bls/multithread/jobItem.js +10 -65
  68. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  69. package/lib/chain/bls/multithread/types.d.ts +29 -8
  70. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  71. package/lib/chain/bls/multithread/types.js +12 -0
  72. package/lib/chain/bls/multithread/types.js.map +1 -1
  73. package/lib/chain/bls/multithread/utils.d.ts +4 -0
  74. package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
  75. package/lib/chain/bls/multithread/utils.js +10 -0
  76. package/lib/chain/bls/multithread/utils.js.map +1 -1
  77. package/lib/chain/bls/multithread/worker.js +49 -23
  78. package/lib/chain/bls/multithread/worker.js.map +1 -1
  79. package/lib/chain/bls/singleThread.d.ts +4 -10
  80. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  81. package/lib/chain/bls/singleThread.js +8 -45
  82. package/lib/chain/bls/singleThread.js.map +1 -1
  83. package/lib/chain/bls/utils.d.ts +4 -4
  84. package/lib/chain/bls/utils.d.ts.map +1 -1
  85. package/lib/chain/bls/utils.js +18 -19
  86. package/lib/chain/bls/utils.js.map +1 -1
  87. package/lib/chain/builderCircuitBreaker.d.ts +6 -5
  88. package/lib/chain/builderCircuitBreaker.d.ts.map +1 -1
  89. package/lib/chain/builderCircuitBreaker.js +28 -15
  90. package/lib/chain/builderCircuitBreaker.js.map +1 -1
  91. package/lib/chain/chain.d.ts +10 -5
  92. package/lib/chain/chain.d.ts.map +1 -1
  93. package/lib/chain/chain.js +24 -9
  94. package/lib/chain/chain.js.map +1 -1
  95. package/lib/chain/errors/blockError.d.ts +2 -0
  96. package/lib/chain/errors/blockError.d.ts.map +1 -1
  97. package/lib/chain/errors/blockError.js +6 -1
  98. package/lib/chain/errors/blockError.js.map +1 -1
  99. package/lib/chain/errors/proposerPreferences.d.ts +6 -0
  100. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
  101. package/lib/chain/errors/proposerPreferences.js +1 -0
  102. package/lib/chain/errors/proposerPreferences.js.map +1 -1
  103. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  104. package/lib/chain/forkChoice/index.js +4 -0
  105. package/lib/chain/forkChoice/index.js.map +1 -1
  106. package/lib/chain/interface.d.ts +8 -4
  107. package/lib/chain/interface.d.ts.map +1 -1
  108. package/lib/chain/interface.js.map +1 -1
  109. package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
  110. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  111. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  112. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  113. package/lib/chain/opPools/attestationPool.js +1 -1
  114. package/lib/chain/opPools/attestationPool.js.map +1 -1
  115. package/lib/chain/opPools/deferredVoluntaryExitPool.d.ts +16 -0
  116. package/lib/chain/opPools/deferredVoluntaryExitPool.d.ts.map +1 -0
  117. package/lib/chain/opPools/deferredVoluntaryExitPool.js +57 -0
  118. package/lib/chain/opPools/deferredVoluntaryExitPool.js.map +1 -0
  119. package/lib/chain/opPools/executionPayloadBidPool.d.ts +7 -2
  120. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
  121. package/lib/chain/opPools/executionPayloadBidPool.js +4 -4
  122. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
  123. package/lib/chain/opPools/index.d.ts +2 -1
  124. package/lib/chain/opPools/index.d.ts.map +1 -1
  125. package/lib/chain/opPools/index.js +1 -0
  126. package/lib/chain/opPools/index.js.map +1 -1
  127. package/lib/chain/opPools/payloadAttestationPool.js +3 -3
  128. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  129. package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
  130. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  131. package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
  132. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  133. package/lib/chain/opPools/utils.d.ts +1 -1
  134. package/lib/chain/opPools/utils.d.ts.map +1 -1
  135. package/lib/chain/opPools/utils.js +1 -1
  136. package/lib/chain/opPools/utils.js.map +1 -1
  137. package/lib/chain/options.d.ts +1 -1
  138. package/lib/chain/options.d.ts.map +1 -1
  139. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  140. package/lib/chain/prepareNextSlot.js +25 -7
  141. package/lib/chain/prepareNextSlot.js.map +1 -1
  142. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  143. package/lib/chain/produceBlock/computeNewStateRoot.js +3 -25
  144. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  145. package/lib/chain/produceBlock/produceBlockBody.d.ts +2 -0
  146. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  147. package/lib/chain/produceBlock/produceBlockBody.js +7 -2
  148. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  149. package/lib/chain/regen/interface.d.ts +5 -2
  150. package/lib/chain/regen/interface.d.ts.map +1 -1
  151. package/lib/chain/regen/interface.js +3 -0
  152. package/lib/chain/regen/interface.js.map +1 -1
  153. package/lib/chain/regen/queued.d.ts +2 -2
  154. package/lib/chain/regen/queued.d.ts.map +1 -1
  155. package/lib/chain/regen/queued.js +5 -5
  156. package/lib/chain/regen/queued.js.map +1 -1
  157. package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
  158. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  159. package/lib/chain/seenCache/seenAttesters.js +25 -4
  160. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  161. package/lib/chain/seenCache/seenBlockProposers.d.ts +5 -1
  162. package/lib/chain/seenCache/seenBlockProposers.d.ts.map +1 -1
  163. package/lib/chain/seenCache/seenBlockProposers.js +10 -3
  164. package/lib/chain/seenCache/seenBlockProposers.js.map +1 -1
  165. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +28 -1
  166. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  167. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
  168. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  169. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +5 -1
  170. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  171. package/lib/chain/stateCache/fifoBlockStateCache.js +6 -0
  172. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  173. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +47 -5
  174. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  175. package/lib/chain/stateCache/persistentCheckpointsCache.js +117 -7
  176. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  177. package/lib/chain/stateCache/types.d.ts +3 -3
  178. package/lib/chain/stateCache/types.d.ts.map +1 -1
  179. package/lib/chain/validation/attestation.d.ts.map +1 -1
  180. package/lib/chain/validation/attestation.js +1 -4
  181. package/lib/chain/validation/attestation.js.map +1 -1
  182. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  183. package/lib/chain/validation/attesterSlashing.js +1 -1
  184. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  185. package/lib/chain/validation/block.d.ts.map +1 -1
  186. package/lib/chain/validation/block.js +21 -7
  187. package/lib/chain/validation/block.js.map +1 -1
  188. package/lib/chain/validation/executionPayloadBid.d.ts +13 -3
  189. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  190. package/lib/chain/validation/executionPayloadBid.js +147 -12
  191. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  192. package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
  193. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  194. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  195. package/lib/chain/validation/payloadAttestationMessage.js +5 -14
  196. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  197. package/lib/chain/validation/proposerPreferences.d.ts +1 -1
  198. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
  199. package/lib/chain/validation/proposerPreferences.js +13 -4
  200. package/lib/chain/validation/proposerPreferences.js.map +1 -1
  201. package/lib/chain/validation/proposerSlashing.js +1 -1
  202. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  203. package/lib/chain/validation/voluntaryExit.d.ts +9 -1
  204. package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
  205. package/lib/chain/validation/voluntaryExit.js +46 -1
  206. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  207. package/lib/execution/builder/apiClient.d.ts +64 -0
  208. package/lib/execution/builder/apiClient.d.ts.map +1 -0
  209. package/lib/execution/builder/apiClient.js +184 -0
  210. package/lib/execution/builder/apiClient.js.map +1 -0
  211. package/lib/execution/builder/http.d.ts +10 -7
  212. package/lib/execution/builder/http.d.ts.map +1 -1
  213. package/lib/execution/builder/http.js +11 -8
  214. package/lib/execution/builder/http.js.map +1 -1
  215. package/lib/execution/builder/validateBid.d.ts +22 -0
  216. package/lib/execution/builder/validateBid.d.ts.map +1 -0
  217. package/lib/execution/builder/validateBid.js +111 -0
  218. package/lib/execution/builder/validateBid.js.map +1 -0
  219. package/lib/metrics/metrics/beacon.d.ts +3 -3
  220. package/lib/metrics/metrics/beacon.d.ts.map +1 -1
  221. package/lib/metrics/metrics/beacon.js +9 -9
  222. package/lib/metrics/metrics/beacon.js.map +1 -1
  223. package/lib/metrics/metrics/lodestar.d.ts +88 -23
  224. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  225. package/lib/metrics/metrics/lodestar.js +164 -52
  226. package/lib/metrics/metrics/lodestar.js.map +1 -1
  227. package/lib/network/gossip/topic.d.ts +13 -0
  228. package/lib/network/gossip/topic.d.ts.map +1 -1
  229. package/lib/network/gossip/topic.js +37 -0
  230. package/lib/network/gossip/topic.js.map +1 -1
  231. package/lib/network/libp2p/index.d.ts.map +1 -1
  232. package/lib/network/libp2p/index.js +10 -2
  233. package/lib/network/libp2p/index.js.map +1 -1
  234. package/lib/network/network.d.ts.map +1 -1
  235. package/lib/network/network.js +23 -43
  236. package/lib/network/network.js.map +1 -1
  237. package/lib/network/processor/constants.d.ts +7 -0
  238. package/lib/network/processor/constants.d.ts.map +1 -0
  239. package/lib/network/processor/constants.js +7 -0
  240. package/lib/network/processor/constants.js.map +1 -0
  241. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  242. package/lib/network/processor/gossipHandlers.js +38 -7
  243. package/lib/network/processor/gossipHandlers.js.map +1 -1
  244. package/lib/network/processor/gossipQueues/indexed.d.ts.map +1 -1
  245. package/lib/network/processor/gossipQueues/indexed.js +0 -1
  246. package/lib/network/processor/gossipQueues/indexed.js.map +1 -1
  247. package/lib/network/processor/index.d.ts +3 -0
  248. package/lib/network/processor/index.d.ts.map +1 -1
  249. package/lib/network/processor/index.js +41 -17
  250. package/lib/network/processor/index.js.map +1 -1
  251. package/lib/network/reqresp/score.d.ts.map +1 -1
  252. package/lib/network/reqresp/score.js +5 -11
  253. package/lib/network/reqresp/score.js.map +1 -1
  254. package/lib/network/util.d.ts +0 -1
  255. package/lib/network/util.d.ts.map +1 -1
  256. package/lib/network/util.js +0 -4
  257. package/lib/network/util.js.map +1 -1
  258. package/lib/node/deferredVoluntaryExitPublisher.d.ts +15 -0
  259. package/lib/node/deferredVoluntaryExitPublisher.d.ts.map +1 -0
  260. package/lib/node/deferredVoluntaryExitPublisher.js +38 -0
  261. package/lib/node/deferredVoluntaryExitPublisher.js.map +1 -0
  262. package/lib/node/nodejs.d.ts +2 -1
  263. package/lib/node/nodejs.d.ts.map +1 -1
  264. package/lib/node/nodejs.js +7 -0
  265. package/lib/node/nodejs.js.map +1 -1
  266. package/lib/sync/range/batch.d.ts +23 -5
  267. package/lib/sync/range/batch.d.ts.map +1 -1
  268. package/lib/sync/range/batch.js +61 -22
  269. package/lib/sync/range/batch.js.map +1 -1
  270. package/lib/sync/range/chain.d.ts +2 -1
  271. package/lib/sync/range/chain.d.ts.map +1 -1
  272. package/lib/sync/range/chain.js +23 -10
  273. package/lib/sync/range/chain.js.map +1 -1
  274. package/lib/sync/types.d.ts +32 -0
  275. package/lib/sync/types.d.ts.map +1 -1
  276. package/lib/sync/types.js +33 -0
  277. package/lib/sync/types.js.map +1 -1
  278. package/lib/sync/unknownBlock.d.ts +15 -2
  279. package/lib/sync/unknownBlock.d.ts.map +1 -1
  280. package/lib/sync/unknownBlock.js +234 -63
  281. package/lib/sync/unknownBlock.js.map +1 -1
  282. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  283. package/lib/sync/utils/downloadByRange.js +16 -11
  284. package/lib/sync/utils/downloadByRange.js.map +1 -1
  285. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  286. package/lib/sync/utils/downloadByRoot.js +3 -1
  287. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  288. package/package.json +35 -35
  289. package/src/api/impl/beacon/blocks/index.ts +55 -21
  290. package/src/api/impl/beacon/pool/index.ts +27 -2
  291. package/src/api/impl/beacon/state/utils.ts +2 -1
  292. package/src/api/impl/events/index.ts +12 -4
  293. package/src/api/impl/lodestar/index.ts +12 -13
  294. package/src/api/impl/validator/index.ts +300 -69
  295. package/src/api/impl/validator/utils.ts +30 -15
  296. package/src/api/rest/base.ts +7 -0
  297. package/src/chain/archiveStore/archiveStore.ts +1 -1
  298. package/src/chain/archiveStore/historicalState/metrics.ts +22 -0
  299. package/src/chain/blocks/importBlock.ts +1 -6
  300. package/src/chain/blocks/importExecutionPayload.ts +12 -11
  301. package/src/chain/blocks/index.ts +19 -7
  302. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
  303. package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
  304. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
  305. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
  306. package/src/chain/bls/index.ts +1 -1
  307. package/src/chain/bls/interface.ts +7 -3
  308. package/src/chain/bls/multithread/index.ts +148 -120
  309. package/src/chain/bls/multithread/jobItem.ts +12 -82
  310. package/src/chain/bls/multithread/types.ts +33 -8
  311. package/src/chain/bls/multithread/utils.ts +11 -0
  312. package/src/chain/bls/multithread/worker.ts +85 -27
  313. package/src/chain/bls/singleThread.ts +11 -55
  314. package/src/chain/bls/utils.ts +23 -24
  315. package/src/chain/builderCircuitBreaker.ts +31 -17
  316. package/src/chain/chain.ts +27 -7
  317. package/src/chain/errors/blockError.ts +9 -3
  318. package/src/chain/errors/proposerPreferences.ts +7 -0
  319. package/src/chain/forkChoice/index.ts +4 -0
  320. package/src/chain/interface.ts +8 -3
  321. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  322. package/src/chain/opPools/attestationPool.ts +1 -1
  323. package/src/chain/opPools/deferredVoluntaryExitPool.ts +65 -0
  324. package/src/chain/opPools/executionPayloadBidPool.ts +13 -7
  325. package/src/chain/opPools/index.ts +2 -1
  326. package/src/chain/opPools/payloadAttestationPool.ts +3 -3
  327. package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
  328. package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
  329. package/src/chain/opPools/utils.ts +1 -1
  330. package/src/chain/options.ts +1 -1
  331. package/src/chain/prepareNextSlot.ts +25 -7
  332. package/src/chain/produceBlock/computeNewStateRoot.ts +3 -38
  333. package/src/chain/produceBlock/produceBlockBody.ts +14 -1
  334. package/src/chain/regen/interface.ts +5 -2
  335. package/src/chain/regen/queued.ts +5 -5
  336. package/src/chain/seenCache/seenAttesters.ts +31 -5
  337. package/src/chain/seenCache/seenBlockProposers.ts +13 -3
  338. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
  339. package/src/chain/stateCache/fifoBlockStateCache.ts +8 -1
  340. package/src/chain/stateCache/persistentCheckpointsCache.ts +133 -8
  341. package/src/chain/stateCache/types.ts +3 -3
  342. package/src/chain/validation/attestation.ts +1 -7
  343. package/src/chain/validation/attesterSlashing.ts +1 -8
  344. package/src/chain/validation/block.ts +21 -7
  345. package/src/chain/validation/executionPayloadBid.ts +168 -14
  346. package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
  347. package/src/chain/validation/payloadAttestationMessage.ts +6 -17
  348. package/src/chain/validation/proposerPreferences.ts +15 -5
  349. package/src/chain/validation/proposerSlashing.ts +1 -1
  350. package/src/chain/validation/voluntaryExit.ts +59 -2
  351. package/src/execution/builder/apiClient.ts +244 -0
  352. package/src/execution/builder/http.ts +11 -11
  353. package/src/execution/builder/validateBid.ts +166 -0
  354. package/src/metrics/metrics/beacon.ts +9 -9
  355. package/src/metrics/metrics/lodestar.ts +178 -58
  356. package/src/network/gossip/topic.ts +38 -0
  357. package/src/network/libp2p/index.ts +11 -2
  358. package/src/network/network.ts +29 -54
  359. package/src/network/processor/constants.ts +6 -0
  360. package/src/network/processor/gossipHandlers.ts +41 -5
  361. package/src/network/processor/gossipQueues/indexed.ts +0 -1
  362. package/src/network/processor/index.ts +53 -21
  363. package/src/network/reqresp/score.ts +5 -11
  364. package/src/network/util.ts +0 -5
  365. package/src/node/deferredVoluntaryExitPublisher.ts +54 -0
  366. package/src/node/nodejs.ts +10 -1
  367. package/src/sync/range/batch.ts +83 -28
  368. package/src/sync/range/chain.ts +26 -11
  369. package/src/sync/types.ts +36 -1
  370. package/src/sync/unknownBlock.ts +273 -70
  371. package/src/sync/utils/downloadByRange.ts +21 -12
  372. package/src/sync/utils/downloadByRoot.ts +3 -1
  373. package/lib/chain/bls/maybeBatch.d.ts +0 -12
  374. package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
  375. package/lib/chain/bls/maybeBatch.js +0 -35
  376. package/lib/chain/bls/maybeBatch.js.map +0 -1
  377. 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";
@@ -92,7 +99,12 @@ import {getStateResponseWithRegen} from "../beacon/state/utils.js";
92
99
  import {ApiError, FailureList, IndexedError, NodeIsSyncing, OnlySupportedByDVT} from "../errors.js";
93
100
  import {ApiModules} from "../types.js";
94
101
  import {notWhileSyncing} from "../utils.js";
95
- import {computeSubnetForCommitteesAtSlot, getPubkeysForIndices, selectBlockProductionSource} from "./utils.js";
102
+ import {
103
+ computeSubnetForCommitteesAtSlot,
104
+ getPubkeysForIndices,
105
+ selectBlockProductionSource,
106
+ selectBlockProductionSourceByBoostFactor,
107
+ } from "./utils.js";
96
108
 
97
109
  /**
98
110
  * Cutoff time to wait from start of the slot for execution and builder block production apis to resolve.
@@ -107,6 +119,55 @@ import {computeSubnetForCommitteesAtSlot, getPubkeysForIndices, selectBlockProdu
107
119
  const BLOCK_PRODUCTION_RACE_CUTOFF_MS = 2_000;
108
120
  /** Overall timeout for execution and block production apis */
109
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
+ }
110
171
 
111
172
  type ProduceBlockContentsRes = {executionPayloadValue: Wei; consensusBlockValue: Wei} & {
112
173
  data: BlockContents;
@@ -577,8 +638,7 @@ export function getValidatorApi(
577
638
  builderSelection,
578
639
  isBuilderEnabled,
579
640
  strictFeeRecipientCheck,
580
- // winston logger doesn't like bigint
581
- builderBoostFactor: `${builderBoostFactor}`,
641
+ builderBoostFactor,
582
642
  };
583
643
 
584
644
  logger.verbose("Assembling block with produceEngineOrBuilderBlock", loggerContext);
@@ -851,9 +911,9 @@ export function getValidatorApi(
851
911
  randaoReveal,
852
912
  graffiti,
853
913
  feeRecipient,
914
+ strictFeeRecipientCheck,
854
915
  includePayload,
855
- builderSelection,
856
- builderBoostFactor,
916
+ builderConfig,
857
917
  }) {
858
918
  const fork = config.getForkName(slot);
859
919
 
@@ -861,12 +921,7 @@ export function getValidatorApi(
861
921
  throw new ApiError(400, `produceBlockV4 not supported for pre-gloas fork=${fork}`);
862
922
  }
863
923
 
864
- builderSelection = builderSelection ?? routes.validator.BuilderSelection.MaxProfit;
865
- if (builderSelection === routes.validator.BuilderSelection.BuilderOnly) {
866
- logger.warn("Builder selection builderonly is no longer supported, treating as builderalways");
867
- builderSelection = routes.validator.BuilderSelection.BuilderAlways;
868
- }
869
- builderBoostFactor = builderBoostFactor ?? BigInt(100);
924
+ const builderBoostFactor = builderConfig.builderBoostFactor;
870
925
  if (builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) {
871
926
  throw new ApiError(400, `Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR`);
872
927
  }
@@ -893,35 +948,117 @@ export function getValidatorApi(
893
948
  })
894
949
  );
895
950
 
896
- // TODO GLOAS: add external builder api support when it is implemented
897
951
  const isBuildingOnFull = chain.forkChoice.shouldBuildOnFull(parentBlock, slot);
898
952
  const bidParentBlockHash = isBuildingOnFull ? parentBlock.executionPayloadBlockHash : parentBlock.parentBlockHash;
899
- // Bids are only skipped entirely with executiononly or while the circuit breaker is active,
900
- // other engine-preferring selections still build a block with the best bid as fallback in
901
- // case local production fails
902
- const circuitBreakerActive = chain.builderCircuitBreaker.isActive(slot);
903
- const builderBid =
904
- builderSelection === routes.validator.BuilderSelection.ExecutionOnly || circuitBreakerActive
905
- ? null
906
- : chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
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
+ }
957
+ const circuitBreakerActive = chain.builderCircuitBreaker.isActive(slot, parentBlock);
958
+
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
+ }
907
977
 
908
- const logCtx = {
909
- slot,
910
- parentSlot,
911
- parentBlockRoot: parentBlockRootHex,
912
- parentBlockHash: parentBlock.executionPayloadBlockHash,
913
- fork,
914
- builderSelection,
915
- builderBoostFactor,
916
- circuitBreakerActive,
917
- ...(builderBid !== null
918
- ? {
919
- bidValue: builderBid.message.value,
920
- builderIndex: builderBid.message.builderIndex,
921
- bidBlockHash: toRootHex(builderBid.message.blockHash),
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;
922
1000
  }
923
- : {}),
924
- };
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
+
1011
+ const candidates = (
1012
+ await Promise.all(
1013
+ builderApiBids.map(async ({url, entry, signedBid, receivedMs}): Promise<BidCandidate | null> => {
1014
+ try {
1015
+ await validateBuilderApiExecutionPayloadBid(chain, signedBid, {
1016
+ slot,
1017
+ parentBlock,
1018
+ parentBlockHash: bidParentBlockHash,
1019
+ parentBlockRoot: parentBlockRootHex,
1020
+ entry,
1021
+ });
1022
+ return {
1023
+ signedBid,
1024
+ totalGwei: getBuilderBidTotalGwei(signedBid.message, entry.maxExecutionPayment),
1025
+ boostFactor: entry.builderBoostFactor,
1026
+ url,
1027
+ receivedMs,
1028
+ };
1029
+ } catch (e) {
1030
+ metrics?.builderApi.bidsDiscarded.inc();
1031
+ logger.warn("Ignoring invalid builder API bid", {slot, builder: toPrintableUrl(url)}, e as Error);
1032
+ return null;
1033
+ }
1034
+ })
1035
+ )
1036
+ ).filter((candidate): candidate is BidCandidate => candidate !== null);
1037
+
1038
+ if (p2pBid !== null) {
1039
+ candidates.push({
1040
+ signedBid: p2pBid.signedBid,
1041
+ totalGwei: BigInt(p2pBid.signedBid.message.value),
1042
+ boostFactor: builderConfig.builderBoostFactor,
1043
+ receivedMs: p2pBid.receivedMs,
1044
+ });
1045
+ }
1046
+
1047
+ const best = selectBestBid(candidates);
1048
+ if (candidates.length > 0) {
1049
+ logger.debug("Ranked builder bid candidates", {
1050
+ slot,
1051
+ candidates: candidates
1052
+ .map(
1053
+ (candidate) =>
1054
+ `${candidate.url ?? "p2p"}:total=${prettyGweiToEth(candidate.totalGwei)}:boost=${candidate.boostFactor}:received=${candidate.receivedMs}ms`
1055
+ )
1056
+ .join(","),
1057
+ bidSource: best?.url ?? "p2p",
1058
+ });
1059
+ }
1060
+ return best;
1061
+ })();
925
1062
 
926
1063
  const commonBlockBodyPromise = chain.produceCommonBlockBody({
927
1064
  slot,
@@ -936,13 +1073,11 @@ export function getValidatorApi(
936
1073
  randaoReveal,
937
1074
  graffiti: graffitiBytes,
938
1075
  feeRecipient,
1076
+ strictFeeRecipientCheck,
939
1077
  commonBlockBodyPromise,
940
1078
  };
941
1079
 
942
1080
  metrics?.blockProductionRequests.inc({source: ProducedBlockSource.engine});
943
- if (builderBid !== null) {
944
- metrics?.blockProductionRequests.inc({source: ProducedBlockSource.builder});
945
- }
946
1081
 
947
1082
  const timed = <T>(source: ProducedBlockSource, fn: () => Promise<T>): Promise<T> => {
948
1083
  const t = metrics?.blockProductionTime.startTimer();
@@ -959,23 +1094,25 @@ export function getValidatorApi(
959
1094
  const enginePromise: ReturnType<typeof chain.produceBlock> = timed(ProducedBlockSource.engine, () =>
960
1095
  chain.produceBlock(baseAttrs)
961
1096
  ).then((engineBlock) => {
962
- // No need to wait for the bid block if the engine block will always be selected due to
963
- // suspected builder censorship, a builder boost factor of 0 or executionalways selection
964
- if (
965
- engineBlock.shouldOverrideBuilder ||
966
- builderBoostFactor === BigInt(0) ||
967
- builderSelection === routes.validator.BuilderSelection.ExecutionAlways
968
- ) {
1097
+ // No need to wait for the bid block if the engine block will always be selected, either
1098
+ // due to suspected builder censorship, or because no builders are configured and the
1099
+ // boost factor of 0 always prefers the local block over p2p bids
1100
+ if (engineBlock.shouldOverrideBuilder || (builderConfig.builders.length === 0 && builderBoostFactor === 0n)) {
969
1101
  controller.abort();
970
1102
  }
971
1103
  return engineBlock;
972
1104
  });
973
- const bidPromise: ReturnType<typeof chain.produceBlock> =
974
- builderBid !== null
975
- ? timed(ProducedBlockSource.builder, () => chain.produceBlock({...baseAttrs, builderBid}))
976
- : Promise.reject(new Error("No builder bid available"));
1105
+ const bidBlockPromise: ReturnType<typeof chain.produceBlock> = bestBidPromise.then((candidate) => {
1106
+ if (candidate === null) {
1107
+ throw new Error(NO_BID_AVAILABLE);
1108
+ }
1109
+ metrics?.blockProductionRequests.inc({source: ProducedBlockSource.builder});
1110
+ return timed(ProducedBlockSource.builder, () =>
1111
+ chain.produceBlock({...baseAttrs, builderBid: candidate.signedBid})
1112
+ );
1113
+ });
977
1114
 
978
- const [engineResult, bidResult] = await resolveOrRacePromises([enginePromise, bidPromise], {
1115
+ const [engineResult, bidBlockResult] = await resolveOrRacePromises([enginePromise, bidBlockPromise], {
979
1116
  resolveTimeoutMs: cutoffMs,
980
1117
  raceTimeoutMs: BLOCK_PRODUCTION_RACE_TIMEOUT_MS,
981
1118
  signal: controller.signal,
@@ -984,30 +1121,74 @@ export function getValidatorApi(
984
1121
  let bestResult: typeof engineResult | null = null;
985
1122
  let source: ProducedBlockSource = ProducedBlockSource.engine;
986
1123
 
1124
+ // Resolved instantly whenever the bid branch produced a block
1125
+ const bestBid = bidBlockResult.status === "fulfilled" ? await bestBidPromise : null;
1126
+
1127
+ const logCtx = {
1128
+ slot,
1129
+ parentSlot,
1130
+ parentBlockRoot: parentBlockRootHex,
1131
+ parentBlockHash: parentBlock.executionPayloadBlockHash,
1132
+ fork,
1133
+ builderBoostFactor,
1134
+ strictFeeRecipientCheck,
1135
+ circuitBreakerActive,
1136
+ builderEntries: builderConfig.builders.length,
1137
+ ...(bestBid !== null
1138
+ ? {
1139
+ bidSource: bestBid.url !== undefined ? toPrintableUrl(bestBid.url) : "p2p",
1140
+ bidValue: prettyGweiToEth(bestBid.signedBid.message.value),
1141
+ bidExecutionPayment: prettyGweiToEth(bestBid.signedBid.message.executionPayment),
1142
+ // The full bid total and the counted total used during bid selection
1143
+ bidTotal: prettyGweiToEth(
1144
+ BigInt(bestBid.signedBid.message.value) + bestBid.signedBid.message.executionPayment
1145
+ ),
1146
+ bidCountedTotal: prettyGweiToEth(bestBid.totalGwei),
1147
+ bidBoostFactor: bestBid.boostFactor,
1148
+ builderIndex: bestBid.signedBid.message.builderIndex,
1149
+ bidBlockHash: toRootHex(bestBid.signedBid.message.blockHash),
1150
+ bidReceivedMs: bestBid.receivedMs,
1151
+ }
1152
+ : {}),
1153
+ };
1154
+
987
1155
  // handle shouldOverrideBuilder separately
988
- if (engineResult.status === "fulfilled" && engineResult.value.shouldOverrideBuilder && builderBid !== null) {
1156
+ if (
1157
+ engineResult.status === "fulfilled" &&
1158
+ engineResult.value.shouldOverrideBuilder &&
1159
+ (builderBidExpected || bidBlockResult.status === "fulfilled")
1160
+ ) {
989
1161
  source = ProducedBlockSource.engine;
990
1162
  bestResult = engineResult;
991
1163
  metrics?.blockProductionSelectionResults.inc({
992
1164
  source: ProducedBlockSource.engine,
993
1165
  reason: EngineBlockSelectionReason.BuilderCensorship,
994
1166
  });
995
- logger.warn("Selected local block: censorship suspected in builder bid", logCtx);
996
- } else if (engineResult.status === "fulfilled" && bidResult.status === "fulfilled") {
997
- const result = selectBlockProductionSource({
998
- builderSelection,
999
- builderBoostFactor,
1167
+ logger.warn("Selected local block: censorship suspected in builder bid", {
1168
+ ...logCtx,
1169
+ durationMs: engineResult.durationMs,
1170
+ ...getBlockValueLogInfo(engineResult.value),
1171
+ });
1172
+ } else if (engineResult.status === "fulfilled" && bidBlockResult.status === "fulfilled") {
1173
+ const result = selectBlockProductionSourceByBoostFactor({
1174
+ builderBoostFactor: bestBid?.boostFactor ?? builderBoostFactor,
1000
1175
  engineExecutionPayloadValue: engineResult.value.executionPayloadValue,
1001
- // The bid value is the payment to the proposer, in Gwei
1002
- builderExecutionPayloadValue: BigInt(builderBid?.message.value ?? 0) * GWEI_TO_WEI,
1176
+ // The bid total payment is its value plus its counted executionPayment, in Gwei
1177
+ builderExecutionPayloadValue: (bestBid?.totalGwei ?? 0n) * GWEI_TO_WEI,
1003
1178
  });
1004
1179
  source = result.source;
1005
1180
  metrics?.blockProductionSelectionResults.inc(result);
1006
- logger.info(`Selected ${source} block`, {reason: result.reason, ...logCtx});
1007
- bestResult = source === ProducedBlockSource.builder ? bidResult : engineResult;
1008
- } else if (bidResult.status === "fulfilled") {
1181
+ logger.info(`Selected ${source} block`, {
1182
+ reason: result.reason,
1183
+ ...logCtx,
1184
+ engineDurationMs: engineResult.durationMs,
1185
+ ...getBlockValueLogInfo(engineResult.value, ProducedBlockSource.engine),
1186
+ builderDurationMs: bidBlockResult.durationMs,
1187
+ });
1188
+ bestResult = source === ProducedBlockSource.builder ? bidBlockResult : engineResult;
1189
+ } else if (bidBlockResult.status === "fulfilled") {
1009
1190
  source = ProducedBlockSource.builder;
1010
- bestResult = bidResult;
1191
+ bestResult = bidBlockResult;
1011
1192
  const reason =
1012
1193
  engineResult.status === "pending"
1013
1194
  ? BuilderBlockSelectionReason.EnginePending
@@ -1016,28 +1197,32 @@ export function getValidatorApi(
1016
1197
  logger.info("Selected builder bid block: no local block produced", {
1017
1198
  reason,
1018
1199
  ...logCtx,
1200
+ durationMs: bidBlockResult.durationMs,
1201
+ ...getBlockValueLogInfo(bidBlockResult.value),
1019
1202
  error: engineResult.status === "rejected" ? (engineResult.reason as Error).message : undefined,
1020
1203
  });
1021
1204
  } else if (engineResult.status === "fulfilled") {
1022
1205
  source = ProducedBlockSource.engine;
1023
1206
  bestResult = engineResult;
1024
1207
  const reason =
1025
- builderBid === null
1208
+ bidBlockResult.status === "rejected" && (bidBlockResult.reason as Error).message === NO_BID_AVAILABLE
1026
1209
  ? EngineBlockSelectionReason.BuilderNoBid
1027
- : bidResult.status === "pending"
1210
+ : bidBlockResult.status === "pending"
1028
1211
  ? EngineBlockSelectionReason.BuilderPending
1029
1212
  : EngineBlockSelectionReason.BuilderError;
1030
1213
  metrics?.blockProductionSelectionResults.inc({source: ProducedBlockSource.engine, reason});
1031
1214
  logger.info("Selected local block: no builder bid block produced", {
1032
1215
  reason,
1033
1216
  ...logCtx,
1034
- error: bidResult.status === "rejected" ? (bidResult.reason as Error).message : undefined,
1217
+ durationMs: engineResult.durationMs,
1218
+ ...getBlockValueLogInfo(engineResult.value),
1219
+ error: bidBlockResult.status === "rejected" ? (bidBlockResult.reason as Error).message : undefined,
1035
1220
  });
1036
1221
  }
1037
1222
 
1038
1223
  if (bestResult === null || bestResult.status !== "fulfilled") {
1039
1224
  const engineReason = engineResult.status === "rejected" ? engineResult.reason : engineResult.status;
1040
- const bidReason = bidResult.status === "rejected" ? bidResult.reason : bidResult.status;
1225
+ const bidReason = bidBlockResult.status === "rejected" ? bidBlockResult.reason : bidBlockResult.status;
1041
1226
  logger.error("Block production failed", {
1042
1227
  ...logCtx,
1043
1228
  engineReason: String(engineReason),
@@ -1061,7 +1246,10 @@ export function getValidatorApi(
1061
1246
  root: blockRoot,
1062
1247
  });
1063
1248
  if (chain.opts.persistProducedBlocks) {
1064
- void chain.persistBlock(block, "produced_engine_block");
1249
+ void chain.persistBlock(
1250
+ block,
1251
+ source === ProducedBlockSource.builder ? "produced_builder_block" : "produced_engine_block"
1252
+ );
1065
1253
  }
1066
1254
 
1067
1255
  // Include the payload for self-builds unless disabled (stateless flow)
@@ -1098,7 +1286,13 @@ export function getValidatorApi(
1098
1286
 
1099
1287
  return {
1100
1288
  data: block as gloas.BeaconBlock,
1101
- meta: {version: fork, consensusBlockValue, executionPayloadValue, executionPayloadIncluded: false},
1289
+ meta: {
1290
+ version: fork,
1291
+ consensusBlockValue,
1292
+ executionPayloadValue,
1293
+ executionPayloadIncluded: false,
1294
+ builderUrl: source === ProducedBlockSource.builder ? bestBid?.url : undefined,
1295
+ },
1102
1296
  };
1103
1297
  },
1104
1298
 
@@ -1882,6 +2076,43 @@ export function getValidatorApi(
1882
2076
  }
1883
2077
  },
1884
2078
 
2079
+ async submitBuilderPreferences({builderPreferences}) {
2080
+ const failures: FailureList = [];
2081
+
2082
+ await Promise.all(
2083
+ builderPreferences.map(async (entry, i) => {
2084
+ let builder = Buffer.from(entry.url).toString("utf8");
2085
+ try {
2086
+ const url = decodeBuilderUrl(entry.url);
2087
+ builder = toPrintableUrl(url);
2088
+ const proposerIndex = chain.getHeadState().getBeaconProposer(entry.auth.message.slot);
2089
+ const expectedProposerPubkey = chain.pubkeyCache.getOrThrow(proposerIndex).toBytes();
2090
+ if (!byteArrayEquals(entry.proposerPubkey, expectedProposerPubkey)) {
2091
+ throw new ApiError(
2092
+ 400,
2093
+ `Invalid proposer pubkey for builder preferences slot=${entry.auth.message.slot}`
2094
+ );
2095
+ }
2096
+ await chain.builderApiClient.submitBuilderPreferences(url, entry.proposerPubkey, {
2097
+ preferences: {maxExecutionPayment: entry.maxExecutionPayment},
2098
+ auth: entry.auth,
2099
+ });
2100
+ } catch (e) {
2101
+ failures.push({index: i, message: (e as Error).message});
2102
+ logger.verbose(
2103
+ `Error on submitBuilderPreferences [${i}]`,
2104
+ {slot: entry.auth.message.slot, builder},
2105
+ e as Error
2106
+ );
2107
+ }
2108
+ })
2109
+ );
2110
+
2111
+ if (failures.length > 0) {
2112
+ throw new IndexedError("Error submitting builder preferences", failures);
2113
+ }
2114
+ },
2115
+
1885
2116
  async getExecutionPayloadEnvelope({slot, beaconBlockRoot}) {
1886
2117
  const fork = config.getForkName(slot);
1887
2118
 
@@ -59,24 +59,39 @@ export function selectBlockProductionSource({
59
59
  return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.EnginePreferred};
60
60
 
61
61
  case routes.validator.BuilderSelection.Default:
62
- case routes.validator.BuilderSelection.MaxProfit: {
63
- if (builderBoostFactor === BigInt(0)) {
64
- return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.EnginePreferred};
65
- }
66
-
67
- if (builderBoostFactor === MAX_BUILDER_BOOST_FACTOR) {
68
- return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BuilderPreferred};
69
- }
70
-
71
- if (engineExecutionPayloadValue >= (builderExecutionPayloadValue * builderBoostFactor) / BigInt(100)) {
72
- return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.BlockValue};
73
- }
74
-
75
- return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BlockValue};
76
- }
62
+ case routes.validator.BuilderSelection.MaxProfit:
63
+ return selectBlockProductionSourceByBoostFactor({
64
+ engineExecutionPayloadValue,
65
+ builderExecutionPayloadValue,
66
+ builderBoostFactor,
67
+ });
77
68
 
78
69
  case routes.validator.BuilderSelection.BuilderAlways:
79
70
  case routes.validator.BuilderSelection.BuilderOnly:
80
71
  return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BuilderPreferred};
81
72
  }
82
73
  }
74
+
75
+ export function selectBlockProductionSourceByBoostFactor({
76
+ engineExecutionPayloadValue,
77
+ builderExecutionPayloadValue,
78
+ builderBoostFactor,
79
+ }: {
80
+ engineExecutionPayloadValue: bigint;
81
+ builderExecutionPayloadValue: bigint;
82
+ builderBoostFactor: bigint;
83
+ }): BlockSelectionResult {
84
+ if (builderBoostFactor === BigInt(0)) {
85
+ return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.EnginePreferred};
86
+ }
87
+
88
+ if (builderBoostFactor === MAX_BUILDER_BOOST_FACTOR) {
89
+ return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BuilderPreferred};
90
+ }
91
+
92
+ if (engineExecutionPayloadValue * 100n >= builderExecutionPayloadValue * builderBoostFactor) {
93
+ return {source: ProducedBlockSource.engine, reason: EngineBlockSelectionReason.BlockValue};
94
+ }
95
+
96
+ return {source: ProducedBlockSource.builder, reason: BuilderBlockSelectionReason.BlockValue};
97
+ }
@@ -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
@@ -1,3 +1,4 @@
1
+ import {ForkName} from "@lodestar/params";
1
2
  import {
2
3
  BeaconStateTransitionMetrics,
3
4
  EpochTransitionStep,
@@ -45,6 +46,27 @@ export function createHistoricalStateTransitionMetrics(
45
46
  labelNames: ["step"],
46
47
  buckets: [0.01, 0.05, 0.1, 0.2, 0.5, 0.75, 1],
47
48
  }),
49
+ forkUpgradeTime: metricsRegister.histogram<{fork: ForkName}>({
50
+ name: "lodestar_historical_state_stfn_fork_upgrade_seconds",
51
+ help: "Time to upgrade the state at a fork boundary in seconds",
52
+ labelNames: ["fork"],
53
+ buckets: [0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30],
54
+ }),
55
+ onboardBuildersTime: metricsRegister.histogram({
56
+ name: "lodestar_historical_state_stfn_gloas_onboard_builders_seconds",
57
+ help: "Time spent in onboardBuildersFromPendingDeposits at the gloas fork transition",
58
+ buckets: [0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30],
59
+ }),
60
+ onboardBuildersDeposits: metricsRegister.gauge<{outcome: "onboarded" | "topup" | "kept" | "dropped"}>({
61
+ name: "lodestar_historical_state_stfn_gloas_onboard_builders_deposits",
62
+ help: "Pending deposits handled at the gloas fork transition, by outcome",
63
+ labelNames: ["outcome"],
64
+ }),
65
+ onboardBuildersSignatureChecks: metricsRegister.gauge<{source: "cache" | "verified"}>({
66
+ name: "lodestar_historical_state_stfn_gloas_onboard_builders_signature_checks",
67
+ help: "Builder deposit signature checks at the gloas fork transition, by whether the pre-verify cache served them",
68
+ labelNames: ["source"],
69
+ }),
48
70
  processBlockTime: metricsRegister.histogram({
49
71
  name: "lodestar_historical_state_stfn_process_block_seconds",
50
72
  help: "Time to process a single block in seconds",
@@ -22,7 +22,6 @@ import {
22
22
  RootCache,
23
23
  computeEpochAtSlot,
24
24
  computeTimeAtSlot,
25
- isStartSlotOfEpoch,
26
25
  isStatePostAltair,
27
26
  isStatePostBellatrix,
28
27
  } from "@lodestar/state-transition";
@@ -404,11 +403,7 @@ export async function importBlock(
404
403
  notOverrideFcuReason = NotReorgedReason.NotProposerOfNextSlot;
405
404
  }
406
405
  } catch (e) {
407
- if (isStartSlotOfEpoch(proposalSlot)) {
408
- notOverrideFcuReason = NotReorgedReason.AtEpochBoundary;
409
- } else {
410
- this.logger.warn("Unable to get beacon proposer. Do not override fcu.", {proposalSlot}, e as Error);
411
- }
406
+ this.logger.warn("Unable to get beacon proposer. Do not override fcu.", {proposalSlot}, e as Error);
412
407
  }
413
408
 
414
409
  if (shouldOverrideFcu) {