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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +44 -12
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +21 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +2 -1
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  10. package/lib/api/impl/events/index.d.ts.map +1 -1
  11. package/lib/api/impl/events/index.js +2 -0
  12. package/lib/api/impl/events/index.js.map +1 -1
  13. package/lib/api/impl/lodestar/index.js +1 -1
  14. package/lib/api/impl/lodestar/index.js.map +1 -1
  15. package/lib/api/impl/validator/index.d.ts.map +1 -1
  16. package/lib/api/impl/validator/index.js +237 -49
  17. package/lib/api/impl/validator/index.js.map +1 -1
  18. package/lib/api/impl/validator/utils.js +1 -1
  19. package/lib/api/impl/validator/utils.js.map +1 -1
  20. package/lib/api/rest/base.d.ts.map +1 -1
  21. package/lib/api/rest/base.js +7 -0
  22. package/lib/api/rest/base.js.map +1 -1
  23. package/lib/chain/archiveStore/archiveStore.js +1 -1
  24. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  25. package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
  26. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  27. package/lib/chain/blocks/importExecutionPayload.js +11 -9
  28. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  29. package/lib/chain/blocks/index.d.ts.map +1 -1
  30. package/lib/chain/blocks/index.js +21 -13
  31. package/lib/chain/blocks/index.js.map +1 -1
  32. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
  33. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  34. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
  35. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  36. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
  37. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  38. package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
  39. package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -1
  40. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  41. package/lib/chain/blocks/verifyBlock.js +5 -2
  42. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  43. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  44. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
  45. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  46. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  47. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  48. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  49. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  50. package/lib/chain/bls/index.d.ts +1 -1
  51. package/lib/chain/bls/index.d.ts.map +1 -1
  52. package/lib/chain/bls/interface.d.ts +5 -5
  53. package/lib/chain/bls/interface.d.ts.map +1 -1
  54. package/lib/chain/bls/multithread/index.d.ts +5 -11
  55. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  56. package/lib/chain/bls/multithread/index.js +116 -101
  57. package/lib/chain/bls/multithread/index.js.map +1 -1
  58. package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
  59. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  60. package/lib/chain/bls/multithread/jobItem.js +10 -65
  61. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  62. package/lib/chain/bls/multithread/types.d.ts +29 -8
  63. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  64. package/lib/chain/bls/multithread/types.js +12 -0
  65. package/lib/chain/bls/multithread/types.js.map +1 -1
  66. package/lib/chain/bls/multithread/utils.d.ts +4 -0
  67. package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
  68. package/lib/chain/bls/multithread/utils.js +10 -0
  69. package/lib/chain/bls/multithread/utils.js.map +1 -1
  70. package/lib/chain/bls/multithread/worker.js +49 -23
  71. package/lib/chain/bls/multithread/worker.js.map +1 -1
  72. package/lib/chain/bls/singleThread.d.ts +4 -10
  73. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  74. package/lib/chain/bls/singleThread.js +8 -45
  75. package/lib/chain/bls/singleThread.js.map +1 -1
  76. package/lib/chain/bls/utils.d.ts +4 -4
  77. package/lib/chain/bls/utils.d.ts.map +1 -1
  78. package/lib/chain/bls/utils.js +18 -19
  79. package/lib/chain/bls/utils.js.map +1 -1
  80. package/lib/chain/chain.d.ts +9 -4
  81. package/lib/chain/chain.d.ts.map +1 -1
  82. package/lib/chain/chain.js +22 -8
  83. package/lib/chain/chain.js.map +1 -1
  84. package/lib/chain/errors/blockError.d.ts +1 -0
  85. package/lib/chain/errors/blockError.d.ts.map +1 -1
  86. package/lib/chain/errors/blockError.js +6 -1
  87. package/lib/chain/errors/blockError.js.map +1 -1
  88. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  89. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  90. package/lib/chain/errors/executionPayloadBid.js +1 -0
  91. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  92. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  93. package/lib/chain/forkChoice/index.js +4 -0
  94. package/lib/chain/forkChoice/index.js.map +1 -1
  95. package/lib/chain/interface.d.ts +8 -4
  96. package/lib/chain/interface.d.ts.map +1 -1
  97. package/lib/chain/interface.js.map +1 -1
  98. package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
  99. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  100. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  101. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  102. package/lib/chain/opPools/attestationPool.js +1 -1
  103. package/lib/chain/opPools/attestationPool.js.map +1 -1
  104. package/lib/chain/opPools/deferredVoluntaryExitPool.d.ts +16 -0
  105. package/lib/chain/opPools/deferredVoluntaryExitPool.d.ts.map +1 -0
  106. package/lib/chain/opPools/deferredVoluntaryExitPool.js +57 -0
  107. package/lib/chain/opPools/deferredVoluntaryExitPool.js.map +1 -0
  108. package/lib/chain/opPools/executionPayloadBidPool.d.ts +7 -2
  109. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
  110. package/lib/chain/opPools/executionPayloadBidPool.js +4 -4
  111. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
  112. package/lib/chain/opPools/index.d.ts +2 -1
  113. package/lib/chain/opPools/index.d.ts.map +1 -1
  114. package/lib/chain/opPools/index.js +1 -0
  115. package/lib/chain/opPools/index.js.map +1 -1
  116. package/lib/chain/opPools/payloadAttestationPool.js +3 -3
  117. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  118. package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
  119. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  120. package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
  121. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  122. package/lib/chain/opPools/utils.d.ts +1 -1
  123. package/lib/chain/opPools/utils.d.ts.map +1 -1
  124. package/lib/chain/opPools/utils.js +1 -1
  125. package/lib/chain/opPools/utils.js.map +1 -1
  126. package/lib/chain/prepareNextSlot.d.ts +5 -0
  127. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  128. package/lib/chain/prepareNextSlot.js +47 -6
  129. package/lib/chain/prepareNextSlot.js.map +1 -1
  130. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  131. package/lib/chain/produceBlock/computeNewStateRoot.js +3 -25
  132. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  133. package/lib/chain/produceBlock/produceBlockBody.js +1 -1
  134. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  135. package/lib/chain/regen/interface.d.ts +5 -2
  136. package/lib/chain/regen/interface.d.ts.map +1 -1
  137. package/lib/chain/regen/interface.js +3 -0
  138. package/lib/chain/regen/interface.js.map +1 -1
  139. package/lib/chain/regen/queued.d.ts +2 -2
  140. package/lib/chain/regen/queued.d.ts.map +1 -1
  141. package/lib/chain/regen/queued.js +5 -5
  142. package/lib/chain/regen/queued.js.map +1 -1
  143. package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
  144. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  145. package/lib/chain/seenCache/seenAttesters.js +25 -4
  146. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  147. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +28 -1
  148. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  149. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
  150. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  151. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +5 -1
  152. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  153. package/lib/chain/stateCache/fifoBlockStateCache.js +6 -0
  154. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  155. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +47 -5
  156. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  157. package/lib/chain/stateCache/persistentCheckpointsCache.js +117 -7
  158. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  159. package/lib/chain/stateCache/types.d.ts +3 -3
  160. package/lib/chain/stateCache/types.d.ts.map +1 -1
  161. package/lib/chain/validation/attestation.d.ts.map +1 -1
  162. package/lib/chain/validation/attestation.js +1 -4
  163. package/lib/chain/validation/attestation.js.map +1 -1
  164. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  165. package/lib/chain/validation/attesterSlashing.js +1 -1
  166. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  167. package/lib/chain/validation/block.d.ts.map +1 -1
  168. package/lib/chain/validation/block.js +40 -10
  169. package/lib/chain/validation/block.js.map +1 -1
  170. package/lib/chain/validation/executionPayloadBid.d.ts +15 -3
  171. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  172. package/lib/chain/validation/executionPayloadBid.js +166 -12
  173. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  174. package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
  175. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  176. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  177. package/lib/chain/validation/payloadAttestationMessage.js +5 -14
  178. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  179. package/lib/chain/validation/proposerPreferences.js +2 -2
  180. package/lib/chain/validation/proposerPreferences.js.map +1 -1
  181. package/lib/chain/validation/proposerSlashing.js +1 -1
  182. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  183. package/lib/chain/validation/voluntaryExit.d.ts +9 -1
  184. package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
  185. package/lib/chain/validation/voluntaryExit.js +46 -1
  186. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  187. package/lib/execution/builder/apiClient.d.ts +70 -0
  188. package/lib/execution/builder/apiClient.d.ts.map +1 -0
  189. package/lib/execution/builder/apiClient.js +202 -0
  190. package/lib/execution/builder/apiClient.js.map +1 -0
  191. package/lib/execution/builder/validateBid.d.ts +23 -0
  192. package/lib/execution/builder/validateBid.d.ts.map +1 -0
  193. package/lib/execution/builder/validateBid.js +119 -0
  194. package/lib/execution/builder/validateBid.js.map +1 -0
  195. package/lib/metrics/metrics/lodestar.d.ts +84 -23
  196. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  197. package/lib/metrics/metrics/lodestar.js +161 -55
  198. package/lib/metrics/metrics/lodestar.js.map +1 -1
  199. package/lib/network/gossip/topic.d.ts +13 -0
  200. package/lib/network/gossip/topic.d.ts.map +1 -1
  201. package/lib/network/gossip/topic.js +37 -0
  202. package/lib/network/gossip/topic.js.map +1 -1
  203. package/lib/network/network.d.ts.map +1 -1
  204. package/lib/network/network.js +23 -43
  205. package/lib/network/network.js.map +1 -1
  206. package/lib/network/processor/constants.d.ts +7 -0
  207. package/lib/network/processor/constants.d.ts.map +1 -0
  208. package/lib/network/processor/constants.js +7 -0
  209. package/lib/network/processor/constants.js.map +1 -0
  210. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  211. package/lib/network/processor/gossipHandlers.js +6 -2
  212. package/lib/network/processor/gossipHandlers.js.map +1 -1
  213. package/lib/network/processor/gossipQueues/indexed.d.ts.map +1 -1
  214. package/lib/network/processor/gossipQueues/indexed.js +0 -1
  215. package/lib/network/processor/gossipQueues/indexed.js.map +1 -1
  216. package/lib/network/processor/index.d.ts +3 -0
  217. package/lib/network/processor/index.d.ts.map +1 -1
  218. package/lib/network/processor/index.js +52 -23
  219. package/lib/network/processor/index.js.map +1 -1
  220. package/lib/network/reqresp/score.d.ts.map +1 -1
  221. package/lib/network/reqresp/score.js +5 -11
  222. package/lib/network/reqresp/score.js.map +1 -1
  223. package/lib/network/util.d.ts +0 -1
  224. package/lib/network/util.d.ts.map +1 -1
  225. package/lib/network/util.js +0 -4
  226. package/lib/network/util.js.map +1 -1
  227. package/lib/node/deferredVoluntaryExitPublisher.d.ts +15 -0
  228. package/lib/node/deferredVoluntaryExitPublisher.d.ts.map +1 -0
  229. package/lib/node/deferredVoluntaryExitPublisher.js +38 -0
  230. package/lib/node/deferredVoluntaryExitPublisher.js.map +1 -0
  231. package/lib/node/nodejs.d.ts +2 -1
  232. package/lib/node/nodejs.d.ts.map +1 -1
  233. package/lib/node/nodejs.js +7 -0
  234. package/lib/node/nodejs.js.map +1 -1
  235. package/lib/sync/range/batch.d.ts +23 -5
  236. package/lib/sync/range/batch.d.ts.map +1 -1
  237. package/lib/sync/range/batch.js +61 -22
  238. package/lib/sync/range/batch.js.map +1 -1
  239. package/lib/sync/range/chain.d.ts +2 -1
  240. package/lib/sync/range/chain.d.ts.map +1 -1
  241. package/lib/sync/range/chain.js +32 -12
  242. package/lib/sync/range/chain.js.map +1 -1
  243. package/lib/sync/range/range.js +1 -1
  244. package/lib/sync/range/range.js.map +1 -1
  245. package/lib/sync/types.d.ts +32 -0
  246. package/lib/sync/types.d.ts.map +1 -1
  247. package/lib/sync/types.js +33 -0
  248. package/lib/sync/types.js.map +1 -1
  249. package/lib/sync/unknownBlock.d.ts +6 -2
  250. package/lib/sync/unknownBlock.d.ts.map +1 -1
  251. package/lib/sync/unknownBlock.js +143 -68
  252. package/lib/sync/unknownBlock.js.map +1 -1
  253. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  254. package/lib/sync/utils/downloadByRange.js +16 -11
  255. package/lib/sync/utils/downloadByRange.js.map +1 -1
  256. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  257. package/lib/sync/utils/downloadByRoot.js +3 -1
  258. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  259. package/package.json +35 -35
  260. package/src/api/impl/beacon/blocks/index.ts +51 -15
  261. package/src/api/impl/beacon/pool/index.ts +22 -2
  262. package/src/api/impl/beacon/state/utils.ts +2 -1
  263. package/src/api/impl/events/index.ts +3 -1
  264. package/src/api/impl/lodestar/index.ts +1 -1
  265. package/src/api/impl/validator/index.ts +290 -49
  266. package/src/api/impl/validator/utils.ts +1 -1
  267. package/src/api/rest/base.ts +7 -0
  268. package/src/chain/archiveStore/archiveStore.ts +1 -1
  269. package/src/chain/blocks/importExecutionPayload.ts +12 -11
  270. package/src/chain/blocks/index.ts +25 -13
  271. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
  272. package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
  273. package/src/chain/blocks/verifyBlock.ts +5 -2
  274. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
  275. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
  276. package/src/chain/bls/index.ts +1 -1
  277. package/src/chain/bls/interface.ts +7 -3
  278. package/src/chain/bls/multithread/index.ts +148 -120
  279. package/src/chain/bls/multithread/jobItem.ts +12 -82
  280. package/src/chain/bls/multithread/types.ts +33 -8
  281. package/src/chain/bls/multithread/utils.ts +11 -0
  282. package/src/chain/bls/multithread/worker.ts +85 -27
  283. package/src/chain/bls/singleThread.ts +11 -55
  284. package/src/chain/bls/utils.ts +23 -24
  285. package/src/chain/chain.ts +25 -7
  286. package/src/chain/errors/blockError.ts +8 -2
  287. package/src/chain/errors/executionPayloadBid.ts +6 -0
  288. package/src/chain/forkChoice/index.ts +4 -0
  289. package/src/chain/interface.ts +8 -3
  290. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  291. package/src/chain/opPools/attestationPool.ts +1 -1
  292. package/src/chain/opPools/deferredVoluntaryExitPool.ts +65 -0
  293. package/src/chain/opPools/executionPayloadBidPool.ts +13 -7
  294. package/src/chain/opPools/index.ts +2 -1
  295. package/src/chain/opPools/payloadAttestationPool.ts +3 -3
  296. package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
  297. package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
  298. package/src/chain/opPools/utils.ts +1 -1
  299. package/src/chain/prepareNextSlot.ts +49 -6
  300. package/src/chain/produceBlock/computeNewStateRoot.ts +3 -38
  301. package/src/chain/produceBlock/produceBlockBody.ts +1 -1
  302. package/src/chain/regen/interface.ts +5 -2
  303. package/src/chain/regen/queued.ts +5 -5
  304. package/src/chain/seenCache/seenAttesters.ts +31 -5
  305. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
  306. package/src/chain/stateCache/fifoBlockStateCache.ts +8 -1
  307. package/src/chain/stateCache/persistentCheckpointsCache.ts +133 -8
  308. package/src/chain/stateCache/types.ts +3 -3
  309. package/src/chain/validation/attestation.ts +1 -7
  310. package/src/chain/validation/attesterSlashing.ts +1 -8
  311. package/src/chain/validation/block.ts +43 -10
  312. package/src/chain/validation/executionPayloadBid.ts +193 -14
  313. package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
  314. package/src/chain/validation/payloadAttestationMessage.ts +6 -17
  315. package/src/chain/validation/proposerPreferences.ts +3 -3
  316. package/src/chain/validation/proposerSlashing.ts +1 -1
  317. package/src/chain/validation/voluntaryExit.ts +59 -2
  318. package/src/execution/builder/apiClient.ts +264 -0
  319. package/src/execution/builder/validateBid.ts +181 -0
  320. package/src/metrics/metrics/lodestar.ts +176 -61
  321. package/src/network/gossip/topic.ts +38 -0
  322. package/src/network/network.ts +29 -54
  323. package/src/network/processor/constants.ts +6 -0
  324. package/src/network/processor/gossipHandlers.ts +6 -2
  325. package/src/network/processor/gossipQueues/indexed.ts +0 -1
  326. package/src/network/processor/index.ts +67 -30
  327. package/src/network/reqresp/score.ts +5 -11
  328. package/src/network/util.ts +0 -5
  329. package/src/node/deferredVoluntaryExitPublisher.ts +54 -0
  330. package/src/node/nodejs.ts +10 -1
  331. package/src/sync/range/batch.ts +83 -28
  332. package/src/sync/range/chain.ts +35 -13
  333. package/src/sync/range/range.ts +1 -1
  334. package/src/sync/types.ts +33 -0
  335. package/src/sync/unknownBlock.ts +167 -73
  336. package/src/sync/utils/downloadByRange.ts +21 -12
  337. package/src/sync/utils/downloadByRoot.ts +3 -1
  338. package/lib/chain/bls/maybeBatch.d.ts +0 -12
  339. package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
  340. package/lib/chain/bls/maybeBatch.js +0 -35
  341. package/lib/chain/bls/maybeBatch.js.map +0 -1
  342. package/src/chain/bls/maybeBatch.ts +0 -45
