@lodestar/beacon-node 1.46.0 → 1.47.0-dev.02d2dbea03

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 (348) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +6 -8
  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 +12 -22
  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 +3 -8
  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 +12 -10
  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 +17 -11
  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/verifyBlock.d.ts.map +1 -1
  51. package/lib/chain/blocks/verifyBlock.js +11 -16
  52. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  53. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  54. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
  55. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  56. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  57. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  58. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  59. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  60. package/lib/chain/bls/index.d.ts +1 -1
  61. package/lib/chain/bls/index.d.ts.map +1 -1
  62. package/lib/chain/bls/interface.d.ts +5 -5
  63. package/lib/chain/bls/interface.d.ts.map +1 -1
  64. package/lib/chain/bls/multithread/index.d.ts +5 -11
  65. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  66. package/lib/chain/bls/multithread/index.js +116 -101
  67. package/lib/chain/bls/multithread/index.js.map +1 -1
  68. package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
  69. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  70. package/lib/chain/bls/multithread/jobItem.js +10 -65
  71. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  72. package/lib/chain/bls/multithread/types.d.ts +29 -8
  73. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  74. package/lib/chain/bls/multithread/types.js +12 -0
  75. package/lib/chain/bls/multithread/types.js.map +1 -1
  76. package/lib/chain/bls/multithread/utils.d.ts +4 -0
  77. package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
  78. package/lib/chain/bls/multithread/utils.js +10 -0
  79. package/lib/chain/bls/multithread/utils.js.map +1 -1
  80. package/lib/chain/bls/multithread/worker.js +49 -23
  81. package/lib/chain/bls/multithread/worker.js.map +1 -1
  82. package/lib/chain/bls/singleThread.d.ts +4 -10
  83. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  84. package/lib/chain/bls/singleThread.js +8 -45
  85. package/lib/chain/bls/singleThread.js.map +1 -1
  86. package/lib/chain/bls/utils.d.ts +4 -4
  87. package/lib/chain/bls/utils.d.ts.map +1 -1
  88. package/lib/chain/bls/utils.js +18 -19
  89. package/lib/chain/bls/utils.js.map +1 -1
  90. package/lib/chain/builderCircuitBreaker.d.ts +6 -5
  91. package/lib/chain/builderCircuitBreaker.d.ts.map +1 -1
  92. package/lib/chain/builderCircuitBreaker.js +28 -15
  93. package/lib/chain/builderCircuitBreaker.js.map +1 -1
  94. package/lib/chain/chain.d.ts +5 -3
  95. package/lib/chain/chain.d.ts.map +1 -1
  96. package/lib/chain/chain.js +24 -8
  97. package/lib/chain/chain.js.map +1 -1
  98. package/lib/chain/errors/blockError.d.ts +2 -0
  99. package/lib/chain/errors/blockError.d.ts.map +1 -1
  100. package/lib/chain/errors/blockError.js +6 -1
  101. package/lib/chain/errors/blockError.js.map +1 -1
  102. package/lib/chain/errors/proposerPreferences.d.ts +6 -0
  103. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
  104. package/lib/chain/errors/proposerPreferences.js +1 -0
  105. package/lib/chain/errors/proposerPreferences.js.map +1 -1
  106. package/lib/chain/interface.d.ts +4 -2
  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/index.d.ts +1 -0
  120. package/lib/chain/opPools/index.d.ts.map +1 -1
  121. package/lib/chain/opPools/index.js +1 -0
  122. package/lib/chain/opPools/index.js.map +1 -1
  123. package/lib/chain/opPools/payloadAttestationPool.js +3 -3
  124. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  125. package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
  126. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  127. package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
  128. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  129. package/lib/chain/opPools/utils.d.ts +1 -1
  130. package/lib/chain/opPools/utils.d.ts.map +1 -1
  131. package/lib/chain/opPools/utils.js +1 -1
  132. package/lib/chain/opPools/utils.js.map +1 -1
  133. package/lib/chain/options.d.ts +1 -3
  134. package/lib/chain/options.d.ts.map +1 -1
  135. package/lib/chain/options.js.map +1 -1
  136. package/lib/chain/prepareNextSlot.js +2 -2
  137. package/lib/chain/prepareNextSlot.js.map +1 -1
  138. package/lib/chain/produceBlock/produceBlockBody.d.ts +2 -0
  139. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  140. package/lib/chain/produceBlock/produceBlockBody.js +8 -3
  141. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  142. package/lib/chain/regen/interface.d.ts +4 -2
  143. package/lib/chain/regen/interface.d.ts.map +1 -1
  144. package/lib/chain/regen/interface.js +2 -0
  145. package/lib/chain/regen/interface.js.map +1 -1
  146. package/lib/chain/regen/queued.d.ts +2 -2
  147. package/lib/chain/regen/queued.d.ts.map +1 -1
  148. package/lib/chain/regen/queued.js +5 -5
  149. package/lib/chain/regen/queued.js.map +1 -1
  150. package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
  151. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  152. package/lib/chain/seenCache/seenAttesters.js +25 -4
  153. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  154. package/lib/chain/seenCache/seenBlockProposers.d.ts +5 -1
  155. package/lib/chain/seenCache/seenBlockProposers.d.ts.map +1 -1
  156. package/lib/chain/seenCache/seenBlockProposers.js +17 -7
  157. package/lib/chain/seenCache/seenBlockProposers.js.map +1 -1
  158. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +28 -1
  159. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  160. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
  161. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  162. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +5 -1
  163. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  164. package/lib/chain/stateCache/fifoBlockStateCache.js +6 -0
  165. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  166. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +47 -5
  167. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  168. package/lib/chain/stateCache/persistentCheckpointsCache.js +117 -7
  169. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  170. package/lib/chain/stateCache/types.d.ts +3 -3
  171. package/lib/chain/stateCache/types.d.ts.map +1 -1
  172. package/lib/chain/validation/attestation.d.ts.map +1 -1
  173. package/lib/chain/validation/attestation.js +1 -4
  174. package/lib/chain/validation/attestation.js.map +1 -1
  175. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  176. package/lib/chain/validation/attesterSlashing.js +1 -1
  177. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  178. package/lib/chain/validation/block.d.ts.map +1 -1
  179. package/lib/chain/validation/block.js +21 -7
  180. package/lib/chain/validation/block.js.map +1 -1
  181. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  182. package/lib/chain/validation/executionPayloadBid.js +1 -2
  183. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  184. package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
  185. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  186. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  187. package/lib/chain/validation/payloadAttestationMessage.js +5 -14
  188. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  189. package/lib/chain/validation/proposerPreferences.d.ts +1 -1
  190. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
  191. package/lib/chain/validation/proposerPreferences.js +13 -4
  192. package/lib/chain/validation/proposerPreferences.js.map +1 -1
  193. package/lib/chain/validation/proposerSlashing.js +1 -1
  194. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  195. package/lib/chain/validation/voluntaryExit.d.ts +9 -1
  196. package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
  197. package/lib/chain/validation/voluntaryExit.js +46 -1
  198. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  199. package/lib/execution/builder/http.d.ts +10 -7
  200. package/lib/execution/builder/http.d.ts.map +1 -1
  201. package/lib/execution/builder/http.js +11 -8
  202. package/lib/execution/builder/http.js.map +1 -1
  203. package/lib/metrics/metrics/beacon.d.ts +3 -3
  204. package/lib/metrics/metrics/beacon.d.ts.map +1 -1
  205. package/lib/metrics/metrics/beacon.js +9 -9
  206. package/lib/metrics/metrics/beacon.js.map +1 -1
  207. package/lib/metrics/metrics/lodestar.d.ts +71 -22
  208. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  209. package/lib/metrics/metrics/lodestar.js +126 -52
  210. package/lib/metrics/metrics/lodestar.js.map +1 -1
  211. package/lib/network/gossip/topic.d.ts +13 -0
  212. package/lib/network/gossip/topic.d.ts.map +1 -1
  213. package/lib/network/gossip/topic.js +37 -0
  214. package/lib/network/gossip/topic.js.map +1 -1
  215. package/lib/network/libp2p/index.d.ts.map +1 -1
  216. package/lib/network/libp2p/index.js +10 -2
  217. package/lib/network/libp2p/index.js.map +1 -1
  218. package/lib/network/network.d.ts.map +1 -1
  219. package/lib/network/network.js +22 -43
  220. package/lib/network/network.js.map +1 -1
  221. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  222. package/lib/network/processor/gossipHandlers.js +37 -6
  223. package/lib/network/processor/gossipHandlers.js.map +1 -1
  224. package/lib/network/reqresp/score.d.ts.map +1 -1
  225. package/lib/network/reqresp/score.js +5 -11
  226. package/lib/network/reqresp/score.js.map +1 -1
  227. package/lib/network/util.d.ts +0 -1
  228. package/lib/network/util.d.ts.map +1 -1
  229. package/lib/network/util.js +0 -4
  230. package/lib/network/util.js.map +1 -1
  231. package/lib/node/deferredVoluntaryExitPublisher.d.ts +15 -0
  232. package/lib/node/deferredVoluntaryExitPublisher.d.ts.map +1 -0
  233. package/lib/node/deferredVoluntaryExitPublisher.js +38 -0
  234. package/lib/node/deferredVoluntaryExitPublisher.js.map +1 -0
  235. package/lib/node/nodejs.d.ts +2 -1
  236. package/lib/node/nodejs.d.ts.map +1 -1
  237. package/lib/node/nodejs.js +2 -0
  238. package/lib/node/nodejs.js.map +1 -1
  239. package/lib/sync/range/batch.d.ts +23 -5
  240. package/lib/sync/range/batch.d.ts.map +1 -1
  241. package/lib/sync/range/batch.js +62 -23
  242. package/lib/sync/range/batch.js.map +1 -1
  243. package/lib/sync/range/chain.d.ts +2 -1
  244. package/lib/sync/range/chain.d.ts.map +1 -1
  245. package/lib/sync/range/chain.js +23 -10
  246. package/lib/sync/range/chain.js.map +1 -1
  247. package/lib/sync/range/utils/hashBlocks.d.ts +16 -4
  248. package/lib/sync/range/utils/hashBlocks.d.ts.map +1 -1
  249. package/lib/sync/range/utils/hashBlocks.js +49 -18
  250. package/lib/sync/range/utils/hashBlocks.js.map +1 -1
  251. package/lib/sync/types.d.ts +32 -0
  252. package/lib/sync/types.d.ts.map +1 -1
  253. package/lib/sync/types.js +33 -0
  254. package/lib/sync/types.js.map +1 -1
  255. package/lib/sync/unknownBlock.d.ts +9 -0
  256. package/lib/sync/unknownBlock.d.ts.map +1 -1
  257. package/lib/sync/unknownBlock.js +187 -47
  258. package/lib/sync/unknownBlock.js.map +1 -1
  259. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  260. package/lib/sync/utils/downloadByRange.js +16 -11
  261. package/lib/sync/utils/downloadByRange.js.map +1 -1
  262. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  263. package/lib/sync/utils/downloadByRoot.js +3 -1
  264. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  265. package/package.json +37 -37
  266. package/src/api/impl/beacon/blocks/index.ts +7 -8
  267. package/src/api/impl/beacon/pool/index.ts +27 -2
  268. package/src/api/impl/beacon/state/utils.ts +2 -1
  269. package/src/api/impl/events/index.ts +12 -4
  270. package/src/api/impl/lodestar/index.ts +12 -13
  271. package/src/api/impl/validator/index.ts +22 -27
  272. package/src/api/impl/validator/utils.ts +30 -15
  273. package/src/api/rest/base.ts +7 -0
  274. package/src/chain/archiveStore/archiveStore.ts +1 -1
  275. package/src/chain/archiveStore/historicalState/metrics.ts +22 -0
  276. package/src/chain/blocks/importBlock.ts +2 -7
  277. package/src/chain/blocks/importExecutionPayload.ts +13 -12
  278. package/src/chain/blocks/index.ts +21 -11
  279. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
  280. package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
  281. package/src/chain/blocks/verifyBlock.ts +21 -25
  282. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
  283. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
  284. package/src/chain/bls/index.ts +1 -1
  285. package/src/chain/bls/interface.ts +7 -3
  286. package/src/chain/bls/multithread/index.ts +148 -120
  287. package/src/chain/bls/multithread/jobItem.ts +12 -82
  288. package/src/chain/bls/multithread/types.ts +33 -8
  289. package/src/chain/bls/multithread/utils.ts +11 -0
  290. package/src/chain/bls/multithread/worker.ts +85 -27
  291. package/src/chain/bls/singleThread.ts +11 -55
  292. package/src/chain/bls/utils.ts +23 -24
  293. package/src/chain/builderCircuitBreaker.ts +31 -17
  294. package/src/chain/chain.ts +25 -7
  295. package/src/chain/errors/blockError.ts +9 -3
  296. package/src/chain/errors/proposerPreferences.ts +7 -0
  297. package/src/chain/interface.ts +4 -1
  298. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  299. package/src/chain/opPools/attestationPool.ts +1 -1
  300. package/src/chain/opPools/deferredVoluntaryExitPool.ts +65 -0
  301. package/src/chain/opPools/index.ts +1 -0
  302. package/src/chain/opPools/payloadAttestationPool.ts +3 -3
  303. package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
  304. package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
  305. package/src/chain/opPools/utils.ts +1 -1
  306. package/src/chain/options.ts +1 -3
  307. package/src/chain/prepareNextSlot.ts +2 -2
  308. package/src/chain/produceBlock/produceBlockBody.ts +15 -2
  309. package/src/chain/regen/interface.ts +4 -2
  310. package/src/chain/regen/queued.ts +5 -5
  311. package/src/chain/seenCache/seenAttesters.ts +31 -5
  312. package/src/chain/seenCache/seenBlockProposers.ts +24 -7
  313. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
  314. package/src/chain/stateCache/fifoBlockStateCache.ts +8 -1
  315. package/src/chain/stateCache/persistentCheckpointsCache.ts +133 -8
  316. package/src/chain/stateCache/types.ts +3 -3
  317. package/src/chain/validation/attestation.ts +1 -7
  318. package/src/chain/validation/attesterSlashing.ts +1 -8
  319. package/src/chain/validation/block.ts +21 -7
  320. package/src/chain/validation/executionPayloadBid.ts +1 -2
  321. package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
  322. package/src/chain/validation/payloadAttestationMessage.ts +6 -17
  323. package/src/chain/validation/proposerPreferences.ts +15 -5
  324. package/src/chain/validation/proposerSlashing.ts +1 -1
  325. package/src/chain/validation/voluntaryExit.ts +59 -2
  326. package/src/execution/builder/http.ts +11 -11
  327. package/src/metrics/metrics/beacon.ts +9 -9
  328. package/src/metrics/metrics/lodestar.ts +138 -57
  329. package/src/network/gossip/topic.ts +38 -0
  330. package/src/network/libp2p/index.ts +11 -2
  331. package/src/network/network.ts +27 -55
  332. package/src/network/processor/gossipHandlers.ts +40 -4
  333. package/src/network/reqresp/score.ts +5 -11
  334. package/src/network/util.ts +0 -5
  335. package/src/node/deferredVoluntaryExitPublisher.ts +54 -0
  336. package/src/node/nodejs.ts +5 -1
  337. package/src/sync/range/batch.ts +84 -29
  338. package/src/sync/range/chain.ts +26 -11
  339. package/src/sync/range/utils/hashBlocks.ts +56 -21
  340. package/src/sync/types.ts +36 -1
  341. package/src/sync/unknownBlock.ts +212 -53
  342. package/src/sync/utils/downloadByRange.ts +21 -12
  343. package/src/sync/utils/downloadByRoot.ts +3 -1
  344. package/lib/chain/bls/maybeBatch.d.ts +0 -12
  345. package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
  346. package/lib/chain/bls/maybeBatch.js +0 -35
  347. package/lib/chain/bls/maybeBatch.js.map +0 -1
  348. package/src/chain/bls/maybeBatch.ts +0 -45
