@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,5 +1,5 @@
1
1
  import { routes } from "@lodestar/api";
2
- import { ForkSeq } from "@lodestar/params";
2
+ import { ForkSeq, SLOTS_PER_EPOCH, isForkPostGloas } from "@lodestar/params";
3
3
  import { RequestError, RequestErrorCode } from "@lodestar/reqresp";
4
4
  import { computeTimeAtSlot } from "@lodestar/state-transition";
5
5
  import { fromHex, prettyPrintIndices, pruneSetToMax, sleep, toRootHex } from "@lodestar/utils";
@@ -16,13 +16,17 @@ import { shuffle } from "../util/shuffle.js";
16
16
  import { sortBy } from "../util/sortBy.js";
17
17
  import { wrapError } from "../util/wrapError.js";
18
18
  import { MAX_CONCURRENT_REQUESTS } from "./constants.js";
19
- import { PendingBlockInputStatus, PendingBlockType, PendingPayloadInputStatus, getBlockInputSyncCacheItemRootHex, getBlockInputSyncCacheItemSlot, getPayloadSyncCacheItemRootHex, getPayloadSyncCacheItemSlot, isPendingBlockInput, isPendingPayloadEnvelope, isPendingPayloadInput, } from "./types.js";
19
+ import { DroppedItemReason, PendingBlockInputStatus, PendingBlockType, PendingPayloadInputStatus, getBlockInputSyncCacheItemRootHex, getBlockInputSyncCacheItemSlot, getPayloadSyncCacheItemRootHex, getPayloadSyncCacheItemSlot, isPendingBlockInput, isPendingPayloadEnvelope, isPendingPayloadInput, } from "./types.js";
20
20
  import { DownloadByRootError, downloadByRoot } from "./utils/downloadByRoot.js";
21
21
  import { getAllDescendantBlocks, getUnknownAndAncestorBlocks } from "./utils/pendingBlocksTree.js";
22
22
  import { getRateLimitedUntilMs } from "./utils/rateLimit.js";
23
23
  const MAX_ATTEMPTS_PER_BLOCK = 5;
24
24
  const MAX_KNOWN_BAD_BLOCKS = 500;
25
25
  const MAX_PENDING_BLOCKS = 100;
26
+ /**
27
+ * A pending payload without slot can only stay at most 2 epochs.
28
+ */
29
+ const PRUNE_UNRESOLVED_SLOT_EPOCHS = 2;
26
30
  var FetchResult;