@@ -1,7 +1,7 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {ChainForkConfig} from "@lodestar/config";
3
3
  import {CheckpointWithHex} from "@lodestar/fork-choice";
4
- import {ForkSeq, isForkPostGloas} from "@lodestar/params";
4
+ import {ForkSeq, SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
5
5
  import {RequestError, RequestErrorCode} from "@lodestar/reqresp";
6
6
  import {computeTimeAtSlot} from "@lodestar/state-transition";
7
7
  import {RootHex, Slot, gloas} from "@lodestar/types";
@@ -17,6 +17,7 @@ import {validateGossipExecutionPayloadEnvelope} from "../chain/validation/execut
17
17
  import {Metrics} from "../metrics/index.js";
18
18
  import {INetwork, NetworkEvent, NetworkEventData, prettyPrintPeerIdStr} from "../network/index.js";
19
19
  import {PeerSyncMeta} from "../network/peers/peersData.js";
20
+ import {MAX_PEERS_PER_ROOT} from "../network/processor/constants.js";
20
21
  import {PeerIdStr} from "../util/peerId.js";
21
22
  import {shuffle} from "../util/shuffle.js";
22
23
  import {sortBy} from "../util/sortBy.js";
@@ -25,6 +26,7 @@ import {MAX_CONCURRENT_REQUESTS} from "./constants.js";
25
26
  import {SyncOptions} from "./options.js";
26
27
  import {
27
28
  BlockInputSyncCacheItem,
29
+ DroppedItemReason,
28
30
  PayloadSyncCacheItem,
29
31
  PendingBlockInput,
30
32
  PendingBlockInputStatus,
@@ -48,6 +50,10 @@ import {getRateLimitedUntilMs} from "./utils/rateLimit.js";
48
50
  const MAX_ATTEMPTS_PER_BLOCK = 5;
49
51
  const MAX_KNOWN_BAD_BLOCKS = 500;
50
52
  const MAX_PENDING_BLOCKS = 100;
53
+ /**
54
+ * A pending payload without slot can only stay at most 2 epochs.
55
+ */
56
+ const PRUNE_UNRESOLVED_SLOT_EPOCHS = 2;
51
57
 
52
58
  type AdvancePendingBlockResult =
53
59
  | "ready"
@@ -160,6 +166,16 @@ export class BlockInputSync {
160
166
  this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
161
167
  this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
162
168
  this.network.events.on(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
169
+
170
+ // Seed the balancer with peers that connected before we subscribed
171
+ for (const peerId of this.network.getConnectedPeers()) {
172
+ try {
173
+ this.peerBalancer.onPeerConnected(peerId, this.network.getConnectedPeerSyncMeta(peerId));
174
+ } catch (e) {
175
+ this.logger.debug("Failed to seed connected peer into BlockInputSync balancer", {peerId}, e as Error);
176
+ }
177
+ }
178
+
163
179
  this.subscribedToNetworkEvents = true;
164
180
  }
165
181
  }
@@ -177,6 +193,7 @@ export class BlockInputSync {
177
193
  this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
178
194
  this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
179
195
  this.network.events.off(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
196
+ this.peerBalancer.clear();
180
197
  this.subscribedToNetworkEvents = false;
181
198
  }
182
199
 
@@ -193,10 +210,12 @@ export class BlockInputSync {
193
210
  */
194
211
  private onUnknownBlockRoot = (data: ChainEventData[ChainEvent.unknownBlockRoot]): void => {
195
212
  try {
196
- this.addByRootHex(data.rootHex, data.peer);
197
- this.triggerUnknownBlockSearch();
198
- this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_BLOCK_ROOT});
199
- this.metrics?.blockInputSync.source.inc({source: data.source});
213
+ const isNewRoot = this.addByRootHex(data.rootHex, data.peer);
214
+ if (isNewRoot) {
215
+ this.triggerUnknownBlockSearch();
216
+ this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_BLOCK_ROOT});
217
+ this.metrics?.blockInputSync.source.inc({source: data.source});
218
+ }
200
219
  } catch (e) {
201
220
  this.logger.debug("Error handling unknownBlockRoot event", {}, e as Error);
202
221
  }
@@ -218,10 +237,12 @@ export class BlockInputSync {
218
237
 
219
238
  private onUnknownEnvelopeBlockRoot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]): void => {
220
239
  try {
221
- this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
222
- this.triggerUnknownBlockSearch();
223
- this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT});
224
- this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
240
+ const isNewRoot = this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
241
+ if (isNewRoot) {
242
+ this.triggerUnknownBlockSearch();
243
+ this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT});
244
+ this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
245
+ }
225
246
  } catch (e) {
226
247
  this.logger.debug("Error handling unknownEnvelopeBlockRoot event", {}, e as Error);
227
248
  }