@@ -1,6 +1,7 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {ChainForkConfig} from "@lodestar/config";
3
- import {ForkSeq} from "@lodestar/params";
3
+ import {CheckpointWithHex} from "@lodestar/fork-choice";
4
+ import {ForkSeq, SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
4
5
  import {RequestError, RequestErrorCode} from "@lodestar/reqresp";
5
6
  import {computeTimeAtSlot} from "@lodestar/state-transition";
6
7
  import {RootHex, Slot, gloas} from "@lodestar/types";
@@ -24,6 +25,7 @@ import {MAX_CONCURRENT_REQUESTS} from "./constants.js";
24
25
  import {SyncOptions} from "./options.js";
25
26
  import {
26
27
  BlockInputSyncCacheItem,
28
+ DroppedItemReason,
27
29
  PayloadSyncCacheItem,
28
30
  PendingBlockInput,
29
31
  PendingBlockInputStatus,
@@ -47,6 +49,10 @@ import {getRateLimitedUntilMs} from "./utils/rateLimit.js";
47
49
  const MAX_ATTEMPTS_PER_BLOCK = 5;
48
50
  const MAX_KNOWN_BAD_BLOCKS = 500;
49
51
  const MAX_PENDING_BLOCKS = 100;
52
+ /**
53
+ * A pending payload without slot can only stay at most 2 epochs.
54
+ */
55
+ const PRUNE_UNRESOLVED_SLOT_EPOCHS = 2;
50
56
 
51
57
  type AdvancePendingBlockResult =
52
58
  | "ready"
@@ -154,6 +160,7 @@ export class BlockInputSync {
154
160
  this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
155
161
  this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
156
162
  this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
163
+ this.chain.emitter.on(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
157
164
  this.chain.emitter.on(routes.events.EventType.block, this.onBlockImported);
158
165
  this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
159
166
  this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
@@ -170,6 +177,7 @@ export class BlockInputSync {
170
177
  this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
171
178
  this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
172
179
  this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
180
+ this.chain.emitter.off(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
173
181
  this.chain.emitter.off(routes.events.EventType.block, this.onBlockImported);
174
182
  this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
175
183
  this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
@@ -215,7 +223,7 @@ export class BlockInputSync {
215
223
 
216
224
  private onUnknownEnvelopeBlockRoot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]): void => {
217
225
  try {
218
- this.addByPayloadRootHex(data.rootHex, data.peer, data.slot);
226
+ this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
219
227
  this.triggerUnknownBlockSearch();
220
228
  this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT});
221
229
  this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
@@ -252,13 +260,13 @@ export class BlockInputSync {
252
260
  parentRoot: missingDependency.parentRootHex,
253
261
  parentBlockHash: missingDependency.parentBlockHashHex,
254
262
  });
255
- this.removeAndDownScoreAllDescendants(pendingBlock);
263
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
256
264
  }
257
265
  return;
258
266
  }
259
267
 
260
268
  if (missingDependency.kind === "parentPayload") {
261
- this.addByPayloadRootHex(missingDependency.rootHex, data.peer);
269
+ this.addByPayloadRootHex(missingDependency.rootHex, data.peer, missingDependency.slot);
262
270
  } else if (missingDependency.kind === "parentBlock") {
263
271
  this.addByRootHex(missingDependency.rootHex, data.peer);
264
272
  }
@@ -284,6 +292,80 @@ export class BlockInputSync {
284
292
  this.triggerUnknownBlockSearch();
285
293
  };
286
294
 
295
+ /**
296
+ * Drop pending payloads and blocks that fell below the finalized slot.
297
+ * See https://github.com/ChainSafe/lodestar/issues/9800
298
+ */
299
+ private pruneFinalized = (checkpoint: CheckpointWithHex): void => {
300
+ // Use the actual finalized block slot, not computeStartSlotAtEpoch(checkpoint.epoch)
301
+ // because the payload at the finalized block is not finalized
302
+ const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
303
+ const nowSec = Date.now() / 1000;
304
+ const maxSecInCache = (PRUNE_UNRESOLVED_SLOT_EPOCHS * SLOTS_PER_EPOCH * this.config.SLOT_DURATION_MS) / 1000;
305
+
306
+ let belowFinalizedPayloads = 0;
307
+ let agedOutPayloads = 0;
308
+ let unresolvedSlotPayloads = 0;
309
+
310
+ for (const [rootHex, payload] of this.pendingPayloads) {
311
+ // Last-effort resolve for a slot-less PendingPayloadRootHex, and store it back for later passes.
312
+ if (!isPendingPayloadInput(payload) && !isPendingPayloadEnvelope(payload) && payload.slot === undefined) {
313
+ payload.slot = this.resolvePayloadSlot(rootHex);
314
+ if (payload.slot === undefined) {
315
+ // Still unresolvable: age it out so the MAX_PENDING_BLOCKS cap cannot stay saturated.
316
+ if (nowSec - payload.timeAddedSec > maxSecInCache) {
317
+ this.pendingPayloads.delete(rootHex);
318
+ agedOutPayloads++;
319
+ } else {
320
+ unresolvedSlotPayloads++;
321
+ this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
322
+ root: rootHex,
323
+ finalizedSlot,
324
+ });
325
+ }
326
+ continue;
327
+ }
328
+ }
329
+
330
+ const slot = getPayloadSyncCacheItemSlot(payload);
331
+ if (typeof slot === "number" && slot < finalizedSlot) {
332
+ this.pendingPayloads.delete(rootHex);
333
+ belowFinalizedPayloads++;
334
+ }
335
+ }
336
+
337
+ let deletedBlocks = 0;
338
+ for (const [rootHex, block] of this.pendingBlocks) {
339
+ const slot = getBlockInputSyncCacheItemSlot(block);
340
+ if (typeof slot === "number" && slot < finalizedSlot) {
341
+ this.pendingBlocks.delete(rootHex);
342
+ deletedBlocks++;
343
+ }
344
+ }
345
+
346
+ if (belowFinalizedPayloads > 0) {
347
+ this.metrics?.blockInputSync.removedPayloads.inc(
348
+ {reason: DroppedItemReason.belowFinalized},
349
+ belowFinalizedPayloads
350
+ );
351
+ }
352
+ if (agedOutPayloads > 0) {
353
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.agedOut}, agedOutPayloads);
354
+ }
355
+ if (deletedBlocks > 0) {
356
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.belowFinalized}, deletedBlocks);
357
+ }
358
+
359
+ this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
360
+ finalizedSlot,
361
+ finalizedRoot: checkpoint.rootHex,
362
+ belowFinalizedPayloads,
363
+ agedOutPayloads,
364
+ deletedBlocks,
365
+ unresolvedSlotPayloads,
366
+ });
367
+ };
368
+
287
369
  private addByRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr): boolean => {
288
370
  let pendingBlock = this.pendingBlocks.get(rootHex);
289
371
  let added = false;
@@ -311,6 +393,7 @@ export class BlockInputSync {
311
393
  // Limit pending blocks to prevent DOS attacks that cause OOM
312
394
  const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
313
395
  if (prunedItemCount > 0) {
396
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
314
397
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
315
398
  }
316
399
  return added;
@@ -345,6 +428,7 @@ export class BlockInputSync {
345
428
  // Limit pending blocks to prevent DOS attacks that cause OOM
346
429
  const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
347
430
  if (prunedItemCount > 0) {
431
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
348
432
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
349
433
  }
350
434
  };
@@ -369,6 +453,14 @@ export class BlockInputSync {
369
453
  root: rootHex,
370
454
  peerIdStr: peerIdStr ?? "unknown peer",
371
455
  });
456
+ } else if (
457
+ // update a previously slot-less entry once a slot becomes available
458
+ slot !== undefined &&
459
+ !isPendingPayloadInput(pendingPayload) &&
460
+ !isPendingPayloadEnvelope(pendingPayload) &&
461
+ pendingPayload.slot === undefined
462
+ ) {
463
+ pendingPayload.slot = slot;
372
464
  }