27
31
  (function (FetchResult) {
28
32
  FetchResult["SuccessResolved"] = "success_resolved";
@@ -115,6 +119,7 @@ export class BlockInputSync {
115
119
  this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
116
120
  this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
117
121
  this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
122
+ this.chain.emitter.on(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
118
123
  this.chain.emitter.on(routes.events.EventType.block, this.onBlockImported);
119
124
  this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
120
125
  this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
@@ -130,6 +135,7 @@ export class BlockInputSync {
130
135
  this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
131
136
  this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
132
137
  this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
138
+ this.chain.emitter.off(ChainEvent.forkChoiceFinalized, this.pruneFinalized);
133
139
  this.chain.emitter.off(routes.events.EventType.block, this.onBlockImported);
134
140
  this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
135
141
  this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
@@ -172,7 +178,7 @@ export class BlockInputSync {
172
178
  };
173
179
  onUnknownEnvelopeBlockRoot = (data) => {
174
180
  try {
175
- this.addByPayloadRootHex(data.rootHex, data.peer, data.slot);
181
+ this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
176
182
  this.triggerUnknownBlockSearch();
177
183
  this.metrics?.blockInputSync.requests.inc({ type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT });
178
184
  this.metrics?.blockInputSync.payloadSource.inc({ source: data.source });
@@ -208,12 +214,12 @@ export class BlockInputSync {
208
214
  parentRoot: missingDependency.parentRootHex,
209
215
  parentBlockHash: missingDependency.parentBlockHashHex,
210
216
  });
211
- this.removeAndDownScoreAllDescendants(pendingBlock);
217
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
212
218
  }
213
219
  return;
214
220
  }
215
221
  if (missingDependency.kind === "parentPayload") {
216
- this.addByPayloadRootHex(missingDependency.rootHex, data.peer);
222
+ this.addByPayloadRootHex(missingDependency.rootHex, data.peer, missingDependency.slot);
217
223
  }
218
224
  else if (missingDependency.kind === "parentBlock") {
219
225
  this.addByRootHex(missingDependency.rootHex, data.peer);
@@ -236,6 +242,71 @@ export class BlockInputSync {
236
242
  this.pendingPayloads.delete(blockRoot);
237
243
  this.triggerUnknownBlockSearch();
238
244
  };
245
+ /**
246
+ * Drop pending payloads and blocks that fell below the finalized slot.
247
+ * See https://github.com/ChainSafe/lodestar/issues/9800
248
+ */
249
+ pruneFinalized = (checkpoint) => {
250
+ // Use the actual finalized block slot, not computeStartSlotAtEpoch(checkpoint.epoch)
251
+ // because the payload at the finalized block is not finalized
252
+ const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
253
+ const nowSec = Date.now() / 1000;
254
+ const maxSecInCache = (PRUNE_UNRESOLVED_SLOT_EPOCHS * SLOTS_PER_EPOCH * this.config.SLOT_DURATION_MS) / 1000;
255
+ let belowFinalizedPayloads = 0;
256
+ let agedOutPayloads = 0;
257
+ let unresolvedSlotPayloads = 0;
258
+ for (const [rootHex, payload] of this.pendingPayloads) {
259
+ // Last-effort resolve for a slot-less PendingPayloadRootHex, and store it back for later passes.
260
+ if (!isPendingPayloadInput(payload) && !isPendingPayloadEnvelope(payload) && payload.slot === undefined) {
261
+ payload.slot = this.resolvePayloadSlot(rootHex);
262
+ if (payload.slot === undefined) {
263
+ // Still unresolvable: age it out so the MAX_PENDING_BLOCKS cap cannot stay saturated.
264
+ if (nowSec - payload.timeAddedSec > maxSecInCache) {
265
+ this.pendingPayloads.delete(rootHex);
266
+ agedOutPayloads++;
267
+ }
268
+ else {
269
+ unresolvedSlotPayloads++;
270
+ this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
271
+ root: rootHex,
272
+ finalizedSlot,
273
+ });
274
+ }
275
+ continue;
276
+ }
277
+ }
278
+ const slot = getPayloadSyncCacheItemSlot(payload);
279
+ if (typeof slot === "number" && slot < finalizedSlot) {
280
+ this.pendingPayloads.delete(rootHex);
281
+ belowFinalizedPayloads++;
282
+ }
283
+ }
284
+ let deletedBlocks = 0;
285
+ for (const [rootHex, block] of this.pendingBlocks) {
286
+ const slot = getBlockInputSyncCacheItemSlot(block);
287
+ if (typeof slot === "number" && slot < finalizedSlot) {
288
+ this.pendingBlocks.delete(rootHex);
289
+ deletedBlocks++;
290
+ }
291
+ }
292
+ if (belowFinalizedPayloads > 0) {
293
+ this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.belowFinalized }, belowFinalizedPayloads);
294
+ }
295
+ if (agedOutPayloads > 0) {
296
+ this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.agedOut }, agedOutPayloads);
297
+ }
298
+ if (deletedBlocks > 0) {
299
+ this.metrics?.blockInputSync.removedBlocks.inc({ reason: DroppedItemReason.belowFinalized }, deletedBlocks);
300
+ }
301
+ this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
302
+ finalizedSlot,
303
+ finalizedRoot: checkpoint.rootHex,
304
+ belowFinalizedPayloads,
305
+ agedOutPayloads,
306
+ deletedBlocks,
307
+ unresolvedSlotPayloads,
308
+ });
309
+ };
239
310
  addByRootHex = (rootHex, peerIdStr) => {
240
311
  let pendingBlock = this.pendingBlocks.get(rootHex);
241
312
  let added = false;
@@ -260,6 +331,7 @@ export class BlockInputSync {
260
331
  // Limit pending blocks to prevent DOS attacks that cause OOM
261
332
  const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
262
333
  if (prunedItemCount > 0) {
334
+ this.metrics?.blockInputSync.removedBlocks.inc({ reason: DroppedItemReason.capacity }, prunedItemCount);
263
335
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
264
336
  }
265
337
  return added;
@@ -290,6 +362,7 @@ export class BlockInputSync {
290
362
  // Limit pending blocks to prevent DOS attacks that cause OOM
291
363
  const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
292
364
  if (prunedItemCount > 0) {
365
+ this.metrics?.blockInputSync.removedBlocks.inc({ reason: DroppedItemReason.capacity }, prunedItemCount);
293
366
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
294
367
  }
295
368
  };
@@ -313,15 +386,44 @@ export class BlockInputSync {
313
386
  peerIdStr: peerIdStr ?? "unknown peer",
314
387
  });
315
388
  }