@@ -255,7 +276,7 @@ export class BlockInputSync {
255
276
  parentRoot: missingDependency.parentRootHex,
256
277
  parentBlockHash: missingDependency.parentBlockHashHex,
257
278
  });
258
- this.removeAndDownScoreAllDescendants(pendingBlock);
279
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
259
280
  }
260
281
  return;
261
282
  }
@@ -295,28 +316,37 @@ export class BlockInputSync {
295
316
  // Use the actual finalized block slot, not computeStartSlotAtEpoch(checkpoint.epoch)
296
317
  // because the payload at the finalized block is not finalized
297
318
  const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
319
+ const nowSec = Date.now() / 1000;
320
+ const maxSecInCache = (PRUNE_UNRESOLVED_SLOT_EPOCHS * SLOTS_PER_EPOCH * this.config.SLOT_DURATION_MS) / 1000;
298
321
 
299
- let deletedPayloads = 0;
322
+ let belowFinalizedPayloads = 0;
323
+ let agedOutPayloads = 0;
300
324
  let unresolvedSlotPayloads = 0;
325
+
301
326
  for (const [rootHex, payload] of this.pendingPayloads) {
302
327
  // Last-effort resolve for a slot-less PendingPayloadRootHex, and store it back for later passes.
303
328
  if (!isPendingPayloadInput(payload) && !isPendingPayloadEnvelope(payload) && payload.slot === undefined) {
304
329
  payload.slot = this.resolvePayloadSlot(rootHex);
330
+ if (payload.slot === undefined) {
331
+ // Still unresolvable: age it out so the MAX_PENDING_BLOCKS cap cannot stay saturated.
332
+ if (nowSec - payload.timeAddedSec > maxSecInCache) {
333
+ this.pendingPayloads.delete(rootHex);
334
+ agedOutPayloads++;
335
+ } else {
336
+ unresolvedSlotPayloads++;
337
+ this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
338
+ root: rootHex,
339
+ finalizedSlot,
340
+ });
341
+ }
342
+ continue;
343
+ }
305
344
  }