373
465
 
374
466
  if (peerIdStr) {
@@ -377,11 +469,35 @@ export class BlockInputSync {
377
469
 
378
470
  const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
379
471
  if (prunedItemCount > 0) {
472
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
380
473
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
381
474
  }
382
475
  return added;
383
476
  };
384
477
 
478
+ /**
479
+ * Resolve the block slot for a payload root.
480
+ */
481
+ private resolvePayloadSlot(rootHex: RootHex): Slot | undefined {
482
+ // a pending block of the same root
483
+ const pendingBlock = this.pendingBlocks.get(rootHex);
484
+ if (pendingBlock) {
485
+ const pendingBlockSlot = getBlockInputSyncCacheItemSlot(pendingBlock);
486
+ if (typeof pendingBlockSlot === "number") {
487
+ return pendingBlockSlot;
488
+ }
489
+ }
490
+
491
+ // the block is in fork choice
492
+ const forkChoiceSlot = this.chain.forkChoice.getBlockHexDefaultStatus(rootHex)?.slot;
493
+ if (forkChoiceSlot !== undefined) {
494
+ return forkChoiceSlot;
495
+ }
496
+
497
+ // a seen payload envelope input
498
+ return this.chain.seenPayloadEnvelopeInputCache.get(rootHex)?.slot;
499
+ }
500
+
385
501
  private addByPayloadInput = (
386
502
  payloadInput: PayloadEnvelopeInput,
387
503
  peerIdStr?: PeerIdStr,
@@ -407,6 +523,7 @@ export class BlockInputSync {
407
523
 
408
524
  const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
409
525
  if (prunedItemCount > 0) {
526
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
410
527
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
411
528
  }
412
529
  };
@@ -436,10 +553,12 @@ export class BlockInputSync {
436
553
  blockInput: IBlockInput
437
554
  ):
438
555
  | {kind: "ready"}
439
- | {kind: "block" | "parentBlock" | "parentPayload"; rootHex: RootHex}
556
+ | {kind: "block" | "parentBlock"; rootHex: RootHex}
557
+ | {kind: "parentPayload"; rootHex: RootHex; slot: Slot}
440
558
  | {kind: "invalidParentPayload"; parentRootHex: RootHex; parentBlockHashHex: RootHex} {
441
559
  const parentRootHex = blockInput.parentRootHex;
442
- if (!this.chain.forkChoice.hasBlockHex(parentRootHex)) {
560
+ const parentBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentRootHex);
561
+ if (!parentBlock) {
443
562
  return {kind: "parentBlock", rootHex: parentRootHex};
444
563
  }
445
564
 
@@ -461,16 +580,8 @@ export class BlockInputSync {
461
580
  return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
462
581
  }
463
582
 
464
- const parentPayloadInput = this.chain.seenPayloadEnvelopeInputCache.get(parentRootHex);
465
- if (parentPayloadInput) {
466
- if (parentPayloadInput.getBlockHashHex() === parentBlockHashHex) {
467
- return {kind: "parentPayload", rootHex: parentRootHex};
468
- }
469
-
470
- return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
471
- }
472
-
473
- return {kind: "parentPayload", rootHex: parentRootHex};
583
+ // Parent is in fork choice but its payload `parentBlockHashHex` isn't revealed yet
584
+ return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
474
585
  }
475
586
 
476
587
  private advancePendingBlock(pendingBlock: PendingBlockInput): AdvancePendingBlockResult {
@@ -493,9 +604,9 @@ export class BlockInputSync {
493
604
  }
494
605
 
495
606
  case "parentPayload": {
496
- let added = this.addByPayloadRootHex(missingDependency.rootHex);
607
+ let added = this.addByPayloadRootHex(missingDependency.rootHex, undefined, missingDependency.slot);
497
608
  for (const peerIdStr of pendingBlock.peerIdStrings) {
498
- added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr) || added;
609
+ added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr, missingDependency.slot) || added;
499
610
  }
500
611
  return added ? "queued_parent_payload" : "blocked";
501
612
  }
@@ -507,7 +618,7 @@ export class BlockInputSync {
507
618
  parentRoot: missingDependency.parentRootHex,
508
619
  parentBlockHash: missingDependency.parentBlockHashHex,
509
620
  });