389
+ else if (
390
+ // update a previously slot-less entry once a slot becomes available
391
+ slot !== undefined &&
392
+ !isPendingPayloadInput(pendingPayload) &&
393
+ !isPendingPayloadEnvelope(pendingPayload) &&
394
+ pendingPayload.slot === undefined) {
395
+ pendingPayload.slot = slot;
396
+ }
316
397
  if (peerIdStr) {
317
398
  pendingPayload.peerIdStrings.add(peerIdStr);
318
399
  }
319
400
  const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
320
401
  if (prunedItemCount > 0) {
402
+ this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.capacity }, prunedItemCount);
321
403
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
322
404
  }
323
405
  return added;
324
406
  };
407
+ /**
408
+ * Resolve the block slot for a payload root.
409
+ */
410
+ resolvePayloadSlot(rootHex) {
411
+ // a pending block of the same root
412
+ const pendingBlock = this.pendingBlocks.get(rootHex);
413
+ if (pendingBlock) {
414
+ const pendingBlockSlot = getBlockInputSyncCacheItemSlot(pendingBlock);
415
+ if (typeof pendingBlockSlot === "number") {
416
+ return pendingBlockSlot;
417
+ }
418
+ }
419
+ // the block is in fork choice
420
+ const forkChoiceSlot = this.chain.forkChoice.getBlockHexDefaultStatus(rootHex)?.slot;
421
+ if (forkChoiceSlot !== undefined) {
422
+ return forkChoiceSlot;
423
+ }
424
+ // a seen payload envelope input
425
+ return this.chain.seenPayloadEnvelopeInputCache.get(rootHex)?.slot;
426
+ }
325
427
  addByPayloadInput = (payloadInput, peerIdStr, envelope) => {
326
428
  const pendingPayload = this.toPendingPayloadInput(payloadInput, this.pendingPayloads.get(payloadInput.blockRootHex), envelope);
327
429
  if (peerIdStr) {
@@ -335,6 +437,7 @@ export class BlockInputSync {
335
437
  });
336
438
  const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
337
439
  if (prunedItemCount > 0) {
440
+ this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.capacity }, prunedItemCount);
338
441
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
339
442
  }
340
443
  };
@@ -360,7 +463,8 @@ export class BlockInputSync {
360
463
  */
361
464
  getMissingBlockDependency(blockInput) {
362
465
  const parentRootHex = blockInput.parentRootHex;
363
- if (!this.chain.forkChoice.hasBlockHex(parentRootHex)) {
466
+ const parentBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentRootHex);
467
+ if (!parentBlock) {
364
468
  return { kind: "parentBlock", rootHex: parentRootHex };
365
469
  }
366
470
  if (!blockInput.hasBlock()) {
@@ -377,14 +481,8 @@ export class BlockInputSync {
377
481
  if (this.chain.forkChoice.hasPayloadHexUnsafe(parentRootHex)) {
378
482
  return { kind: "invalidParentPayload", parentRootHex, parentBlockHashHex };
379
483
  }
380
- const parentPayloadInput = this.chain.seenPayloadEnvelopeInputCache.get(parentRootHex);
381
- if (parentPayloadInput) {
382
- if (parentPayloadInput.getBlockHashHex() === parentBlockHashHex) {
383
- return { kind: "parentPayload", rootHex: parentRootHex };
384
- }
385
- return { kind: "invalidParentPayload", parentRootHex, parentBlockHashHex };
386
- }
387
- return { kind: "parentPayload", rootHex: parentRootHex };
484
+ // Parent is in fork choice but its payload `parentBlockHashHex` isn't revealed yet
485
+ return { kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot };
388
486
  }
389
487
  advancePendingBlock(pendingBlock) {
390
488
  const missingDependency = this.getMissingBlockDependency(pendingBlock.blockInput);
@@ -402,9 +500,9 @@ export class BlockInputSync {
402
500
  return added ? "queued_parent_block" : "blocked";
403
501
  }
404
502
  case "parentPayload": {
405
- let added = this.addByPayloadRootHex(missingDependency.rootHex);
503
+ let added = this.addByPayloadRootHex(missingDependency.rootHex, undefined, missingDependency.slot);
406
504
  for (const peerIdStr of pendingBlock.peerIdStrings) {
407
- added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr) || added;
505
+ added = this.addByPayloadRootHex(missingDependency.rootHex, peerIdStr, missingDependency.slot) || added;
408
506
  }
409
507
  return added ? "queued_parent_payload" : "blocked";
410
508
  }
@@ -415,7 +513,7 @@ export class BlockInputSync {
415
513
  parentRoot: missingDependency.parentRootHex,
416
514
  parentBlockHash: missingDependency.parentBlockHashHex,
417
515
  });
418
- this.removeAndDownScoreAllDescendants(pendingBlock);
516
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
419
517
  return "removed";
420
518
  }
421
519
  }