306
345
 
307
346
  const slot = getPayloadSyncCacheItemSlot(payload);
308
- if (typeof slot !== "number") {
309
- unresolvedSlotPayloads++;
310
- this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
311
- root: rootHex,
312
- finalizedSlot,
313
- });
314
- continue;
315
- }
316
-
317
- if (slot < finalizedSlot) {
347
+ if (typeof slot === "number" && slot < finalizedSlot) {
318
348
  this.pendingPayloads.delete(rootHex);
319
- deletedPayloads++;
349
+ belowFinalizedPayloads++;
320
350
  }
321
351
  }
322
352
 
@@ -329,14 +359,24 @@ export class BlockInputSync {
329
359
  }
330
360
  }
331
361
 
332
- if (deletedPayloads > 0 || deletedBlocks > 0) {
333
- this.metrics?.blockInputSync.removedBlocks.inc(deletedPayloads + deletedBlocks);
362
+ if (belowFinalizedPayloads > 0) {
363
+ this.metrics?.blockInputSync.removedPayloads.inc(
364
+ {reason: DroppedItemReason.belowFinalized},
365
+ belowFinalizedPayloads
366
+ );
367
+ }
368
+ if (agedOutPayloads > 0) {
369
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.agedOut}, agedOutPayloads);
370
+ }
371
+ if (deletedBlocks > 0) {
372
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.belowFinalized}, deletedBlocks);
334
373
  }
