@lodestar/beacon-node 1.51.0-dev.312812503e → 1.51.0-dev.36022cc5cb

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 (356) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +17 -27
  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 +5 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +1 -1
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/api/impl/validator/index.d.ts +6 -0
  10. package/lib/api/impl/validator/index.d.ts.map +1 -1
  11. package/lib/api/impl/validator/index.js +42 -26
  12. package/lib/api/impl/validator/index.js.map +1 -1
  13. package/lib/chain/GetBlobsTracker.d.ts +13 -2
  14. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  15. package/lib/chain/GetBlobsTracker.js +85 -27
  16. package/lib/chain/GetBlobsTracker.js.map +1 -1
  17. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  18. package/lib/chain/archiveStore/archiveStore.js +1 -0
  19. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  20. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +4 -0
  21. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  22. package/lib/chain/archiveStore/utils/archiveBlocks.js +61 -97
  23. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  24. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  25. package/lib/chain/blocks/importBlock.js +21 -50
  26. package/lib/chain/blocks/importBlock.js.map +1 -1
  27. package/lib/chain/blocks/importExecutionPayload.d.ts +10 -11
  28. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  29. package/lib/chain/blocks/importExecutionPayload.js +32 -18
  30. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  31. package/lib/chain/blocks/index.d.ts.map +1 -1
  32. package/lib/chain/blocks/index.js +4 -4
  33. package/lib/chain/blocks/index.js.map +1 -1
  34. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +12 -9
  35. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  36. package/lib/chain/blocks/payloadEnvelopeProcessor.js +24 -19
  37. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  38. package/lib/chain/blocks/types.d.ts +4 -1
  39. package/lib/chain/blocks/types.d.ts.map +1 -1
  40. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  41. package/lib/chain/blocks/verifyBlock.js +18 -7
  42. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  43. package/lib/chain/blocks/verifyBlocksDataAvailability.d.ts.map +1 -1
  44. package/lib/chain/blocks/verifyBlocksDataAvailability.js +8 -1
  45. package/lib/chain/blocks/verifyBlocksDataAvailability.js.map +1 -1
  46. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +1 -1
  47. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  48. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  49. package/lib/chain/blocks/verifyBlocksSanityChecks.js +4 -0
  50. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  51. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  52. package/lib/chain/blocks/verifyBlocksSignatures.js +7 -5
  53. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  54. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +3 -3
  55. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  56. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +11 -6
  57. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  58. package/lib/chain/bls/interface.d.ts +2 -0
  59. package/lib/chain/bls/interface.d.ts.map +1 -1
  60. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  61. package/lib/chain/bls/multithread/index.js +13 -11
  62. package/lib/chain/bls/multithread/index.js.map +1 -1
  63. package/lib/chain/bls/multithread/types.d.ts +1 -1
  64. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  65. package/lib/chain/bls/multithread/worker.js +1 -1
  66. package/lib/chain/bls/multithread/worker.js.map +1 -1
  67. package/lib/chain/bls/singleThread.js +1 -1
  68. package/lib/chain/bls/singleThread.js.map +1 -1
  69. package/lib/chain/bls/utils.js +1 -1
  70. package/lib/chain/bls/utils.js.map +1 -1
  71. package/lib/chain/chain.d.ts +8 -2
  72. package/lib/chain/chain.d.ts.map +1 -1
  73. package/lib/chain/chain.js +57 -7
  74. package/lib/chain/chain.js.map +1 -1
  75. package/lib/chain/errors/blockError.d.ts +1 -1
  76. package/lib/chain/errors/blockError.d.ts.map +1 -1
  77. package/lib/chain/errors/blockError.js +1 -1
  78. package/lib/chain/errors/blockError.js.map +1 -1
  79. package/lib/chain/errors/executionPayloadEnvelope.d.ts +7 -0
  80. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  81. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  82. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  83. package/lib/chain/forkChoice/index.d.ts +11 -1
  84. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  85. package/lib/chain/forkChoice/index.js +11 -0
  86. package/lib/chain/forkChoice/index.js.map +1 -1
  87. package/lib/chain/forkChoiceExecutionEngine.d.ts +53 -0
  88. package/lib/chain/forkChoiceExecutionEngine.d.ts.map +1 -0
  89. package/lib/chain/forkChoiceExecutionEngine.js +121 -0
  90. package/lib/chain/forkChoiceExecutionEngine.js.map +1 -0
  91. package/lib/chain/interface.d.ts +5 -5
  92. package/lib/chain/interface.d.ts.map +1 -1
  93. package/lib/chain/interface.js.map +1 -1
  94. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  95. package/lib/chain/opPools/aggregatedAttestationPool.js +23 -10
  96. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  97. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  98. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  99. package/lib/chain/opPools/attestationPool.js +15 -4
  100. package/lib/chain/opPools/attestationPool.js.map +1 -1
  101. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  102. package/lib/chain/opPools/payloadAttestationPool.js +17 -7
  103. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  104. package/lib/chain/opPools/syncCommitteeMessagePool.d.ts.map +1 -1
  105. package/lib/chain/opPools/syncCommitteeMessagePool.js +9 -3
  106. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  107. package/lib/chain/opPools/syncContributionAndProofPool.d.ts.map +1 -1
  108. package/lib/chain/opPools/syncContributionAndProofPool.js +11 -3
  109. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  110. package/lib/chain/opPools/utils.d.ts +1 -1
  111. package/lib/chain/opPools/utils.d.ts.map +1 -1
  112. package/lib/chain/opPools/utils.js +1 -1
  113. package/lib/chain/opPools/utils.js.map +1 -1
  114. package/lib/chain/options.d.ts +0 -1
  115. package/lib/chain/options.d.ts.map +1 -1
  116. package/lib/chain/options.js +0 -1
  117. package/lib/chain/options.js.map +1 -1
  118. package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -2
  119. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  120. package/lib/chain/produceBlock/produceBlockBody.js +1 -1
  121. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  122. package/lib/chain/regen/interface.d.ts +1 -1
  123. package/lib/chain/regen/interface.d.ts.map +1 -1
  124. package/lib/chain/regen/queued.d.ts +1 -1
  125. package/lib/chain/regen/queued.d.ts.map +1 -1
  126. package/lib/chain/regen/queued.js +5 -3
  127. package/lib/chain/regen/queued.js.map +1 -1
  128. package/lib/chain/validation/executionPayloadBid.js +13 -13
  129. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  130. package/lib/chain/validation/executionPayloadEnvelope.d.ts +6 -0
  131. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  132. package/lib/chain/validation/executionPayloadEnvelope.js +53 -0
  133. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  134. package/lib/db/beacon.d.ts +7 -0
  135. package/lib/db/beacon.d.ts.map +1 -1
  136. package/lib/db/beacon.js +34 -0
  137. package/lib/db/beacon.js.map +1 -1
  138. package/lib/db/dataColumnStore.d.ts +1 -1
  139. package/lib/db/dataColumnStore.d.ts.map +1 -1
  140. package/lib/db/dataColumnStore.js +1 -4
  141. package/lib/db/dataColumnStore.js.map +1 -1
  142. package/lib/db/flatFileStore/flatFileStore.js +5 -5
  143. package/lib/db/flatFileStore/flatFileStore.js.map +1 -1
  144. package/lib/db/flatFileStore/slotIndex.d.ts.map +1 -1
  145. package/lib/db/flatFileStore/slotIndex.js +2 -2
  146. package/lib/db/flatFileStore/slotIndex.js.map +1 -1
  147. package/lib/db/interface.d.ts +1 -0
  148. package/lib/db/interface.d.ts.map +1 -1
  149. package/lib/db/repositories/dataColumnSidecarArchive.d.ts +6 -0
  150. package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
  151. package/lib/db/repositories/dataColumnSidecarArchive.js +19 -0
  152. package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
  153. package/lib/execution/builder/apiClient.d.ts +14 -8
  154. package/lib/execution/builder/apiClient.d.ts.map +1 -1
  155. package/lib/execution/builder/apiClient.js +12 -10
  156. package/lib/execution/builder/apiClient.js.map +1 -1
  157. package/lib/execution/builder/http.d.ts +2 -0
  158. package/lib/execution/builder/http.d.ts.map +1 -1
  159. package/lib/execution/builder/http.js +2 -0
  160. package/lib/execution/builder/http.js.map +1 -1
  161. package/lib/execution/engine/http.d.ts +2 -2
  162. package/lib/execution/engine/http.d.ts.map +1 -1
  163. package/lib/execution/engine/http.js +5 -4
  164. package/lib/execution/engine/http.js.map +1 -1
  165. package/lib/execution/engine/index.d.ts +1 -1
  166. package/lib/execution/engine/index.d.ts.map +1 -1
  167. package/lib/execution/engine/index.js +1 -1
  168. package/lib/execution/engine/index.js.map +1 -1
  169. package/lib/execution/engine/interface.d.ts +17 -3
  170. package/lib/execution/engine/interface.d.ts.map +1 -1
  171. package/lib/execution/engine/interface.js.map +1 -1
  172. package/lib/execution/engine/jsonRpcTransport.d.ts +2 -2
  173. package/lib/execution/engine/jsonRpcTransport.d.ts.map +1 -1
  174. package/lib/execution/engine/jsonRpcTransport.js +1 -1
  175. package/lib/execution/engine/jsonRpcTransport.js.map +1 -1
  176. package/lib/execution/engine/restTransport.d.ts +2 -2
  177. package/lib/execution/engine/restTransport.d.ts.map +1 -1
  178. package/lib/execution/engine/restTransport.js.map +1 -1
  179. package/lib/execution/engine/transport.d.ts +1 -12
  180. package/lib/execution/engine/transport.d.ts.map +1 -1
  181. package/lib/execution/engine/types.d.ts.map +1 -1
  182. package/lib/execution/engine/types.js +2 -2
  183. package/lib/execution/engine/types.js.map +1 -1
  184. package/lib/execution/engine/utils.d.ts.map +1 -1
  185. package/lib/execution/engine/utils.js +3 -2
  186. package/lib/execution/engine/utils.js.map +1 -1
  187. package/lib/index.d.ts +1 -0
  188. package/lib/index.d.ts.map +1 -1
  189. package/lib/index.js +2 -0
  190. package/lib/index.js.map +1 -1
  191. package/lib/metrics/metrics/lodestar.d.ts +4 -0
  192. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  193. package/lib/metrics/metrics/lodestar.js +10 -0
  194. package/lib/metrics/metrics/lodestar.js.map +1 -1
  195. package/lib/metrics/server/http.js +5 -5
  196. package/lib/metrics/server/http.js.map +1 -1
  197. package/lib/monitoring/service.js +1 -1
  198. package/lib/monitoring/service.js.map +1 -1
  199. package/lib/network/core/networkCore.d.ts +2 -0
  200. package/lib/network/core/networkCore.d.ts.map +1 -1
  201. package/lib/network/core/networkCore.js +3 -0
  202. package/lib/network/core/networkCore.js.map +1 -1
  203. package/lib/network/core/networkCoreWorker.js +1 -0
  204. package/lib/network/core/networkCoreWorker.js.map +1 -1
  205. package/lib/network/core/networkCoreWorkerHandler.d.ts +2 -0
  206. package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
  207. package/lib/network/core/networkCoreWorkerHandler.js +3 -0
  208. package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
  209. package/lib/network/core/types.d.ts +2 -0
  210. package/lib/network/core/types.d.ts.map +1 -1
  211. package/lib/network/gossip/gossipsub.d.ts +1 -0
  212. package/lib/network/gossip/gossipsub.d.ts.map +1 -1
  213. package/lib/network/gossip/gossipsub.js +10 -0
  214. package/lib/network/gossip/gossipsub.js.map +1 -1
  215. package/lib/network/interface.d.ts +2 -0
  216. package/lib/network/interface.d.ts.map +1 -1
  217. package/lib/network/libp2p/index.d.ts.map +1 -1
  218. package/lib/network/libp2p/index.js +5 -1
  219. package/lib/network/libp2p/index.js.map +1 -1
  220. package/lib/network/network.d.ts +4 -1
  221. package/lib/network/network.d.ts.map +1 -1
  222. package/lib/network/network.js +45 -15
  223. package/lib/network/network.js.map +1 -1
  224. package/lib/network/options.d.ts +2 -0
  225. package/lib/network/options.d.ts.map +1 -1
  226. package/lib/network/options.js.map +1 -1
  227. package/lib/network/peers/peerManager.d.ts +2 -1
  228. package/lib/network/peers/peerManager.d.ts.map +1 -1
  229. package/lib/network/peers/peerManager.js +28 -1
  230. package/lib/network/peers/peerManager.js.map +1 -1
  231. package/lib/network/peers/utils/assertPeerRelevance.d.ts +9 -1
  232. package/lib/network/peers/utils/assertPeerRelevance.d.ts.map +1 -1
  233. package/lib/network/peers/utils/assertPeerRelevance.js +32 -21
  234. package/lib/network/peers/utils/assertPeerRelevance.js.map +1 -1
  235. package/lib/network/peers/utils/prioritizePeers.d.ts +4 -1
  236. package/lib/network/peers/utils/prioritizePeers.d.ts.map +1 -1
  237. package/lib/network/peers/utils/prioritizePeers.js +8 -16
  238. package/lib/network/peers/utils/prioritizePeers.js.map +1 -1
  239. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  240. package/lib/network/processor/gossipHandlers.js +33 -19
  241. package/lib/network/processor/gossipHandlers.js.map +1 -1
  242. package/lib/network/processor/index.d.ts +6 -0
  243. package/lib/network/processor/index.d.ts.map +1 -1
  244. package/lib/network/processor/index.js +29 -3
  245. package/lib/network/processor/index.js.map +1 -1
  246. package/lib/node/nodejs.d.ts +3 -1
  247. package/lib/node/nodejs.d.ts.map +1 -1
  248. package/lib/node/nodejs.js +47 -21
  249. package/lib/node/nodejs.js.map +1 -1
  250. package/lib/node/options.d.ts +3 -1
  251. package/lib/node/options.d.ts.map +1 -1
  252. package/lib/node/options.js +4 -2
  253. package/lib/node/options.js.map +1 -1
  254. package/lib/sync/interface.d.ts.map +1 -1
  255. package/lib/sync/interface.js.map +1 -1
  256. package/lib/sync/sync.d.ts +7 -0
  257. package/lib/sync/sync.d.ts.map +1 -1
  258. package/lib/sync/sync.js +61 -3
  259. package/lib/sync/sync.js.map +1 -1
  260. package/lib/util/execution.d.ts +4 -4
  261. package/lib/util/execution.d.ts.map +1 -1
  262. package/lib/util/execution.js.map +1 -1
  263. package/lib/util/file.d.ts.map +1 -1
  264. package/lib/util/file.js +8 -9
  265. package/lib/util/file.js.map +1 -1
  266. package/lib/util/queue/itemQueue.js +1 -1
  267. package/lib/util/queue/itemQueue.js.map +1 -1
  268. package/lib/util/sszBytes.d.ts +5 -0
  269. package/lib/util/sszBytes.d.ts.map +1 -1
  270. package/lib/util/sszBytes.js +35 -2
  271. package/lib/util/sszBytes.js.map +1 -1
  272. package/package.json +16 -17
  273. package/src/api/impl/beacon/blocks/index.ts +35 -45
  274. package/src/api/impl/beacon/pool/index.ts +5 -1
  275. package/src/api/impl/beacon/state/utils.ts +1 -1
  276. package/src/api/impl/validator/index.ts +47 -30
  277. package/src/chain/GetBlobsTracker.ts +99 -40
  278. package/src/chain/archiveStore/archiveStore.ts +1 -0
  279. package/src/chain/archiveStore/utils/archiveBlocks.ts +76 -130
  280. package/src/chain/blocks/importBlock.ts +40 -71
  281. package/src/chain/blocks/importExecutionPayload.ts +55 -34
  282. package/src/chain/blocks/index.ts +11 -4
  283. package/src/chain/blocks/payloadEnvelopeProcessor.ts +35 -24
  284. package/src/chain/blocks/types.ts +4 -1
  285. package/src/chain/blocks/verifyBlock.ts +31 -16
  286. package/src/chain/blocks/verifyBlocksDataAvailability.ts +10 -1
  287. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +1 -1
  288. package/src/chain/blocks/verifyBlocksSanityChecks.ts +4 -1
  289. package/src/chain/blocks/verifyBlocksSignatures.ts +7 -5
  290. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +14 -6
  291. package/src/chain/bls/interface.ts +2 -0
  292. package/src/chain/bls/multithread/index.ts +14 -10
  293. package/src/chain/bls/multithread/types.ts +1 -1
  294. package/src/chain/bls/multithread/worker.ts +1 -5
  295. package/src/chain/bls/singleThread.ts +1 -1
  296. package/src/chain/bls/utils.ts +1 -1
  297. package/src/chain/chain.ts +67 -8
  298. package/src/chain/errors/blockError.ts +1 -1
  299. package/src/chain/errors/executionPayloadEnvelope.ts +8 -0
  300. package/src/chain/forkChoice/index.ts +11 -0
  301. package/src/chain/forkChoiceExecutionEngine.ts +197 -0
  302. package/src/chain/interface.ts +5 -5
  303. package/src/chain/opPools/aggregatedAttestationPool.ts +25 -9
  304. package/src/chain/opPools/attestationPool.ts +16 -4
  305. package/src/chain/opPools/payloadAttestationPool.ts +18 -7
  306. package/src/chain/opPools/syncCommitteeMessagePool.ts +10 -3
  307. package/src/chain/opPools/syncContributionAndProofPool.ts +13 -3
  308. package/src/chain/opPools/utils.ts +1 -1
  309. package/src/chain/options.ts +0 -2
  310. package/src/chain/produceBlock/produceBlockBody.ts +4 -2
  311. package/src/chain/regen/interface.ts +1 -1
  312. package/src/chain/regen/queued.ts +6 -4
  313. package/src/chain/validation/executionPayloadBid.ts +14 -13
  314. package/src/chain/validation/executionPayloadEnvelope.ts +68 -1
  315. package/src/db/beacon.ts +44 -0
  316. package/src/db/dataColumnStore.ts +2 -4
  317. package/src/db/flatFileStore/flatFileStore.ts +7 -7
  318. package/src/db/flatFileStore/slotIndex.ts +4 -3
  319. package/src/db/interface.ts +2 -0
  320. package/src/db/repositories/dataColumnSidecarArchive.ts +20 -0
  321. package/src/execution/builder/apiClient.ts +16 -13
  322. package/src/execution/builder/http.ts +4 -0
  323. package/src/execution/engine/http.ts +12 -13
  324. package/src/execution/engine/index.ts +1 -1
  325. package/src/execution/engine/interface.ts +19 -3
  326. package/src/execution/engine/jsonRpcTransport.ts +10 -2
  327. package/src/execution/engine/restTransport.ts +3 -1
  328. package/src/execution/engine/transport.ts +8 -14
  329. package/src/execution/engine/types.ts +3 -1
  330. package/src/execution/engine/utils.ts +4 -2
  331. package/src/index.ts +2 -0
  332. package/src/metrics/metrics/lodestar.ts +10 -0
  333. package/src/metrics/server/http.ts +5 -5
  334. package/src/monitoring/service.ts +1 -1
  335. package/src/network/core/networkCore.ts +5 -0
  336. package/src/network/core/networkCoreWorker.ts +1 -0
  337. package/src/network/core/networkCoreWorkerHandler.ts +4 -0
  338. package/src/network/core/types.ts +2 -0
  339. package/src/network/gossip/gossipsub.ts +11 -0
  340. package/src/network/interface.ts +2 -0
  341. package/src/network/libp2p/index.ts +5 -1
  342. package/src/network/network.ts +45 -19
  343. package/src/network/options.ts +2 -0
  344. package/src/network/peers/peerManager.ts +28 -3
  345. package/src/network/peers/utils/assertPeerRelevance.ts +39 -23
  346. package/src/network/peers/utils/prioritizePeers.ts +14 -22
  347. package/src/network/processor/gossipHandlers.ts +38 -21
  348. package/src/network/processor/index.ts +25 -3
  349. package/src/node/nodejs.ts +58 -22
  350. package/src/node/options.ts +9 -6
  351. package/src/sync/interface.ts +1 -0
  352. package/src/sync/sync.ts +65 -4
  353. package/src/util/execution.ts +6 -6
  354. package/src/util/file.ts +8 -9
  355. package/src/util/queue/itemQueue.ts +1 -1
  356. package/src/util/sszBytes.ts +42 -2