@@ -604,7 +702,7 @@ export class BlockInputSync {
604
702
  ...logCtx2,
605
703
  finalizedSlot,
606
704
  });
607
- this.removeAndDownScoreAllDescendants(block);
705
+ this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
608
706
  }
609
707
  else {
610
708
  this.onUnknownBlockRoot({ rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot });
@@ -622,7 +720,7 @@ export class BlockInputSync {
622
720
  }
623
721
  this.metrics?.blockInputSync.downloadedBlocksError.inc();
624
722
  this.logger.debug("Ignoring unknown block root after many failed downloads", logCtx, res.err);
625
- this.removeAndDownScoreAllDescendants(block);
723
+ this.removeAndDownScoreAllDescendants(block, DroppedItemReason.unavailable);
626
724
  }
627
725
  }
628
726
  /**
@@ -637,9 +735,10 @@ export class BlockInputSync {
637
735
  // this prevents unbundling attack
638
736
  // see https://lighthouse-blog.sigmaprime.io/mev-unbundling-rpc.html
639
737
  const { slot: blockSlot, proposerIndex } = pendingBlock.blockInput.getBlock().message;
738
+ const blockRootHex = pendingBlock.blockInput.blockRootHex;
640
739
  const logCtx = {
641
740
  slot: blockSlot,
642
- root: pendingBlock.blockInput.blockRootHex,
741
+ root: blockRootHex,
643
742
  delaySec: this.chain.clock.secFromSlot(blockSlot),
644
743
  };
645
744
  this.logger.verbose("Processing downloaded block", logCtx);
@@ -651,7 +750,7 @@ export class BlockInputSync {
651
750
  // eligible for proposer boost to prevent unbundling attack
652
751
  this.logger.verbose("Avoid proposer boost for this block of known proposer", {
653
752
  slot: blockSlot,
654
- root: pendingBlock.blockInput.blockRootHex,
753
+ root: blockRootHex,
655
754
  proposerIndex,
656
755
  });
657
756
  await sleep(proposerBoostWindowMs);
@@ -676,13 +775,24 @@ export class BlockInputSync {
676
775
  if (!res.err) {
677
776
  this.logger.verbose("Processed block from unknown sync", logCtx);
678
777
  // no need to update status to "processed", delete anyway
679
- this.pendingBlocks.delete(pendingBlock.blockInput.blockRootHex);
778
+ this.pendingBlocks.delete(blockRootHex);
779
+ if (isForkPostGloas(fork)) {
780
+ const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
781
+ if (!payloadInput) {
782
+ this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
783
+ }
784
+ else {
785
+ // Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
786
+ // The bid already carries the kzg commitments, so there is no reason to wait for the payload to arrive.
787
+ this.chain.getBlobsTracker.triggerGetBlobs(payloadInput);
788
+ }
789
+ }
680
790
  // Re-enter the scheduler so descendants blocked on either parent blocks or parent payloads
681
791
  // are advanced through the same dependency checks as every other pending item.
682
792
  this.triggerUnknownBlockSearch();
683
793
  }
684
794
  else {
685
- const errorData = { slot: pendingBlock.blockInput.slot, root: pendingBlock.blockInput.blockRootHex };
795
+ const errorData = { slot: pendingBlock.blockInput.slot, root: blockRootHex };
686
796
  if (res.err instanceof BlockError) {
687
797
  switch (res.err.type.code) {
688
798
  // This cases are already handled with `{ignoreIfKnown: true}`
@@ -705,17 +815,17 @@ export class BlockInputSync {
705
815
  case BlockErrorCode.EXECUTION_ENGINE_ERROR:
706
816
  // Removing the block(s) without penalizing the peers, hoping for EL to
707
817
  // recover on a latter download + verify attempt.
708
- this.removeAllDescendants(pendingBlock);
818
+ this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
709
819
  break;
710
820
  case BlockErrorCode.EXECUTION_ENGINE_INVALID:
711
821
  // the peer served a bad block
712
822
  this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
713
- this.removeAndDownScoreAllDescendants(pendingBlock);
823
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
714
824
  break;
715
825
  default:
716
826
  // Block is not correct with respect to our chain. Log error loudly
717
827
  this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
718
- this.removeAndDownScoreAllDescendants(pendingBlock);
828
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
719
829
  }
720
830
  }
721
831
  // Probably a queue error or something unwanted happened, mark as pending to try again latter
@@ -736,7 +846,6 @@ export class BlockInputSync {
736
846
  this.pendingPayloads.delete(rootHex);
737
847
  return;
738
848
  }
739
- const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
740
849
  if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
741
850
  // Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
742
851
  // non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
@@ -750,8 +859,9 @@ export class BlockInputSync {
750
859
  }
751
860
  return;
752
861
  }
862
+ const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
753
863
  if (!payloadInput) {
754
- this.logger.debug("Missing PayloadEnvelopeInput for known block while reconciling payload envelope", {
864
+ this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
755
865
  root: rootHex,
756
866
  });
757
867
  return;
@@ -763,6 +873,7 @@ export class BlockInputSync {
763
873
  const pendingPayloadByRoot = {
764
874
  status: PendingPayloadInputStatus.pending,
765
875
  rootHex,
876
+ slot: pendingPayload.envelope.message.payload.slotNumber,
766
877
  timeAddedSec: pendingPayload.timeAddedSec,
767
878
  peerIdStrings: new Set(pendingPayload.peerIdStrings),
768
879
  };
@@ -794,6 +905,9 @@ export class BlockInputSync {
794
905
  if (payload.status !== PendingPayloadInputStatus.pending) {
795
906
  return;
796
907
  }
908
+ if (!isPendingPayloadInput(payload) && payload.slot === undefined) {
909
+ payload.slot = this.resolvePayloadSlot(rootHex);
910
+ }
797
911
  const payloadSlot = getPayloadSyncCacheItemSlot(payload);
798
912
  const logCtx = {
799
913
  slot: payloadSlot,
@@ -806,7 +920,13 @@ export class BlockInputSync {
806
920
  const res = await wrapError(this.fetchPayloadInput(payload));
807
921
  if (!res.err) {
808
922
  const pendingPayload = res.result;
809
- this.pendingPayloads.set(getPayloadSyncCacheItemRootHex(pendingPayload), pendingPayload);
923
+ const resultRootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
924
+ // finalization may have deleted this entry while we were awaiting the network, do not resurrect it via the set below
925
+ if (!this.pendingPayloads.has(resultRootHex)) {
926
+ this.logger.verbose("Dropping downloaded payload, entry pruned during fetch", logCtx);
927
+ return;
928
+ }
929
+ this.pendingPayloads.set(resultRootHex, pendingPayload);
810
930
  if (isPendingPayloadEnvelope(pendingPayload)) {
811
931
  await this.reconcilePayloadEnvelope(pendingPayload);
812
932
  }
@@ -873,16 +993,24 @@ export class BlockInputSync {
873
993
  pendingPayload.status = PendingPayloadInputStatus.downloaded;
874
994
  break;
875
995
  case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
996
+ this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
997
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.elInvalid);
998
+ break;
876
999
  case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
1000
+ this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1001
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidEnvelope);
1002
+ break;
877
1003
  case PayloadErrorCode.INVALID_SIGNATURE:
878
1004
  // TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
879
1005
  // reintroducing envelope replacement / recreation flows.
880
1006
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
881
- this.removePendingPayloadAndDescendants(rootHex);
1007
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
882
1008
  break;
883
1009
  default:
884
1010
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
885
- this.pendingPayloads.delete(rootHex);
1011
+ if (this.pendingPayloads.delete(rootHex)) {
1012
+ this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.unknown }, 1);
1013
+ }
886
1014
  }
887
1015
  return;
888
1016
  }
@@ -901,7 +1029,7 @@ export class BlockInputSync {
901
1029
  let slot = getPayloadSyncCacheItemSlot(cacheItem);
902
1030
  let payloadInput = isPendingPayloadInput(cacheItem)
903
1031
  ? cacheItem.payloadInput
904
- : this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
1032
+ : await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
905
1033
  let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
906
1034
  let i = 0;
907
1035
  let deferredByRateLimit = false;
@@ -914,7 +1042,10 @@ export class BlockInputSync {
914
1042
  if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
915
1043
  throw new UnknownBlockRateLimitedError(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: peers with needed columns are rate-limited`);
916
1044
  }
917
- throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`);
1045
+ const reason = pendingColumns.size > 0
1046
+ ? `cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
1047
+ : "no peer available to download pending payload";
1048
+ throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
918
1049
  }
919
1050
  const { peerId, client: peerClient } = peerMeta;
920
1051
  cacheItem.peerIdStrings.add(peerId);
@@ -923,7 +1054,7 @@ export class BlockInputSync {
923
1054
  envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
924
1055
  slot = envelope.message.payload.slotNumber;
925
1056
  }
926
- payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
1057
+ payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
927
1058
  if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
928
1059
  // Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
929
1060
  // envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
@@ -1194,9 +1325,9 @@ export class BlockInputSync {
1194
1325
  * Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
1195
1326
  * referenced more than one bad block.
1196
1327
  */