335
374
 
336
375
  this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
337
376
  finalizedSlot,
338
377
  finalizedRoot: checkpoint.rootHex,
339
- deletedPayloads,
378
+ belowFinalizedPayloads,
379
+ agedOutPayloads,
340
380
  deletedBlocks,
341
381
  unresolvedSlotPayloads,
342
382
  });
@@ -361,7 +401,9 @@ export class BlockInputSync {
361
401
  });
362
402
  }
363
403
 
364
- if (peerIdStr) {
404
+ // bound peers tracked per root: propagationSource is recorded pre-validation, so cap the set (#9923).
405
+ // Once at the cap, ignore further peers rather than evicting already-tracked ones.
406
+ if (peerIdStr && pendingBlock.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
365
407
  pendingBlock.peerIdStrings.add(peerIdStr);
366
408
  }
367
409
 
@@ -369,6 +411,7 @@ export class BlockInputSync {
369
411
  // Limit pending blocks to prevent DOS attacks that cause OOM
370
412
  const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
371
413
  if (prunedItemCount > 0) {
414
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
372
415
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
373
416
  }
374
417
  return added;
@@ -395,7 +438,9 @@ export class BlockInputSync {
395
438
  });
396
439
  }
397
440
 
398
- if (peerIdStr) {
441
+ // bound peers tracked per root: propagationSource is recorded pre-validation, so cap the set (#9923).
442
+ // Once at the cap, ignore further peers rather than evicting already-tracked ones.
443
+ if (peerIdStr && pendingBlock.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
399
444
  pendingBlock.peerIdStrings.add(peerIdStr);
400
445
  }
401
446
 
@@ -403,6 +448,7 @@ export class BlockInputSync {
403
448
  // Limit pending blocks to prevent DOS attacks that cause OOM
404
449
  const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
405
450
  if (prunedItemCount > 0) {
451
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
406
452
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
407
453
  }
408
454
  };
@@ -427,14 +473,22 @@ export class BlockInputSync {
427
473
  root: rootHex,
428
474
  peerIdStr: peerIdStr ?? "unknown peer",
429
475
  });