510
- this.removeAndDownScoreAllDescendants(pendingBlock);
621
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
511
622
  return "removed";
512
623
  }
513
624
  }
@@ -730,7 +841,7 @@ export class BlockInputSync {
730
841
  ...logCtx2,
731
842
  finalizedSlot,
732
843
  });
733
- this.removeAndDownScoreAllDescendants(block);
844
+ this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
734
845
  } else {
735
846
  this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
736
847
  }
@@ -747,7 +858,7 @@ export class BlockInputSync {
747
858
 
748
859
  this.metrics?.blockInputSync.downloadedBlocksError.inc();
749
860
  this.logger.debug("Ignoring unknown block root after many failed downloads", logCtx, res.err);
750
- this.removeAndDownScoreAllDescendants(block);
861
+ this.removeAndDownScoreAllDescendants(block, DroppedItemReason.unavailable);
751
862
  }
752
863
  }
753
864
 
@@ -764,9 +875,10 @@ export class BlockInputSync {
764
875
  // this prevents unbundling attack
765
876
  // see https://lighthouse-blog.sigmaprime.io/mev-unbundling-rpc.html
766
877
  const {slot: blockSlot, proposerIndex} = pendingBlock.blockInput.getBlock().message;
878
+ const blockRootHex = pendingBlock.blockInput.blockRootHex;
767
879
  const logCtx = {
768
880
  slot: blockSlot,
769
- root: pendingBlock.blockInput.blockRootHex,
881
+ root: blockRootHex,
770
882
  delaySec: this.chain.clock.secFromSlot(blockSlot),
771
883
  };
772
884
  this.logger.verbose("Processing downloaded block", logCtx);
@@ -780,7 +892,7 @@ export class BlockInputSync {
780
892
  // eligible for proposer boost to prevent unbundling attack
781
893
  this.logger.verbose("Avoid proposer boost for this block of known proposer", {
782
894
  slot: blockSlot,
783
- root: pendingBlock.blockInput.blockRootHex,
895
+ root: blockRootHex,
784
896
  proposerIndex,
785
897
  });
786
898
  await sleep(proposerBoostWindowMs);
@@ -807,12 +919,24 @@ export class BlockInputSync {
807
919
  if (!res.err) {
808
920
  this.logger.verbose("Processed block from unknown sync", logCtx);
809
921
  // no need to update status to "processed", delete anyway
810
- this.pendingBlocks.delete(pendingBlock.blockInput.blockRootHex);
922
+ this.pendingBlocks.delete(blockRootHex);
923
+
924
+ if (isForkPostGloas(fork)) {
925
+ const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
926
+ if (!payloadInput) {
927
+ this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
928
+ } else {
929
+ // Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
930
+ // The bid already carries the kzg commitments, so there is no reason to wait for the payload to arrive.
931
+ this.chain.getBlobsTracker.triggerGetBlobs(payloadInput);
932
+ }
933
+ }
934
+
811
935
  // Re-enter the scheduler so descendants blocked on either parent blocks or parent payloads
812
936
  // are advanced through the same dependency checks as every other pending item.
813
937
  this.triggerUnknownBlockSearch();
814
938
  } else {
815
- const errorData = {slot: pendingBlock.blockInput.slot, root: pendingBlock.blockInput.blockRootHex};
939
+ const errorData = {slot: pendingBlock.blockInput.slot, root: blockRootHex};
816
940
  if (res.err instanceof BlockError) {
817
941
  switch (res.err.type.code) {
818
942
  // This cases are already handled with `{ignoreIfKnown: true}`
@@ -842,19 +966,19 @@ export class BlockInputSync {
842
966
  case BlockErrorCode.EXECUTION_ENGINE_ERROR:
843
967
  // Removing the block(s) without penalizing the peers, hoping for EL to
844
968
  // recover on a latter download + verify attempt.
845
- this.removeAllDescendants(pendingBlock);
969
+ this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
846
970
  break;
847
971
 
848
972
  case BlockErrorCode.EXECUTION_ENGINE_INVALID:
849
973
  // the peer served a bad block
850
974
  this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
851
- this.removeAndDownScoreAllDescendants(pendingBlock);
975
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
852
976
  break;
853
977
 
854
978
  default:
855
979
  // Block is not correct with respect to our chain. Log error loudly
856
980
  this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
857
- this.removeAndDownScoreAllDescendants(pendingBlock);
981
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
858
982
  }
859
983
  }
860
984
 
@@ -873,12 +997,12 @@ export class BlockInputSync {
873
997
  */
874
998
  private async reconcilePayloadEnvelope(pendingPayload: PendingPayloadEnvelope): Promise<void> {
875
999
  const rootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
1000
+
876
1001
  if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
877
1002
  this.pendingPayloads.delete(rootHex);
878
1003
  return;
879
1004
  }
880
1005
 
881
- const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
882
1006
  if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
883
1007
  // Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
884
1008
  // non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
@@ -894,8 +1018,9 @@ export class BlockInputSync {
894
1018
  return;
895
1019
  }
896
1020
 
1021
+ const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
897
1022
  if (!payloadInput) {
898
- this.logger.debug("Missing PayloadEnvelopeInput for known block while reconciling payload envelope", {
1023
+ this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
899
1024
  root: rootHex,
900
1025
  });
901
1026
  return;
@@ -915,6 +1040,7 @@ export class BlockInputSync {
915
1040
  const pendingPayloadByRoot: PendingPayloadRootHex = {
916
1041
  status: PendingPayloadInputStatus.pending,
917
1042
  rootHex,
1043
+ slot: pendingPayload.envelope.message.payload.slotNumber,
918
1044
  timeAddedSec: pendingPayload.timeAddedSec,
919
1045
  peerIdStrings: new Set(pendingPayload.peerIdStrings),
920
1046
  };
@@ -954,6 +1080,10 @@ export class BlockInputSync {
954
1080
  return;
955
1081
  }
956
1082
 
1083
+ if (!isPendingPayloadInput(payload) && payload.slot === undefined) {
1084
+ payload.slot = this.resolvePayloadSlot(rootHex);
1085
+ }
1086
+
957
1087
  const payloadSlot = getPayloadSyncCacheItemSlot(payload);
958
1088
  const logCtx = {
959
1089
  slot: payloadSlot,
@@ -969,7 +1099,13 @@ export class BlockInputSync {
969
1099
  const res = await wrapError(this.fetchPayloadInput(payload));
970
1100
  if (!res.err) {
971
1101
  const pendingPayload = res.result;
972
- this.pendingPayloads.set(getPayloadSyncCacheItemRootHex(pendingPayload), pendingPayload);
1102
+ const resultRootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
1103
+ // finalization may have deleted this entry while we were awaiting the network, do not resurrect it via the set below
1104
+ if (!this.pendingPayloads.has(resultRootHex)) {
1105
+ this.logger.verbose("Dropping downloaded payload, entry pruned during fetch", logCtx);
1106
+ return;
1107
+ }
1108
+ this.pendingPayloads.set(resultRootHex, pendingPayload);
973
1109
 
974
1110
  if (isPendingPayloadEnvelope(pendingPayload)) {
975
1111
  await this.reconcilePayloadEnvelope(pendingPayload);
@@ -1046,17 +1182,27 @@ export class BlockInputSync {
1046
1182
  break;
1047
1183
 
1048
1184
  case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
1185
+ this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1186
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.elInvalid);
1187
+ break;
1188
+
1049
1189
  case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
1190
+ this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1191
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidEnvelope);
1192
+ break;
1193
+
1050
1194
  case PayloadErrorCode.INVALID_SIGNATURE:
1051
1195
  // TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
1052
1196
  // reintroducing envelope replacement / recreation flows.
1053
1197
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1054
- this.removePendingPayloadAndDescendants(rootHex);
1198
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
1055
1199
  break;
1056
1200
 
1057
1201
  default:
1058
1202
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1059
- this.pendingPayloads.delete(rootHex);
1203
+ if (this.pendingPayloads.delete(rootHex)) {
1204
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.unknown}, 1);
1205
+ }
1060
1206
  }
1061
1207
  return;
1062
1208
  }
@@ -1080,7 +1226,7 @@ export class BlockInputSync {
1080
1226
  let slot = getPayloadSyncCacheItemSlot(cacheItem);
1081
1227
  let payloadInput = isPendingPayloadInput(cacheItem)
1082
1228
  ? cacheItem.payloadInput
1083
- : this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
1229
+ : await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1084
1230
  let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
1085
1231
 
1086
1232
  let i = 0;
@@ -1097,9 +1243,11 @@ export class BlockInputSync {
1097
1243
  );
1098
1244
  }
1099
1245
 
1100
- throw Error(
1101
- `Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
1102
- );
1246
+ const reason =
1247
+ pendingColumns.size > 0
1248
+ ? `cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
1249
+ : "no peer available to download pending payload";
1250
+ throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
1103
1251
  }
1104
1252
 
1105
1253
  const {peerId, client: peerClient} = peerMeta;
@@ -1111,7 +1259,7 @@ export class BlockInputSync {
1111
1259
  slot = envelope.message.payload.slotNumber;
1112
1260
  }
1113
1261
 
1114
- payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
1262
+ payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1115
1263
  if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
1116
1264
  // Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
1117
1265
  // envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
@@ -1444,9 +1592,9 @@ export class BlockInputSync {
1444
1592
  * Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
1445
1593
  * referenced more than one bad block.
1446
1594
  */
1447
- private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem): void {
1595
+ private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
1448
1596
  // Get all blocks that are a descendant of this one
1449
- const badPendingBlocks = this.removeAllDescendants(block);
1597
+ const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
1450
1598
  // just console log and do not penalize on pending/bad blocks for debugging
1451
1599
  // console.log("removeAndDownscoreAllDescendants", {block});
1452
1600
 
@@ -1473,18 +1621,22 @@ export class BlockInputSync {
1473
1621
  }
1474
1622
 
1475
1623
  // Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
1476
- private removePendingPayloadAndDescendants(rootHex: RootHex): void {
1624
+ private removePendingPayloadAndDescendants(rootHex: RootHex, headReason: DroppedItemReason): void {
1477
1625
  // Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
1478
1626
  // later validation/finalization logic decides when it can leave memory.
1479
- this.pendingPayloads.delete(rootHex);
1627
+ if (this.pendingPayloads.delete(rootHex)) {
1628
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: headReason}, 1);
1629
+ }
1480
1630
 
1481
1631
  const badPendingBlocks = getAllDescendantBlocks(rootHex, this.pendingBlocks);
1482
- this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
1483
-
1484
1632
  for (const block of badPendingBlocks) {
1485
1633
  const descendantRootHex = getBlockInputSyncCacheItemRootHex(block);
1486
- this.pendingBlocks.delete(descendantRootHex);
1487
- this.pendingPayloads.delete(descendantRootHex);
1634
+ if (this.pendingBlocks.delete(descendantRootHex)) {
1635
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.invalidParent}, 1);
1636
+ }
1637
+ if (this.pendingPayloads.delete(descendantRootHex)) {
1638
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.invalidParent}, 1);
1639
+ }
1488
1640
  this.chain.seenBlockInputCache.prune(descendantRootHex);
1489
1641
  this.logger.debug("Removing pending descendant after invalid parent payload", {
1490
1642
  slot: getBlockInputSyncCacheItemSlot(block),
@@ -1494,18 +1646,25 @@ export class BlockInputSync {
1494
1646
  }
1495
1647
  }
1496
1648
 
1497
- private removeAllDescendants(block: BlockInputSyncCacheItem): BlockInputSyncCacheItem[] {
1649
+ private removeAllDescendants(
1650
+ block: BlockInputSyncCacheItem,
1651
+ headReason: DroppedItemReason,
1652
+ descendantReason: DroppedItemReason = DroppedItemReason.invalidParent
1653
+ ): BlockInputSyncCacheItem[] {
1498
1654
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1499
1655
  const slot = getBlockInputSyncCacheItemSlot(block);
1500
- // Get all blocks that are a descendant of this one
1656
+ // Get all blocks that are a descendant of this one (index 0 is the head item itself)
1501
1657
  const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
1502
1658
 
1503
- this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
1504
-
1505
- for (const block of badPendingBlocks) {
1659
+ for (const [i, block] of badPendingBlocks.entries()) {
1506
1660
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1507
- this.pendingBlocks.delete(rootHex);
1508
- this.pendingPayloads.delete(rootHex);
1661
+ const reason = i === 0 ? headReason : descendantReason;
1662
+ if (this.pendingBlocks.delete(rootHex)) {
1663
+ this.metrics?.blockInputSync.removedBlocks.inc({reason}, 1);
1664
+ }
1665
+ if (this.pendingPayloads.delete(rootHex)) {
1666
+ this.metrics?.blockInputSync.removedPayloads.inc({reason}, 1);
1667
+ }
1509
1668
  this.chain.seenBlockInputCache.prune(rootHex);
1510
1669
  // Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
1511
1670
  // importBlock()-owned lifecycle.
@@ -136,6 +136,8 @@ export function cacheByRangeResponses({
136
136
  const source = BlockInputSource.byRange;
137
137
  const updatedBatchBlocks = new Map<Slot, IBlockInput>(batchBlocks.map((block) => [block.slot, block]));
138
138
 
139
+ const payloadEnvelopes = new Map<Slot, PayloadEnvelopeInput>(existingPayloadEnvelopes);
140
+
139
141
  const blocks = responses.validatedBlocks ?? [];
140
142
  for (let i = 0; i < blocks.length; i++) {
141
143
  const {block, blockRoot} = blocks[i];
@@ -172,15 +174,17 @@ export function cacheByRangeResponses({
172
174
  // later step) can throw and abort the batch — otherwise a gloas block would sit in
173
175
  // seenBlockInputCache but unseeded here, and payload-by-root sync would later throw "Missing
174
176
  // PayloadEnvelopeInput for known block" (see issue #9306). add() is idempotent.
175
- if (isForkPostGloas(blockInput.forkName)) {
176
- seenPayloadEnvelopeInputCache.add({
177
+ if (isForkPostGloas(blockInput.forkName) && !payloadEnvelopes.has(blockInput.slot)) {
178
+ const payloadInput = seenPayloadEnvelopeInputCache.add({
177
179
  blockRootHex: blockInput.blockRootHex,
178
180
  block: blockInput.getBlock() as SignedBeaconBlock<ForkPostGloas>,
179
181
  forkName: blockInput.forkName,
180
182
  sampledColumns: custodyConfig.sampledColumns,
181
183
  custodyColumns: custodyConfig.custodyColumns,
182
- timeCreatedSec: seenTimestampSec,
184
+ seenTimestampSec,
185
+ source: PayloadEnvelopeInputSource.byRange,
183
186
  });
187
+ payloadEnvelopes.set(blockInput.slot, payloadInput);
184
188
  }
185
189
  }
186
190
 
@@ -222,17 +226,22 @@ export function cacheByRangeResponses({
222
226
  }
223
227
  }
224
228
 
225
- let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null =
226
- existingPayloadEnvelopes !== null ? new Map(existingPayloadEnvelopes) : null;
227
229
  if (downloadedPayloadEnvelopes !== null) {
228
- payloadEnvelopes ??= new Map();
229
230
  for (const [slot, envelope] of downloadedPayloadEnvelopes) {
230
- const envelopeBlockRootHex = toRootHex(envelope.message.beaconBlockRoot);
231
- const payloadInput = seenPayloadEnvelopeInputCache.get(envelopeBlockRootHex);
231
+ // the only PayloadEnvelopeInput miss is the dangling parent, which we can get from the seen cache
232
+ let payloadInput = payloadEnvelopes.get(slot);
232
233
  if (payloadInput === undefined) {
233
- // Unreachable given the validatedBlocks loop above seeded an entry for every gloas block in
234
- // the batch. for the parent block, it's populated at BeaconChain init
235
- throw new Error(`Missing PayloadEnvelopeInput for block ${envelopeBlockRootHex}`);
234
+ if (updatedBatchBlocks.has(slot)) {
235
+ throw new Error(
236
+ `Missing PayloadEnvelopeInput for in-batch slot ${slot} root ${toRootHex(envelope.message.beaconBlockRoot)}`
237
+ );
238
+ }
239
+ payloadInput = seenPayloadEnvelopeInputCache.get(toRootHex(envelope.message.beaconBlockRoot));
240
+ }
241
+ if (payloadInput === undefined) {
242
+ throw new Error(
243
+ `Missing PayloadEnvelopeInput for slot ${slot} root ${toRootHex(envelope.message.beaconBlockRoot)}`
244
+ );
236
245
  }
237
246
 
238
247
  if (!payloadInput.hasPayloadEnvelope()) {
@@ -262,7 +271,7 @@ export function cacheByRangeResponses({
262
271
  // Gloas columns are attached to the matching PayloadEnvelopeInput, NOT to IBlockInput.
263
272
  // Gloas DataColumnSidecar has `slot` directly (no signedBlockHeader).
264
273
  const dataSlot = firstColumn.slot;
265
- const payloadInput = payloadEnvelopes?.get(dataSlot);
274
+ const payloadInput = payloadEnvelopes.get(dataSlot);
266
275
  if (!payloadInput) {
267
276
  // Should not happen: we built payloadInputs for all gloas blocks above
268
277
  continue;
@@ -13,6 +13,7 @@ import {BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu} from "@lod
13
13
  import {LodestarError, byteArrayEquals, fromHex, prettyPrintIndices, toHex, toRootHex} from "@lodestar/utils";
14
14
  import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
15
15
  import {BlockInputSource, IBlockInput} from "../../chain/blocks/blockInput/types.js";
16
+ import {PayloadEnvelopeInputSource} from "../../chain/blocks/payloadEnvelopeInput/index.js";
16
17
  import {ChainEventEmitter} from "../../chain/emitter.js";
17
18
  import {IBeaconChain} from "../../chain/interface.js";
18
19
  import {validateBlockBlobSidecars} from "../../chain/validation/blobSidecar.js";
@@ -122,7 +123,8 @@ export async function downloadByRoot({
122
123
  forkName: blockInput.forkName,
123
124
  sampledColumns: chain.custodyConfig.sampledColumns,
124
125
  custodyColumns: chain.custodyConfig.custodyColumns,
125
- timeCreatedSec: Date.now() / 1000,
126
+ seenTimestampSec: Date.now() / 1000,
127
+ source: PayloadEnvelopeInputSource.byRoot,
126
128
  });
127
129
  }
128
130
 
@@ -1,12 +0,0 @@
1
- import { PublicKey } from "@chainsafe/blst";
2
- export type SignatureSetDeserialized = {
3
- publicKey: PublicKey;
4
- message: Uint8Array;
5
- signature: Uint8Array;
6
- };
7
- /**
8
- * Verify signatures sets with batch verification or regular core verify depending on the set count.
9
- * Abstracted in a separate file to be consumed by the threaded pool and the main thread implementation.
10
- */
11
- export declare function verifySignatureSetsMaybeBatch(sets: SignatureSetDeserialized[]): boolean;
12
- //# sourceMappingURL=maybeBatch.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"maybeBatch.d.ts","sourceRoot":"","sources":["../../../src/chain/bls/maybeBatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAuD,MAAM,iBAAiB,CAAC;AAIhG,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,UAAU,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,wBAAwB,EAAE,GAAG,OAAO,CA8BvF"}