1197
- removeAndDownScoreAllDescendants(block) {
1328
+ removeAndDownScoreAllDescendants(block, headReason) {
1198
1329
  // Get all blocks that are a descendant of this one
1199
- const badPendingBlocks = this.removeAllDescendants(block);
1330
+ const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
1200
1331
  // just console log and do not penalize on pending/bad blocks for debugging
1201
1332
  // console.log("removeAndDownscoreAllDescendants", {block});
1202
1333
  for (const block of badPendingBlocks) {
@@ -1220,16 +1351,21 @@ export class BlockInputSync {
1220
1351
  pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
1221
1352
  }
1222
1353
  // Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
1223
- removePendingPayloadAndDescendants(rootHex) {
1354
+ removePendingPayloadAndDescendants(rootHex, headReason) {
1224
1355
  // Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
1225
1356
  // later validation/finalization logic decides when it can leave memory.
1226
- this.pendingPayloads.delete(rootHex);
1357
+ if (this.pendingPayloads.delete(rootHex)) {
1358
+ this.metrics?.blockInputSync.removedPayloads.inc({ reason: headReason }, 1);
1359
+ }
1227
1360
  const badPendingBlocks = getAllDescendantBlocks(rootHex, this.pendingBlocks);
1228
- this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
1229
1361
  for (const block of badPendingBlocks) {
1230
1362
  const descendantRootHex = getBlockInputSyncCacheItemRootHex(block);
1231
- this.pendingBlocks.delete(descendantRootHex);
1232
- this.pendingPayloads.delete(descendantRootHex);
1363
+ if (this.pendingBlocks.delete(descendantRootHex)) {
1364
+ this.metrics?.blockInputSync.removedBlocks.inc({ reason: DroppedItemReason.invalidParent }, 1);
1365
+ }
1366
+ if (this.pendingPayloads.delete(descendantRootHex)) {
1367
+ this.metrics?.blockInputSync.removedPayloads.inc({ reason: DroppedItemReason.invalidParent }, 1);
1368
+ }
1233
1369
  this.chain.seenBlockInputCache.prune(descendantRootHex);
1234
1370
  this.logger.debug("Removing pending descendant after invalid parent payload", {
1235
1371
  slot: getBlockInputSyncCacheItemSlot(block),
@@ -1238,16 +1374,20 @@ export class BlockInputSync {
1238
1374
  });
1239
1375
  }
1240
1376
  }
1241
- removeAllDescendants(block) {
1377
+ removeAllDescendants(block, headReason, descendantReason = DroppedItemReason.invalidParent) {
1242
1378
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1243
1379
  const slot = getBlockInputSyncCacheItemSlot(block);
1244
- // Get all blocks that are a descendant of this one
1380
+ // Get all blocks that are a descendant of this one (index 0 is the head item itself)
1245
1381
  const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
1246
- this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
1247
- for (const block of badPendingBlocks) {
1382
+ for (const [i, block] of badPendingBlocks.entries()) {
1248
1383
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1249
- this.pendingBlocks.delete(rootHex);
1250
- this.pendingPayloads.delete(rootHex);
1384
+ const reason = i === 0 ? headReason : descendantReason;
1385
+ if (this.pendingBlocks.delete(rootHex)) {
1386
+ this.metrics?.blockInputSync.removedBlocks.inc({ reason }, 1);
1387
+ }
1388
+ if (this.pendingPayloads.delete(rootHex)) {
1389
+ this.metrics?.blockInputSync.removedPayloads.inc({ reason }, 1);
1390
+ }
1251
1391
  this.chain.seenBlockInputCache.prune(rootHex);
1252
1392
  // Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
1253
1393
  // importBlock()-owned lifecycle.