476
+ } else if (
477
+ // update a previously slot-less entry once a slot becomes available
478
+ slot !== undefined &&
479
+ !isPendingPayloadInput(pendingPayload) &&
480
+ !isPendingPayloadEnvelope(pendingPayload) &&
481
+ pendingPayload.slot === undefined
482
+ ) {
483
+ pendingPayload.slot = slot;
430
484
  }
431
-
432
- if (peerIdStr) {
485
+ if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
433
486
  pendingPayload.peerIdStrings.add(peerIdStr);
434
487
  }
435
488
 
436
489
  const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
437
490
  if (prunedItemCount > 0) {
491
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
438
492
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
439
493
  }
440
494
  return added;
@@ -474,7 +528,7 @@ export class BlockInputSync {
474
528
  envelope
475
529
  );
476
530
 
477
- if (peerIdStr) {
531
+ if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
478
532
  pendingPayload.peerIdStrings.add(peerIdStr);
479
533
  }
480
534
 
@@ -488,6 +542,7 @@ export class BlockInputSync {
488
542
 
489
543
  const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
490
544
  if (prunedItemCount > 0) {
545
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
491
546
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
492
547
  }
493
548
  };
@@ -544,15 +599,7 @@ export class BlockInputSync {
544
599
  return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
545
600
  }
546
601
 
547
- const parentPayloadInput = this.chain.seenPayloadEnvelopeInputCache.get(parentRootHex);
548
- if (parentPayloadInput) {
549
- if (parentPayloadInput.getBlockHashHex() === parentBlockHashHex) {
550
- return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
551
- }
552
-
553
- return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
554
- }
555
-
602
+ // Parent is in fork choice but its payload `parentBlockHashHex` isn't revealed yet
556
603
  return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
557
604
  }
558
605
 
@@ -590,7 +637,7 @@ export class BlockInputSync {
590
637
  parentRoot: missingDependency.parentRootHex,
591
638
  parentBlockHash: missingDependency.parentBlockHashHex,
592
639
  });
593
- this.removeAndDownScoreAllDescendants(pendingBlock);
640
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
594
641
  return "removed";
595
642
  }
596
643
  }
@@ -813,7 +860,7 @@ export class BlockInputSync {
813
860
  ...logCtx2,
814
861
  finalizedSlot,
815
862
  });
816
- this.removeAndDownScoreAllDescendants(block);
863
+ this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
817
864
  } else {
818
865
  this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
819
866
  }
@@ -830,7 +877,7 @@ export class BlockInputSync {
830
877
 
831
878
  this.metrics?.blockInputSync.downloadedBlocksError.inc();
832
879
  this.logger.debug("Ignoring unknown block root after many failed downloads", logCtx, res.err);
833
- this.removeAndDownScoreAllDescendants(block);
880
+ this.removeAndDownScoreAllDescendants(block, DroppedItemReason.unavailable);
834
881
  }
835
882
  }
836
883
 