@@ -30,10 +30,11 @@ import {
30
30
  isGloasDataColumnSidecar,
31
31
  phase0,
32
32
  } from "@lodestar/types";
33
- import {prettyPrintIndices, sleep} from "@lodestar/utils";
33
+ import {defer, prettyPrintIndices, sleep} from "@lodestar/utils";
34
34
  import {BlockInputSource} from "../chain/blocks/blockInput/types.js";
35
35
  import {ChainEvent, IBeaconChain} from "../chain/index.js";
36
36
  import {computeSubnetForDataColumnSidecar} from "../chain/validation/dataColumnSidecar.js";
37
+ import {GoodByeReasonCode} from "../constants/index.js";
37
38
  import {IBeaconDb} from "../db/interface.js";
38
39
  import {Metrics, RegistryMetricCreator} from "../metrics/index.js";
39
40
  import {IClock} from "../util/clock.js";
@@ -127,6 +128,7 @@ export class Network implements INetwork {
127
128
 
128
129
  private subscribedToCoreTopics = false;
129
130
  private connectedPeersSyncMeta = new Map<PeerIdStr, Omit<PeerSyncMeta, "peerId">>();
131
+ private closePromise: Promise<void> | undefined;
130
132
 
131
133
  constructor(modules: NetworkModules) {
132
134
  this.peerId = peerIdFromPrivateKey(modules.privateKey);
@@ -144,12 +146,8 @@ export class Network implements INetwork {
144
146
  this.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
145
147
  this.events.on(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
146
148
  this.chain.emitter.on(routes.events.EventType.head, this.onHead);
147
- this.chain.emitter.on(routes.events.EventType.lightClientFinalityUpdate, ({data}) =>
148
- this.onLightClientFinalityUpdate(data)
149
- );
150
- this.chain.emitter.on(routes.events.EventType.lightClientOptimisticUpdate, ({data}) =>
151
- this.onLightClientOptimisticUpdate(data)
152
- );
149
+ this.chain.emitter.on(routes.events.EventType.lightClientFinalityUpdate, this.onLightClientFinalityUpdate);
150
+ this.chain.emitter.on(routes.events.EventType.lightClientOptimisticUpdate, this.onLightClientOptimisticUpdate);
153
151
  this.chain.emitter.on(ChainEvent.updateTargetCustodyGroupCount, this.onTargetGroupCountUpdated);
154
152
  this.chain.emitter.on(ChainEvent.publishDataColumns, this.onPublishDataColumns);
155
153
  this.chain.emitter.on(ChainEvent.publishBlobSidecars, this.onPublishBlobSidecars);
@@ -239,9 +237,16 @@ export class Network implements INetwork {
239
237
  return this.controller.signal.aborted;
240
238
  }
241
239
 
242
- /** Destroy this instance. Can only be called once. */
243
- async close(): Promise<void> {
244
- if (this.closed) return;
240
+ close(): Promise<void> {
241
+ if (this.closePromise !== undefined) return this.closePromise;
242
+ const completion = defer<void>();
243
+ this.closePromise = completion.promise;
244
+ void this.closeInternal().then(completion.resolve, completion.reject);
245
+ return this.closePromise;
246
+ }
247
+
248
+ private async closeInternal(): Promise<void> {
249
+ this.controller.abort();
245
250
 
246
251
  this.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
247
252
  this.events.off(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
@@ -253,10 +258,12 @@ export class Network implements INetwork {
253
258
  this.chain.emitter.off(ChainEvent.publishBlobSidecars, this.onPublishBlobSidecars);
254
259
  this.chain.emitter.off(ChainEvent.publishProposerSlashing, this.onPublishProposerSlashing);
255
260
  this.chain.emitter.off(ChainEvent.updateStatus, this.onUpdateStatus);
256
- await this.core.close();
257
-
258
- // Used only for sleep() statements
259
- this.controller.abort();
261
+ this.connectedPeersSyncMeta.clear();
262
+ this.subscribedToCoreTopics = false;
263
+ const results = await Promise.allSettled([this.networkProcessor.stop(), this.core.close()]);
264
+ for (const result of results) {
265
+ if (result.status === "rejected") throw result.reason;
266
+ }
260
267
  this.logger.debug("network core closed");
261
268
  }
262
269
 
@@ -289,6 +296,10 @@ export class Network implements INetwork {
289
296
  return this.core.reStatusPeers(peers);
290
297
  }
291
298
 
299
+ async goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void> {
300
+ return this.core.goodbyeAndDisconnect(peer, reason);
301
+ }
302
+
292
303
  searchUnknownBlock(slotRoot: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
293
304
  this.networkProcessor.searchUnknownBlock(slotRoot, source, peer);
294
305
  }
@@ -328,6 +339,7 @@ export class Network implements INetwork {
328
339
  async subscribeGossipCoreTopics(): Promise<void> {
329
340
  if (!this.subscribedToCoreTopics) {
330
341
  await this.core.subscribeGossipCoreTopics();
342
+ if (this.closed) return;
331
343
  // Only mark subscribedToCoreTopics if worker resolved this call
332
344
  this.subscribedToCoreTopics = true;
333
345
  }
@@ -798,26 +810,32 @@ export class Network implements INetwork {
798
810
  return this.core.writeDiscv5HeapSnapshot(prefix, dirpath);
799
811
  }
800
812
 
801
- private onLightClientFinalityUpdate = async (finalityUpdate: LightClientFinalityUpdate): Promise<void> => {
813
+ private onLightClientFinalityUpdate = async ({
814
+ data: finalityUpdate,
815
+ }: routes.events.EventData[routes.events.EventType.lightClientFinalityUpdate]): Promise<void> => {
802
816
  // TODO: Review is OK to remove if (this.hasAttachedSyncCommitteeMember())
803
817
 
804
818
  try {
805
819
  // messages SHOULD be broadcast after SYNC_MESSAGE_DUE_BPS of slot has transpired
806
820
  // https://github.com/ethereum/consensus-specs/blob/v1.6.1/specs/altair/light-client/p2p-interface.md#sync-committee
807
821
  await this.waitForSyncMessageCutoff(finalityUpdate.signatureSlot);
822
+ if (this.closed) return;
808
823
  await this.publishLightClientFinalityUpdate(finalityUpdate);
809
824
  } catch (e) {
810
825
  this.logger.debug("Error on BeaconGossipHandler.onLightclientFinalityUpdate", {}, e as Error);
811
826
  }
812
827
  };
813
828
 
814
- private onLightClientOptimisticUpdate = async (optimisticUpdate: LightClientOptimisticUpdate): Promise<void> => {
829
+ private onLightClientOptimisticUpdate = async ({
830
+ data: optimisticUpdate,
831
+ }: routes.events.EventData[routes.events.EventType.lightClientOptimisticUpdate]): Promise<void> => {
815
832
  // TODO: Review is OK to remove if (this.hasAttachedSyncCommitteeMember())
816
833
 
817
834
  try {
818
835
  // messages SHOULD be broadcast after SYNC_MESSAGE_DUE_BPS of slot has transpired
819
836
  // https://github.com/ethereum/consensus-specs/blob/v1.6.1/specs/altair/light-client/p2p-interface.md#sync-committee
820
837
  await this.waitForSyncMessageCutoff(optimisticUpdate.signatureSlot);
838
+ if (this.closed) return;
821
839
  await this.publishLightClientOptimisticUpdate(optimisticUpdate);
822
840
  } catch (e) {
823
841
  this.logger.debug("Error on BeaconGossipHandler.onLightclientOptimisticUpdate", {}, e as Error);
@@ -854,8 +872,12 @@ export class Network implements INetwork {
854
872
  this.connectedPeersSyncMeta.delete(data.peer);
855
873
  };
856
874
 
857
- private onTargetGroupCountUpdated = (count: number): void => {
858
- this.core.setTargetGroupCount(count);
875
+ private onTargetGroupCountUpdated = async (count: number): Promise<void> => {
876
+ try {
877
+ await this.core.setTargetGroupCount(count);
878
+ } catch (error) {
879
+ this.logger.error("Error updating network custody group count", {count}, error as Error);
880
+ }
859
881
  };
860
882
 
861
883
  private onPublishDataColumns = async (sidecars: DataColumnSidecar[]): Promise<void> => {
@@ -879,6 +901,10 @@ export class Network implements INetwork {
879
901
  };
880
902
 
881
903
  private onUpdateStatus = async (): Promise<void> => {
882
- await this.core.updateStatus(this.chain.getStatus());
904
+ try {
905
+ await this.core.updateStatus(this.chain.getStatus());
906
+ } catch (error) {
907
+ this.logger.error("Error updating network status", {}, error as Error);
908
+ }
883
909
  };
884
910
  }
@@ -25,6 +25,8 @@ export interface NetworkOptions
25
25
  mdns?: boolean;
26
26
  connectToDiscv5Bootnodes?: boolean;
27
27
  version?: string;
28
+ /** Include the version in libp2p Identify. Private mode takes precedence. */
29
+ advertiseVersion?: boolean;
28
30
  private?: boolean;
29
31
  useWorker?: boolean;
30
32
  maxYoungGenerationSizeMb?: number;
@@ -14,6 +14,7 @@ import {NetworkCoreMetrics} from "../core/metrics.js";
14
14
  import {LodestarDiscv5Opts} from "../discv5/types.js";
15
15
  import {INetworkEventBus, NetworkEvent, NetworkEventData} from "../events.js";
16
16
  import {Eth2Gossipsub} from "../gossip/gossipsub.js";
17
+ import {GossipType} from "../gossip/interface.js";
17
18
  import {Libp2p} from "../interface.js";
18
19
  import {SubnetType} from "../metadata.js";
19
20
  import {NetworkConfig} from "../networkConfig.js";
@@ -577,6 +578,8 @@ export class PeerManager {
577
578
  this.lastStatus = status;
578
579
  this.metrics?.peerManager.starved.set(starved ? 1 : 0);
579
580
  const forkSeq = this.config.getForkSeq(this.clock.currentSlot);
581
+ const boundary = this.config.getForkBoundaryAtEpoch(this.clock.currentEpoch);
582
+ const connectedHealthyPeerIds = new Set(connectedHealthyPeers.map((peer) => peer.toString()));
580
583
 
581
584
  const prioritizeTimer = this.metrics?.peerManager.prioritizePeersDuration.startTimer();
582
585
  const {peersToDisconnect, peersToConnect, attnetQueries, syncnetQueries, custodyGroupQueries} = prioritizePeers(
@@ -594,8 +597,30 @@ export class PeerManager {
594
597
  };
595
598
  }),
596
599
  // Collect subnets which we need peers for in the current slot
597
- this.attnetsService.getActiveSubnets(),
598
- this.syncnetsService.getActiveSubnets(),
600
+ this.attnetsService.getActiveSubnets().map((request) => {
601
+ const subscribers = this.gossipsub.getSubscribersWithOutboundStream({
602
+ type: GossipType.beacon_attestation,
603
+ boundary,
604
+ subnet: request.subnet,
605
+ });
606
+ let peerCount = 0;
607
+ for (const peer of subscribers) {
608
+ if (connectedHealthyPeerIds.has(peer)) peerCount++;
609
+ }
610
+ return {...request, peerCount};
611
+ }),
612
+ this.syncnetsService.getActiveSubnets().map((request) => {
613
+ const subscribers = this.gossipsub.getSubscribersWithOutboundStream({
614
+ type: GossipType.sync_committee,
615
+ boundary,
616
+ subnet: request.subnet,
617
+ });
618
+ let peerCount = 0;
619
+ for (const peer of subscribers) {
620
+ if (connectedHealthyPeerIds.has(peer)) peerCount++;
621
+ }
622
+ return {...request, peerCount};
623
+ }),
599
624
  // ignore samplingGroups for pre-fulu forks
600
625
  forkSeq >= ForkSeq.fulu ? this.networkConfig.custodyConfig.sampleGroups : undefined,
601
626
  {
@@ -893,7 +918,7 @@ export class PeerManager {
893
918
  }
894
919
  }
895
920
 
896
- private async goodbyeAndDisconnect(peer: PeerId, goodbye: GoodByeReasonCode): Promise<void> {
921
+ async goodbyeAndDisconnect(peer: PeerId, goodbye: GoodByeReasonCode): Promise<void> {
897
922
  const reason = GOODBYE_KNOWN_CODES[goodbye.toString()] || "";
898
923
  const peerIdStr = peer.toString();
899
924
  try {
@@ -1,5 +1,6 @@
1
- import {ForkName, isForkPostFulu} from "@lodestar/params";
2
- import {ForkDigest, Root, Slot, Status, fulu, ssz} from "@lodestar/types";
1
+ import {ForkName, GENESIS_EPOCH, isForkPostFulu} from "@lodestar/params";
2
+ import {computeEpochAtSlot} from "@lodestar/state-transition";
3
+ import {Epoch, ForkDigest, Root, Slot, Status, fulu, ssz} from "@lodestar/types";
3
4
  import {toHex, toRootHex} from "@lodestar/utils";
4
5
 
5
6
  // TODO: Why this value? (From Lighthouse)
@@ -9,6 +10,8 @@ export enum IrrelevantPeerCode {
9
10
  INCOMPATIBLE_FORKS = "IRRELEVANT_PEER_INCOMPATIBLE_FORKS",
10
11
  DIFFERENT_CLOCKS = "IRRELEVANT_PEER_DIFFERENT_CLOCKS",
11
12
  DIFFERENT_FINALIZED = "IRRELEVANT_PEER_DIFFERENT_FINALIZED",
13
+ FINALIZED_EPOCH_TOO_HIGH = "IRRELEVANT_PEER_FINALIZED_EPOCH_TOO_HIGH",
14
+ INVALID_FINALIZED_ROOT = "IRRELEVANT_PEER_INVALID_FINALIZED_ROOT",
12
15
  NO_EARLIEST_AVAILABLE_SLOT = "NO_EARLIEST_AVAILABLE_SLOT",
13
16
  }
14
17
 
@@ -16,6 +19,8 @@ type IrrelevantPeerType =
16
19
  | {code: IrrelevantPeerCode.INCOMPATIBLE_FORKS; ours: ForkDigest; theirs: ForkDigest}
17
20
  | {code: IrrelevantPeerCode.DIFFERENT_CLOCKS; slotDiff: number}
18
21
  | {code: IrrelevantPeerCode.NO_EARLIEST_AVAILABLE_SLOT}
22
+ | {code: IrrelevantPeerCode.FINALIZED_EPOCH_TOO_HIGH; finalizedEpoch: Epoch; maxFinalizedEpoch: Epoch}
23
+ | {code: IrrelevantPeerCode.INVALID_FINALIZED_ROOT}
19
24
  | {code: IrrelevantPeerCode.DIFFERENT_FINALIZED; expectedRoot: Root; remoteRoot: Root};
20
25
 
21
26
  /**
@@ -45,29 +50,35 @@ export function assertPeerRelevance(
45
50
  return {code: IrrelevantPeerCode.DIFFERENT_CLOCKS, slotDiff};
46
51
  }
47
52
 
48
- // The remote's finalized epoch is less than or equal to ours, but the block root is
49
- // different to the one in our chain. Therefore, the node is on a different chain and we
50
- // should not communicate with them.
53
+ // A checkpoint can be finalized at the earliest at the start of epoch + 2
54
+ const maxFinalizedEpoch = Math.max(
55
+ GENESIS_EPOCH,
56
+ computeEpochAtSlot(Math.max(currentSlot, 0) + FUTURE_SLOT_TOLERANCE) - 2
57
+ );
58
+ if (remote.finalizedEpoch > maxFinalizedEpoch) {
59
+ return {
60
+ code: IrrelevantPeerCode.FINALIZED_EPOCH_TOO_HIGH,
61
+ finalizedEpoch: remote.finalizedEpoch,
62
+ maxFinalizedEpoch,
63
+ };
64
+ }
65
+
66
+ if (remote.finalizedEpoch > GENESIS_EPOCH && isZeroRoot(remote.finalizedRoot)) {
67
+ return {code: IrrelevantPeerCode.INVALID_FINALIZED_ROOT};
68
+ }
51
69
 
70
+ // The remote's finalized epoch is equal to ours, but the block root is different to the one in our chain.
71
+ // Therefore, the node is on a different chain and we should not communicate with them.
52
72
  if (
53
- remote.finalizedEpoch <= local.finalizedEpoch &&
54
- !isZeroRoot(remote.finalizedRoot) &&
55
- !isZeroRoot(local.finalizedRoot)
73
+ remote.finalizedEpoch === local.finalizedEpoch &&
74
+ !isZeroRoot(local.finalizedRoot) &&
75
+ !ssz.Root.equals(remote.finalizedRoot, local.finalizedRoot)
56
76
  ) {
57
- // NOTE: due to preferring to not access chain state here, we can't check the finalized root against our history.
58
- // The impact of not doing check is low: peers that are behind us we can't confirm they are in the same chain as us.
59
- // In the worst case they will attempt to sync from us, fail and disconnect. The ENR fork check should be sufficient
60
- // to differentiate most peers in normal network conditions.
61
- const remoteRoot = remote.finalizedRoot;
62
- const expectedRoot = remote.finalizedEpoch === local.finalizedEpoch ? local.finalizedRoot : null;
63
-
64
- if (expectedRoot !== null && !ssz.Root.equals(remoteRoot, expectedRoot)) {
65
- return {
66
- code: IrrelevantPeerCode.DIFFERENT_FINALIZED,
67
- expectedRoot: expectedRoot, // forkChoice returns Tree BranchNode which the logger prints as {}
68
- remoteRoot: remoteRoot,
69
- };
70
- }
77
+ return {
78
+ code: IrrelevantPeerCode.DIFFERENT_FINALIZED,
79
+ expectedRoot: local.finalizedRoot,
80
+ remoteRoot: remote.finalizedRoot,
81
+ };
71
82
  }
72
83
 
73
84
  if (isForkPostFulu(forkName) && (remote as fulu.Status).earliestAvailableSlot === undefined) {
@@ -76,7 +87,8 @@ export function assertPeerRelevance(
76
87
  };
77
88
  }
78
89
 
79
- // Note: Accept request status finalized checkpoint in the future, we do not know if it is a true finalized root
90
+ // Note: for a behind finalized checkpoint, we validate it more on the main thread against our history,
91
+ // see BeaconSync.verifyPastFinalizedCheckpoint
80
92
  return null;
81
93
  }
82
94
 
@@ -93,6 +105,10 @@ export function renderIrrelevantPeerType(type: IrrelevantPeerType): string {
93
105
  return `DIFFERENT_CLOCKS slotDiff: ${type.slotDiff}`;
94
106
  case IrrelevantPeerCode.DIFFERENT_FINALIZED:
95
107
  return `DIFFERENT_FINALIZED root: ${toRootHex(type.remoteRoot)} expected: ${toRootHex(type.expectedRoot)}`;
108
+ case IrrelevantPeerCode.FINALIZED_EPOCH_TOO_HIGH:
109
+ return `FINALIZED_EPOCH_TOO_HIGH finalizedEpoch: ${type.finalizedEpoch} max: ${type.maxFinalizedEpoch}`;
110
+ case IrrelevantPeerCode.INVALID_FINALIZED_ROOT:
111
+ return "INVALID_FINALIZED_ROOT zero root for a non-genesis finalized epoch";
96
112
  case IrrelevantPeerCode.NO_EARLIEST_AVAILABLE_SLOT:
97
113
  return "No earliestAvailableSlot announced via peer Status";
98
114
  }
@@ -49,6 +49,8 @@ const syncnetsZero = BitArray.fromBitLen(SYNC_COMMITTEE_SUBNET_COUNT);
49
49
 
50
50
  type SubnetDiscvQuery = {subnet: SubnetID; toSlot: number; maxPeersToDiscover: number};
51
51
 
52
+ export type RequestedSubnetWithPeerCount = RequestedSubnet & {peerCount: number};
53
+
52
54
  /**
53
55
  * A map of das custody group index to maxPeersToDiscover
54
56
  */
@@ -145,8 +147,8 @@ export function prioritizePeers(
145
147
  samplingGroups: CustodyIndex[] | null;
146
148
  score: number;
147
149
  }[],
148
- activeAttnets: RequestedSubnet[],
149
- activeSyncnets: RequestedSubnet[],
150
+ activeAttnets: RequestedSubnetWithPeerCount[],
151
+ activeSyncnets: RequestedSubnetWithPeerCount[],
150
152
  samplingGroups: CustodyIndex[] | undefined,
151
153
  opts: PrioritizePeersOpts,
152
154
  config: ChainConfig,
@@ -231,8 +233,8 @@ export function prioritizePeers(
231
233
  */
232
234
  function requestSubnetPeers(
233
235
  connectedPeers: PeerInfo[],
234
- activeAttnets: RequestedSubnet[],
235
- activeSyncnets: RequestedSubnet[],
236
+ activeAttnets: RequestedSubnetWithPeerCount[],
237
+ activeSyncnets: RequestedSubnetWithPeerCount[],
236
238
  ourSamplingGroups: CustodyIndex[] | undefined,
237
239
  opts: PrioritizePeersOpts,
238
240
  config: ChainConfig,
@@ -252,54 +254,44 @@ function requestSubnetPeers(
252
254
 
253
255
  // attnets, do we need queries for more peers
254
256
  if (activeAttnets.length > 0) {
255
- /** Map of peers per subnet, peer may be in multiple arrays */
256
- const peersPerSubnet = new Map<number, number>();
257
-
258
257
  for (const peer of connectedPeers) {
259
258
  const trueBitIndices = peer.attnetsTrueBitIndices;
260
259
  let dutyCount = 0;
261
260
  for (const {subnet} of activeAttnets) {
262
261
  if (trueBitIndices.includes(subnet)) {
263
262
  dutyCount += 1;
264
- peersPerSubnet.set(subnet, 1 + (peersPerSubnet.get(subnet) ?? 0));
265
263
  }
266
264
  }
267
265
  dutiesByPeer.set(peer, dutyCount);
268
266
  }
269
267
 
270
- for (const {subnet, toSlot} of activeAttnets) {
271
- const peersInSubnet = peersPerSubnet.get(subnet) ?? 0;
272
- metrics?.peerManager.peersPerActiveSubnet.observe({type: SubnetType.attnets}, peersInSubnet);
273
- if (peersInSubnet < targetSubnetPeers) {
268
+ for (const {subnet, toSlot, peerCount} of activeAttnets) {
269
+ metrics?.peerManager.peersPerActiveSubnet.observe({type: SubnetType.attnets}, peerCount);
270
+ if (peerCount < targetSubnetPeers) {
274
271
  // We need more peers
275
- attnetQueries.push({subnet, toSlot, maxPeersToDiscover: targetSubnetPeers - peersInSubnet});
272
+ attnetQueries.push({subnet, toSlot, maxPeersToDiscover: targetSubnetPeers - peerCount});
276
273
  }
277
274
  }
278
275
  }
279
276
 
280
277
  // syncnets, do we need queries for more peers
281
278
  if (activeSyncnets.length > 0) {
282
- /** Map of peers per subnet, peer may be in multiple arrays */
283
- const peersPerSubnet = new Map<number, number>();
284
-
285
279
  for (const peer of connectedPeers) {
286
280
  const trueBitIndices = peer.syncnetsTrueBitIndices;
287
281
  let dutyCount = dutiesByPeer.get(peer) ?? 0;
288
282
  for (const {subnet} of activeSyncnets) {
289
283
  if (trueBitIndices.includes(subnet)) {
290
284
  dutyCount += 1;
291
- peersPerSubnet.set(subnet, 1 + (peersPerSubnet.get(subnet) ?? 0));
292
285
  }
293
286
  }
294
287
  dutiesByPeer.set(peer, dutyCount);
295
288
  }
296
289
 
297
- for (const {subnet, toSlot} of activeSyncnets) {
298
- const peersInSubnet = peersPerSubnet.get(subnet) ?? 0;
299
- metrics?.peerManager.peersPerActiveSubnet.observe({type: SubnetType.syncnets}, peersInSubnet);
300
- if (peersInSubnet < targetSubnetPeers) {
290
+ for (const {subnet, toSlot, peerCount} of activeSyncnets) {
291
+ metrics?.peerManager.peersPerActiveSubnet.observe({type: SubnetType.syncnets}, peerCount);
292
+ if (peerCount < targetSubnetPeers) {
301
293
  // We need more peers
302
- syncnetQueries.push({subnet, toSlot, maxPeersToDiscover: targetSubnetPeers - peersInSubnet});
294
+ syncnetQueries.push({subnet, toSlot, maxPeersToDiscover: targetSubnetPeers - peerCount});
303
295
  }
304
296
  }
305
297
  }
@@ -66,7 +66,10 @@ import {
66
66
  validateGossipGloasDataColumnSidecar,
67
67
  } from "../../chain/validation/dataColumnSidecar.js";
68
68
  import {validateGossipExecutionPayloadBid} from "../../chain/validation/executionPayloadBid.js";
69
- import {validateGossipExecutionPayloadEnvelope} from "../../chain/validation/executionPayloadEnvelope.js";
69
+ import {
70
+ validateGossipExecutionPayloadEnvelope,
71
+ validateGossipExecutionPayloadEnvelopeSerialized,
72
+ } from "../../chain/validation/executionPayloadEnvelope.js";
70
73
  import {InclusionListValidationResult, validateGossipInclusionList} from "../../chain/validation/inclusionList.js";
71
74
  import {
72
75
  AggregateAndProofValidationResult,
@@ -705,10 +708,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
705
708
 
706
709
  // Immediately attempt fetch of data columns from execution engine as the bid contains kzg commitments
707
710
  // which is all the information we need so there is no reason to delay until execution payload arrives
708
- // TODO GLOAS: If we want EL retries after this initial attempt, add an explicit retry policy here
709
- // (for example later in the slot). Do not couple retries to incoming gossip columns.
710
- // Columns fetched here feed payloadInput.addColumn, which resolves waitForAllData for any
711
- // in-flight importExecutionPayload. No processExecutionPayload trigger needed from this path.
711
+ // Columns fetched here feed payloadInput.addColumn, which resolves the waitForAllData of a
712
+ // pending payload import. No processExecutionPayload trigger needed from this path.
712
713
  chain.getBlobsTracker.triggerGetBlobs(payloadInput);
713
714
  }
714
715
  })
@@ -718,11 +719,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
718
719
 
719
720
  if (e instanceof BlockError) {
720
721
  switch (e.type.code) {
721
- case BlockErrorCode.DATA_UNAVAILABLE: {
722
- // Error is quite frequent and not critical
722
+ case BlockErrorCode.DATA_UNAVAILABLE:
723
+ // Data did not arrive in time, BlockInputSync keeps pulling it and retries the import
723
724
  logLevel = LogLevel.debug;
724
725
  break;
725
- }
726
726
  // ALREADY_KNOWN should not happen with ignoreIfKnown=true above
727
727
  // PARENT_BLOCK_UNKNOWN should not happen, we handled this in validateBeaconBlock() function above
728
728
  case BlockErrorCode.ALREADY_KNOWN:
@@ -930,7 +930,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
930
930
  }
931
931
 
932
932
  // NOTE: we do NOT call chain.processExecutionPayload here. That is triggered only by
933
- // envelope arrival (gossip or API). An in-flight importExecutionPayload is awaiting
933
+ // envelope arrival (gossip or API). A pending payload import is awaiting
934
934
  // payloadInput.waitForAllData(); addColumn above will resolve it once hasAllData flips.
935
935
 
936
936
  scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
@@ -1279,6 +1279,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1279
1279
  seenTimestampSec,
1280
1280
  }: GossipHandlerParamGeneric<GossipType.execution_payload>) => {
1281
1281
  const {serializedData} = gossipData;
1282
+ validateGossipExecutionPayloadEnvelopeSerialized(chain, serializedData);
1282
1283
  const signedEnvelope = sszDeserialize(topic, serializedData);
1283
1284
  const envelope = signedEnvelope.message;
1284
1285
 
@@ -1331,18 +1332,22 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1331
1332
  });
1332
1333
  }
1333
1334
 
1335
+ // Add the envelope in the same tick as validation, otherwise a by-root download that completes
1336
+ // before the next event loop sees no envelope, validates it again and adds it first
1337
+ if (!payloadInput.hasPayloadEnvelope()) {
1338
+ chain.serializedCache.set(signedEnvelope, serializedData);
1339
+
1340
+ payloadInput.addPayloadEnvelope({
1341
+ envelope: signedEnvelope,
1342
+ source: PayloadEnvelopeInputSource.gossip,
1343
+ seenTimestampSec,
1344
+ peerIdStr,
1345
+ });
1346
+ }
1347
+
1334
1348
  // Handler - deferred to next event loop so the validation result propagates first
1335
1349
  callInNextEventLoop(() => {
1336
1350
  try {
1337
- chain.serializedCache.set(signedEnvelope, serializedData);
1338
-
1339
- payloadInput.addPayloadEnvelope({
1340
- envelope: signedEnvelope,
1341
- source: PayloadEnvelopeInputSource.gossip,
1342
- seenTimestampSec,
1343
- peerIdStr,
1344
- });
1345
-
1346
1351
  scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
1347
1352
 
1348
1353
  chain.emitter.emit(routes.events.EventType.executionPayloadGossip, {
@@ -1352,12 +1357,18 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1352
1357
  blockRoot: blockRootHex,
1353
1358
  });
1354
1359
 
1355
- chain.processExecutionPayload(payloadInput, {validSignature: true}).catch((e) => {
1360
+ // Signature is verified above only for this envelope, one added by another source is verified at import
1361
+ const validSignature = payloadInput.getPayloadEnvelope() === signedEnvelope;
1362
+ chain.processExecutionPayload(payloadInput, {validSignature}).catch((e) => {
1356
1363
  // Adjust verbosity based on error type
1357
1364
  let logLevel: LogLevel;
1358
1365
 
1359
1366
  if (e instanceof PayloadError) {
1360
1367
  switch (e.type.code) {
1368
+ case PayloadErrorCode.DATA_UNAVAILABLE:
1369
+ // Columns did not arrive in time, BlockInputSync keeps pulling them and retries the import
1370
+ logLevel = LogLevel.debug;
1371
+ break;
1361
1372
  // BLOCK_NOT_IN_FORK_CHOICE should not happen, validateGossipExecutionPayloadEnvelope above
1362
1373
  // already verified the block is in fork choice
1363
1374
  case PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE:
@@ -1366,11 +1377,17 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1366
1377
  // Errors might indicate an issue with our node or the connected EL client
1367
1378
  logLevel = LogLevel.error;
1368
1379
  break;
1369
- // INVALID_SIGNATURE should not happen, signature is verified during gossip validation
1380
+ case PayloadErrorCode.BLOCK_EXECUTION_INVALID:
1381
+ logLevel = LogLevel.warn;
1382
+ break;
1383
+ // INVALID_SIGNATURE only happens for an envelope added by another source
1370
1384
  case PayloadErrorCode.INVALID_SIGNATURE:
1371
1385
  case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
1372
1386
  case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
1373
- core.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadGossipPayload");
1387
+ // Penalize only when the stored envelope is the one this peer sent, not one added by another source
1388
+ if (validSignature) {
1389
+ core.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadGossipPayload");
1390
+ }
1374
1391
  // The builder may have signed another envelope that is valid, keeping this one would make
1375
1392
  // by-root and range sync reuse it and never import the payload
1376
1393
  chain.seenPayloadEnvelopeInputCache.removeInvalid(payloadInput);
@@ -244,6 +244,12 @@ type SearchUnknownRootTarget =
244
244
  * Such that enough work is processed to fill either one of the queue.
245
245
  */
246
246
  export class NetworkProcessor {
247
+ private stopped = false;
248
+ /**
249
+ * Replaced by dropAllJobs(). Loops that yield while re-queueing awaiting messages compare it after each yield
250
+ * and stop, so no message is queued after a drop.
251
+ */
252
+ private jobGeneration = Symbol();
247
253
  private readonly chain: IBeaconChain;
248
254
  private readonly core: INetworkCore;
249
255
  private readonly events: NetworkEventBus;
@@ -335,16 +341,27 @@ export class NetworkProcessor {
335
341
  }
336
342
 
337
343
  async stop(): Promise<void> {
344
+ if (this.stopped) return;
345
+ this.stopped = true;
338
346
  this.events.off(NetworkEvent.pendingGossipsubMessage, this.onPendingGossipsubMessage);
339
347
  this.chain.emitter.off(routes.events.EventType.block, this.onBlockProcessed);
340
348
  this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadEnvelopeProcessed);
341
- this.chain.emitter.off(ClockEvent.slot, this.onClockSlot);
349
+ this.chain.clock.off(ClockEvent.slot, this.onClockSlot);
350
+ this.dropAllJobs();
342
351
  }
343
352
 
344
353
  dropAllJobs(): void {
354
+ this.jobGeneration = Symbol();
345
355
  for (const topic of executeGossipWorkOrder) {
346
356
  this.gossipQueues[topic].clear();
347
357
  }
358
+ this.awaitingMessagesByBlockRoot.clear();
359
+ this.awaitingBlockMessageCount = 0;
360
+ this.awaitingMessagesByPayloadBlockRoot.clear();
361
+ this.awaitingPayloadMessageCount = 0;
362
+ this.searchedRootsBySlot.clear();
363
+ this.bufferedRootsBySlot.clear();
364
+ this.fatalPeers.clear();
348
365
  }
349
366
 
350
367
  dumpGossipQueue(topic: GossipType): PendingGossipsubMessage[] {
@@ -364,7 +381,7 @@ export class NetworkProcessor {
364
381
  * prefer them as by-root download candidates.
365
382
  */
366
383
  searchUnknownBlock({slot, root}: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
367
- if (this.chain.seenBlock(root)) {
384
+ if (this.stopped || this.chain.seenBlock(root)) {
368
385
  return;
369
386
  }
370
387
  const entry = this.searchedRootsBySlot.getOrDefault(slot).getOrDefault(root);
@@ -398,7 +415,7 @@ export class NetworkProcessor {
398
415
  peer?: PeerIdStr,
399
416
  slotIsPayloadSlot = false
400
417
  ): void {
401
- if (this.chain.seenPayloadEnvelope(root)) {
418
+ if (this.stopped || this.chain.seenPayloadEnvelope(root)) {
402
419
  return;
403
420
  }
404
421
  const entry = this.searchedRootsBySlot.getOrDefault(slot).getOrDefault(root);
@@ -801,6 +818,7 @@ export class NetworkProcessor {
801
818
  this.awaitingBlockMessageCount -= total;
802
819
  }
803
820
 
821
+ const generation = this.jobGeneration;
804
822
  const nowSec = Date.now() / 1000;
805
823
  let count = 0;
806
824
  // TODO: we can group attestations to process in batches but since we have the SeenAttestationDatas
@@ -819,6 +837,7 @@ export class NetworkProcessor {
819
837
  if (count === MAX_AWAITING_GOSSIP_OBJECTS_PER_TICK) {
820
838
  count = 0;
821
839
  await sleep(AWAITING_GOSSIP_OBJECTS_YIELD_EVERY_MS);
840
+ if (generation !== this.jobGeneration) return;
822
841
  }
823
842
  }
824
843
  }
@@ -843,6 +862,7 @@ export class NetworkProcessor {
843
862
  this.awaitingPayloadMessageCount -= total;
844
863
  }
845
864
 
865
+ const generation = this.jobGeneration;
846
866
  const nowSec = Date.now() / 1000;
847
867
  let count = 0;
848
868
  for (const messages of messagesByTopic.values()) {
@@ -858,6 +878,7 @@ export class NetworkProcessor {
858
878
  if (count === MAX_AWAITING_GOSSIP_OBJECTS_PER_TICK) {
859
879
  count = 0;
860
880
  await sleep(AWAITING_GOSSIP_OBJECTS_YIELD_EVERY_MS);
881
+ if (generation !== this.jobGeneration) return;
861
882
  }
862
883
  }
863
884
  }
@@ -937,6 +958,7 @@ export class NetworkProcessor {
937
958
  };
938
959
 
939
960
  private executeWork(): void {
961
+ if (this.stopped) return;
940
962
  // TODO: Maybe de-bounce by timing the last time executeWork was run
941
963
 
942
964
  this.metrics?.networkProcessor.executeWorkCalls.inc();