@@ -894,9 +941,9 @@ export class BlockInputSync {
894
941
  this.pendingBlocks.delete(blockRootHex);
895
942
 
896
943
  if (isForkPostGloas(fork)) {
897
- const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(blockRootHex);
944
+ const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
898
945
  if (!payloadInput) {
899
- this.logger.warn("PayloadEnvelopeInput not seeded during unknown sync processReadyBlock()", logCtx);
946
+ this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
900
947
  } else {
901
948
  // Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
902
949
  // The bid already carries the kzg commitments, so there is no reason to wait for the payload to arrive.
@@ -938,19 +985,19 @@ export class BlockInputSync {
938
985
  case BlockErrorCode.EXECUTION_ENGINE_ERROR:
939
986
  // Removing the block(s) without penalizing the peers, hoping for EL to
940
987
  // recover on a latter download + verify attempt.
941
- this.removeAllDescendants(pendingBlock);
988
+ this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
942
989
  break;
943
990
 
944
991
  case BlockErrorCode.EXECUTION_ENGINE_INVALID:
945
992
  // the peer served a bad block
946
993
  this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
947
- this.removeAndDownScoreAllDescendants(pendingBlock);
994
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
948
995
  break;
949
996
 
950
997
  default:
951
998
  // Block is not correct with respect to our chain. Log error loudly
952
999
  this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
953
- this.removeAndDownScoreAllDescendants(pendingBlock);
1000
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
954
1001
  }
955
1002
  }
956
1003
 
@@ -969,12 +1016,12 @@ export class BlockInputSync {
969
1016
  */
970
1017
  private async reconcilePayloadEnvelope(pendingPayload: PendingPayloadEnvelope): Promise<void> {
971
1018
  const rootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
1019
+
972
1020
  if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
973
1021
  this.pendingPayloads.delete(rootHex);
974
1022
  return;
975
1023
  }
976
1024
 
977
- const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
978
1025
  if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
979
1026
  // Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
980
1027
  // non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
@@ -990,8 +1037,9 @@ export class BlockInputSync {
990
1037
  return;
991
1038
  }
992
1039
 
1040
+ const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
993
1041
  if (!payloadInput) {
994
- this.logger.debug("Missing PayloadEnvelopeInput for known block while reconciling payload envelope", {
1042
+ this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
995
1043
  root: rootHex,
996
1044
  });
997
1045
  return;
@@ -1153,17 +1201,27 @@ export class BlockInputSync {
1153
1201
  break;
1154
1202
 
1155
1203
  case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
1204
+ this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1205
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.elInvalid);
1206
+ break;
1207
+
1156
1208
  case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
1209
+ this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1210
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidEnvelope);
1211
+ break;
1212
+
1157
1213
  case PayloadErrorCode.INVALID_SIGNATURE:
1158
1214
  // TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
1159
1215
  // reintroducing envelope replacement / recreation flows.
1160
1216
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1161
- this.removePendingPayloadAndDescendants(rootHex);
1217
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
1162
1218
  break;
1163
1219
 
1164
1220
  default:
1165
1221
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1166
- this.pendingPayloads.delete(rootHex);
1222
+ if (this.pendingPayloads.delete(rootHex)) {
1223
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.unknown}, 1);
1224
+ }
1167
1225
  }
1168
1226
  return;
1169
1227
  }
@@ -1187,7 +1245,7 @@ export class BlockInputSync {
1187
1245
  let slot = getPayloadSyncCacheItemSlot(cacheItem);
1188
1246
  let payloadInput = isPendingPayloadInput(cacheItem)
1189
1247
  ? cacheItem.payloadInput
1190
- : this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
1248
+ : await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1191
1249
  let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
1192
1250
 
1193
1251
  let i = 0;
@@ -1196,7 +1254,12 @@ export class BlockInputSync {
1196
1254
  const pendingColumns = payloadInput?.hasAllData()
1197
1255
  ? new Set<number>()
1198
1256
  : new Set(payloadInput?.getMissingSampledColumnMeta().missing ?? []);
1199
- const peerMeta = this.peerBalancer.bestPeerForPendingColumns(pendingColumns, excludedPeers);
1257
+ // prefer peers that gossiped this payload root to us (#9923)
1258
+ const peerMeta = this.peerBalancer.bestPeerForPendingColumns(
1259
+ pendingColumns,
1260
+ excludedPeers,
1261
+ cacheItem.peerIdStrings
1262
+ );
1200
1263
  if (peerMeta === null) {
1201
1264
  if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
1202
1265
  throw new UnknownBlockRateLimitedError(
@@ -1220,7 +1283,7 @@ export class BlockInputSync {
1220
1283
  slot = envelope.message.payload.slotNumber;
1221
1284
  }
1222
1285
 
1223
- payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
1286
+ payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1224
1287
  if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
1225
1288
  // Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
1226
1289
  // envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
@@ -1405,7 +1468,12 @@ export class BlockInputSync {
1405
1468
  isPendingBlockInput(cacheItem) && isBlockInputColumns(cacheItem.blockInput)
1406
1469
  ? new Set(cacheItem.blockInput.getMissingSampledColumnMeta().missing)
1407
1470
  : defaultPendingColumns;
1408
- const peerMeta = this.peerBalancer.bestPeerForPendingColumns(pendingColumns, excludedPeers);
1471
+ // prefer peers that gossiped this block root to us (#9923)
1472
+ const peerMeta = this.peerBalancer.bestPeerForPendingColumns(
1473
+ pendingColumns,
1474
+ excludedPeers,
1475
+ cacheItem.peerIdStrings
1476
+ );
1409
1477
  if (peerMeta === null) {
1410
1478
  if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
1411
1479
  throw new UnknownBlockRateLimitedError(
@@ -1553,9 +1621,9 @@ export class BlockInputSync {
1553
1621
  * Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
1554
1622
  * referenced more than one bad block.
1555
1623
  */
1556
- private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem): void {
1624
+ private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
1557
1625
  // Get all blocks that are a descendant of this one
1558
- const badPendingBlocks = this.removeAllDescendants(block);
1626
+ const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
1559
1627
  // just console log and do not penalize on pending/bad blocks for debugging
1560
1628
  // console.log("removeAndDownscoreAllDescendants", {block});
1561
1629
 
@@ -1582,18 +1650,22 @@ export class BlockInputSync {
1582
1650
  }
1583
1651
 
1584
1652
  // Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
1585
- private removePendingPayloadAndDescendants(rootHex: RootHex): void {
1653
+ private removePendingPayloadAndDescendants(rootHex: RootHex, headReason: DroppedItemReason): void {
1586
1654
  // Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
1587
1655
  // later validation/finalization logic decides when it can leave memory.
1588
- this.pendingPayloads.delete(rootHex);
1656
+ if (this.pendingPayloads.delete(rootHex)) {
1657
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: headReason}, 1);
1658
+ }
1589
1659
 
1590
1660
  const badPendingBlocks = getAllDescendantBlocks(rootHex, this.pendingBlocks);
1591
- this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
1592
-
1593
1661
  for (const block of badPendingBlocks) {
1594
1662
  const descendantRootHex = getBlockInputSyncCacheItemRootHex(block);
1595
- this.pendingBlocks.delete(descendantRootHex);
1596
- this.pendingPayloads.delete(descendantRootHex);
1663
+ if (this.pendingBlocks.delete(descendantRootHex)) {
1664
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.invalidParent}, 1);
1665
+ }
1666
+ if (this.pendingPayloads.delete(descendantRootHex)) {
1667
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.invalidParent}, 1);
1668
+ }
1597
1669
  this.chain.seenBlockInputCache.prune(descendantRootHex);
1598
1670
  this.logger.debug("Removing pending descendant after invalid parent payload", {
1599
1671
  slot: getBlockInputSyncCacheItemSlot(block),
@@ -1603,18 +1675,25 @@ export class BlockInputSync {
1603
1675
  }
1604
1676
  }
1605
1677
 
1606
- private removeAllDescendants(block: BlockInputSyncCacheItem): BlockInputSyncCacheItem[] {
1678
+ private removeAllDescendants(
1679
+ block: BlockInputSyncCacheItem,
1680
+ headReason: DroppedItemReason,
1681
+ descendantReason: DroppedItemReason = DroppedItemReason.invalidParent
1682
+ ): BlockInputSyncCacheItem[] {
1607
1683
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1608
1684
  const slot = getBlockInputSyncCacheItemSlot(block);
1609
- // Get all blocks that are a descendant of this one
1685
+ // Get all blocks that are a descendant of this one (index 0 is the head item itself)
1610
1686
  const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
1611
1687
 
1612
- this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
1613
-
1614
- for (const block of badPendingBlocks) {
1688
+ for (const [i, block] of badPendingBlocks.entries()) {
1615
1689
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1616
- this.pendingBlocks.delete(rootHex);
1617
- this.pendingPayloads.delete(rootHex);
1690
+ const reason = i === 0 ? headReason : descendantReason;
1691
+ if (this.pendingBlocks.delete(rootHex)) {
1692
+ this.metrics?.blockInputSync.removedBlocks.inc({reason}, 1);
1693
+ }
1694
+ if (this.pendingPayloads.delete(rootHex)) {
1695
+ this.metrics?.blockInputSync.removedPayloads.inc({reason}, 1);
1696
+ }
1618
1697
  this.chain.seenBlockInputCache.prune(rootHex);
1619
1698
  // Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
1620
1699
  // importBlock()-owned lifecycle.
@@ -1670,6 +1749,13 @@ export class UnknownBlockPeerBalancer {
1670
1749
  this.rateLimitedUntilByPeer.delete(peerId);
1671
1750
  }
1672
1751
 
1752
+ /** Reset all tracked peer state, e.g. when BlockInputSync unsubscribes from the network. */
1753
+ clear(): void {
1754
+ this.peersMeta.clear();
1755
+ this.activeRequests.clear();
1756
+ this.rateLimitedUntilByPeer.clear();
1757
+ }
1758
+
1673
1759
  onRateLimited(peerId: PeerIdStr, rateLimitedUntilMs: number): void {
1674
1760
  this.rateLimitedUntilByPeer.set(peerId, rateLimitedUntilMs);
1675
1761
  }
@@ -1705,11 +1791,17 @@ export class UnknownBlockPeerBalancer {
1705
1791
  }
1706
1792
 
1707
1793
  /**
1708
- * called from fetchBlockInput() where we only have block root and nothing else
1794
+ * called from fetchBlockInput()/fetchPayloadInput() with a block/payload root.
1709
1795
  * excludedPeers are the peers that we requested already so we don't want to try again
1710
1796
  * pendingColumns is empty for prefulu, or the 1st time we we download a block by root
1797
+ * preferredPeers are the peers NetworkProcessor told us gossiped this root (from
1798
+ * pendingBlock/cacheItem.peerIdStrings). They are preferred but not required.
1711
1799
  */
1712
- bestPeerForPendingColumns(pendingColumns: Set<number>, excludedPeers: Set<PeerIdStr>): PeerSyncMeta | null {
1800
+ bestPeerForPendingColumns(
1801
+ pendingColumns: Set<number>,
1802
+ excludedPeers: Set<PeerIdStr>,
1803
+ preferredPeers?: Set<PeerIdStr>
1804
+ ): PeerSyncMeta | null {
1713
1805
  const eligiblePeers = this.filterPeers(pendingColumns, excludedPeers);
1714
1806
  if (eligiblePeers.length === 0) {
1715
1807
  return null;
@@ -1717,7 +1809,9 @@ export class UnknownBlockPeerBalancer {
1717
1809
 
1718
1810
  const sortedEligiblePeers = sortBy(
1719
1811
  shuffle(eligiblePeers),
1720
- // prefer peers with least active req
1812
+ // 1st key: prefer peers we heard about this root from
1813
+ (peerId) => (preferredPeers?.has(peerId) ? 0 : 1),
1814
+ // 2nd key (tiebreak): prefer peers with least active req
1721
1815
  (peerId) => this.activeRequests.get(peerId) ?? 0
1722
1816
  );
1723
1817
 
@@ -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"}