@lodestar/beacon-node 1.51.0-dev.c6e566f915 → 1.51.0-dev.d2440f7e84

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 (361) hide show
  1. package/lib/api/impl/api.js +1 -1
  2. package/lib/api/impl/api.js.map +1 -1
  3. package/lib/api/impl/beacon/blocks/index.d.ts +2 -1
  4. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/blocks/index.js +29 -34
  6. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  7. package/lib/api/impl/beacon/index.d.ts +2 -1
  8. package/lib/api/impl/beacon/index.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/index.js +2 -2
  10. package/lib/api/impl/beacon/index.js.map +1 -1
  11. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  12. package/lib/api/impl/beacon/pool/index.js +5 -2
  13. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  14. package/lib/api/impl/beacon/state/utils.d.ts +1 -1
  15. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  16. package/lib/api/impl/validator/index.d.ts +6 -0
  17. package/lib/api/impl/validator/index.d.ts.map +1 -1
  18. package/lib/api/impl/validator/index.js +49 -31
  19. package/lib/api/impl/validator/index.js.map +1 -1
  20. package/lib/api/options.d.ts +2 -0
  21. package/lib/api/options.d.ts.map +1 -1
  22. package/lib/api/options.js +1 -0
  23. package/lib/api/options.js.map +1 -1
  24. package/lib/chain/GetBlobsTracker.d.ts +11 -0
  25. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  26. package/lib/chain/GetBlobsTracker.js +85 -27
  27. package/lib/chain/GetBlobsTracker.js.map +1 -1
  28. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  29. package/lib/chain/archiveStore/archiveStore.js +1 -0
  30. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  31. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +4 -0
  32. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  33. package/lib/chain/archiveStore/utils/archiveBlocks.js +61 -97
  34. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  35. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  36. package/lib/chain/blocks/importBlock.js +6 -5
  37. package/lib/chain/blocks/importBlock.js.map +1 -1
  38. package/lib/chain/blocks/importExecutionPayload.d.ts +6 -11
  39. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  40. package/lib/chain/blocks/importExecutionPayload.js +10 -16
  41. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  42. package/lib/chain/blocks/index.js +2 -2
  43. package/lib/chain/blocks/index.js.map +1 -1
  44. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +12 -9
  45. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  46. package/lib/chain/blocks/payloadEnvelopeProcessor.js +24 -19
  47. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  48. package/lib/chain/blocks/types.d.ts +4 -1
  49. package/lib/chain/blocks/types.d.ts.map +1 -1
  50. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  51. package/lib/chain/blocks/verifyBlock.js +18 -7
  52. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  53. package/lib/chain/blocks/verifyBlocksDataAvailability.d.ts.map +1 -1
  54. package/lib/chain/blocks/verifyBlocksDataAvailability.js +8 -1
  55. package/lib/chain/blocks/verifyBlocksDataAvailability.js.map +1 -1
  56. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  57. package/lib/chain/blocks/verifyBlocksSignatures.js +7 -5
  58. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  59. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +3 -3
  60. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  61. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +11 -6
  62. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  63. package/lib/chain/bls/interface.d.ts +2 -0
  64. package/lib/chain/bls/interface.d.ts.map +1 -1
  65. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  66. package/lib/chain/bls/multithread/index.js +13 -11
  67. package/lib/chain/bls/multithread/index.js.map +1 -1
  68. package/lib/chain/bls/multithread/types.d.ts +1 -1
  69. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  70. package/lib/chain/bls/multithread/worker.js +1 -1
  71. package/lib/chain/bls/multithread/worker.js.map +1 -1
  72. package/lib/chain/bls/singleThread.js +1 -1
  73. package/lib/chain/bls/singleThread.js.map +1 -1
  74. package/lib/chain/bls/utils.js +1 -1
  75. package/lib/chain/bls/utils.js.map +1 -1
  76. package/lib/chain/chain.d.ts +1 -1
  77. package/lib/chain/chain.d.ts.map +1 -1
  78. package/lib/chain/chain.js +4 -4
  79. package/lib/chain/chain.js.map +1 -1
  80. package/lib/chain/errors/blockError.d.ts +1 -1
  81. package/lib/chain/errors/blockError.d.ts.map +1 -1
  82. package/lib/chain/errors/blockError.js +1 -1
  83. package/lib/chain/errors/blockError.js.map +1 -1
  84. package/lib/chain/errors/executionPayloadEnvelope.d.ts +7 -0
  85. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  86. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  87. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  88. package/lib/chain/interface.d.ts +2 -3
  89. package/lib/chain/interface.d.ts.map +1 -1
  90. package/lib/chain/interface.js.map +1 -1
  91. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  92. package/lib/chain/opPools/aggregatedAttestationPool.js +23 -10
  93. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  94. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  95. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  96. package/lib/chain/opPools/attestationPool.js +15 -4
  97. package/lib/chain/opPools/attestationPool.js.map +1 -1
  98. package/lib/chain/opPools/inclusionListStore.d.ts.map +1 -1
  99. package/lib/chain/opPools/inclusionListStore.js +2 -2
  100. package/lib/chain/opPools/inclusionListStore.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.map +1 -1
  119. package/lib/chain/produceBlock/produceBlockBody.js +0 -1
  120. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  121. package/lib/chain/regen/interface.d.ts +0 -1
  122. package/lib/chain/regen/interface.d.ts.map +1 -1
  123. package/lib/chain/regen/interface.js +0 -1
  124. package/lib/chain/regen/interface.js.map +1 -1
  125. package/lib/chain/validation/executionPayloadBid.d.ts +0 -15
  126. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  127. package/lib/chain/validation/executionPayloadBid.js +13 -166
  128. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  129. package/lib/chain/validation/executionPayloadEnvelope.d.ts +6 -0
  130. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  131. package/lib/chain/validation/executionPayloadEnvelope.js +53 -0
  132. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  133. package/lib/chain/validation/inclusionList.d.ts.map +1 -1
  134. package/lib/chain/validation/inclusionList.js +11 -2
  135. package/lib/chain/validation/inclusionList.js.map +1 -1
  136. package/lib/db/beacon.d.ts +7 -0
  137. package/lib/db/beacon.d.ts.map +1 -1
  138. package/lib/db/beacon.js +34 -0
  139. package/lib/db/beacon.js.map +1 -1
  140. package/lib/db/dataColumnStore.d.ts +1 -1
  141. package/lib/db/dataColumnStore.d.ts.map +1 -1
  142. package/lib/db/dataColumnStore.js +1 -4
  143. package/lib/db/dataColumnStore.js.map +1 -1
  144. package/lib/db/flatFileStore/flatFileStore.js +5 -5
  145. package/lib/db/flatFileStore/flatFileStore.js.map +1 -1
  146. package/lib/db/flatFileStore/slotIndex.d.ts.map +1 -1
  147. package/lib/db/flatFileStore/slotIndex.js +2 -2
  148. package/lib/db/flatFileStore/slotIndex.js.map +1 -1
  149. package/lib/db/interface.d.ts +1 -0
  150. package/lib/db/interface.d.ts.map +1 -1
  151. package/lib/db/repositories/dataColumnSidecarArchive.d.ts +6 -0
  152. package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
  153. package/lib/db/repositories/dataColumnSidecarArchive.js +19 -0
  154. package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
  155. package/lib/execution/builder/apiClient.d.ts +14 -8
  156. package/lib/execution/builder/apiClient.d.ts.map +1 -1
  157. package/lib/execution/builder/apiClient.js +12 -10
  158. package/lib/execution/builder/apiClient.js.map +1 -1
  159. package/lib/execution/builder/http.d.ts +2 -0
  160. package/lib/execution/builder/http.d.ts.map +1 -1
  161. package/lib/execution/builder/http.js +2 -0
  162. package/lib/execution/builder/http.js.map +1 -1
  163. package/lib/execution/engine/blobVersionedHashes.d.ts +1 -1
  164. package/lib/execution/engine/blobVersionedHashes.d.ts.map +1 -1
  165. package/lib/execution/engine/blobVersionedHashes.js.map +1 -1
  166. package/lib/execution/engine/http.d.ts.map +1 -1
  167. package/lib/execution/engine/http.js +0 -1
  168. package/lib/execution/engine/http.js.map +1 -1
  169. package/lib/execution/engine/index.d.ts +1 -1
  170. package/lib/execution/engine/index.d.ts.map +1 -1
  171. package/lib/execution/engine/index.js +1 -1
  172. package/lib/execution/engine/index.js.map +1 -1
  173. package/lib/execution/engine/interface.d.ts +1 -1
  174. package/lib/execution/engine/interface.d.ts.map +1 -1
  175. package/lib/execution/engine/interface.js.map +1 -1
  176. package/lib/execution/engine/mock.d.ts.map +1 -1
  177. package/lib/execution/engine/mock.js +6 -4
  178. package/lib/execution/engine/mock.js.map +1 -1
  179. package/lib/execution/engine/payloadIdCache.d.ts +1 -2
  180. package/lib/execution/engine/payloadIdCache.d.ts.map +1 -1
  181. package/lib/execution/engine/payloadIdCache.js +3 -3
  182. package/lib/execution/engine/payloadIdCache.js.map +1 -1
  183. package/lib/execution/engine/sszTypes.d.ts +38 -38
  184. package/lib/execution/engine/types.d.ts +1 -1
  185. package/lib/execution/engine/types.d.ts.map +1 -1
  186. package/lib/execution/engine/types.js +9 -8
  187. package/lib/execution/engine/types.js.map +1 -1
  188. package/lib/execution/engine/utils.d.ts.map +1 -1
  189. package/lib/execution/engine/utils.js +3 -2
  190. package/lib/execution/engine/utils.js.map +1 -1
  191. package/lib/index.d.ts +1 -0
  192. package/lib/index.d.ts.map +1 -1
  193. package/lib/index.js +2 -0
  194. package/lib/index.js.map +1 -1
  195. package/lib/metrics/metrics/lodestar.d.ts +7 -0
  196. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  197. package/lib/metrics/metrics/lodestar.js +15 -0
  198. package/lib/metrics/metrics/lodestar.js.map +1 -1
  199. package/lib/metrics/server/http.js +5 -5
  200. package/lib/metrics/server/http.js.map +1 -1
  201. package/lib/monitoring/service.js +1 -1
  202. package/lib/monitoring/service.js.map +1 -1
  203. package/lib/network/core/networkCore.d.ts +2 -0
  204. package/lib/network/core/networkCore.d.ts.map +1 -1
  205. package/lib/network/core/networkCore.js +3 -0
  206. package/lib/network/core/networkCore.js.map +1 -1
  207. package/lib/network/core/networkCoreWorker.js +1 -0
  208. package/lib/network/core/networkCoreWorker.js.map +1 -1
  209. package/lib/network/core/networkCoreWorkerHandler.d.ts +2 -0
  210. package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
  211. package/lib/network/core/networkCoreWorkerHandler.js +3 -0
  212. package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
  213. package/lib/network/core/types.d.ts +2 -0
  214. package/lib/network/core/types.d.ts.map +1 -1
  215. package/lib/network/gossip/gossipsub.d.ts +1 -0
  216. package/lib/network/gossip/gossipsub.d.ts.map +1 -1
  217. package/lib/network/gossip/gossipsub.js +10 -0
  218. package/lib/network/gossip/gossipsub.js.map +1 -1
  219. package/lib/network/gossip/topic.d.ts +6 -6
  220. package/lib/network/interface.d.ts +2 -0
  221. package/lib/network/interface.d.ts.map +1 -1
  222. package/lib/network/libp2p/index.d.ts.map +1 -1
  223. package/lib/network/libp2p/index.js +5 -1
  224. package/lib/network/libp2p/index.js.map +1 -1
  225. package/lib/network/network.d.ts +2 -0
  226. package/lib/network/network.d.ts.map +1 -1
  227. package/lib/network/network.js +6 -1
  228. package/lib/network/network.js.map +1 -1
  229. package/lib/network/options.d.ts +2 -0
  230. package/lib/network/options.d.ts.map +1 -1
  231. package/lib/network/options.js.map +1 -1
  232. package/lib/network/peers/peerManager.d.ts +2 -1
  233. package/lib/network/peers/peerManager.d.ts.map +1 -1
  234. package/lib/network/peers/peerManager.js +30 -1
  235. package/lib/network/peers/peerManager.js.map +1 -1
  236. package/lib/network/peers/utils/assertPeerRelevance.d.ts +9 -1
  237. package/lib/network/peers/utils/assertPeerRelevance.d.ts.map +1 -1
  238. package/lib/network/peers/utils/assertPeerRelevance.js +32 -21
  239. package/lib/network/peers/utils/assertPeerRelevance.js.map +1 -1
  240. package/lib/network/peers/utils/prioritizePeers.d.ts +4 -1
  241. package/lib/network/peers/utils/prioritizePeers.d.ts.map +1 -1
  242. package/lib/network/peers/utils/prioritizePeers.js +8 -16
  243. package/lib/network/peers/utils/prioritizePeers.js.map +1 -1
  244. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  245. package/lib/network/processor/gossipHandlers.js +57 -37
  246. package/lib/network/processor/gossipHandlers.js.map +1 -1
  247. package/lib/network/processor/index.d.ts.map +1 -1
  248. package/lib/network/processor/index.js +26 -25
  249. package/lib/network/processor/index.js.map +1 -1
  250. package/lib/node/nodejs.d.ts +3 -1
  251. package/lib/node/nodejs.d.ts.map +1 -1
  252. package/lib/node/nodejs.js +47 -21
  253. package/lib/node/nodejs.js.map +1 -1
  254. package/lib/node/options.d.ts +3 -1
  255. package/lib/node/options.d.ts.map +1 -1
  256. package/lib/node/options.js +4 -2
  257. package/lib/node/options.js.map +1 -1
  258. package/lib/sync/interface.d.ts.map +1 -1
  259. package/lib/sync/interface.js.map +1 -1
  260. package/lib/sync/sync.d.ts +7 -0
  261. package/lib/sync/sync.d.ts.map +1 -1
  262. package/lib/sync/sync.js +61 -3
  263. package/lib/sync/sync.js.map +1 -1
  264. package/lib/sync/unknownBlock.d.ts.map +1 -1
  265. package/lib/sync/unknownBlock.js +42 -18
  266. package/lib/sync/unknownBlock.js.map +1 -1
  267. package/lib/util/file.d.ts.map +1 -1
  268. package/lib/util/file.js +8 -9
  269. package/lib/util/file.js.map +1 -1
  270. package/lib/util/queue/itemQueue.js +1 -1
  271. package/lib/util/queue/itemQueue.js.map +1 -1
  272. package/lib/util/sszBytes.d.ts +5 -0
  273. package/lib/util/sszBytes.d.ts.map +1 -1
  274. package/lib/util/sszBytes.js +35 -2
  275. package/lib/util/sszBytes.js.map +1 -1
  276. package/package.json +31 -32
  277. package/src/api/impl/api.ts +1 -1
  278. package/src/api/impl/beacon/blocks/index.ts +57 -62
  279. package/src/api/impl/beacon/index.ts +3 -1
  280. package/src/api/impl/beacon/pool/index.ts +5 -1
  281. package/src/api/impl/beacon/state/utils.ts +1 -1
  282. package/src/api/impl/validator/index.ts +54 -37
  283. package/src/api/options.ts +3 -0
  284. package/src/chain/GetBlobsTracker.ts +97 -38
  285. package/src/chain/archiveStore/archiveStore.ts +1 -0
  286. package/src/chain/archiveStore/utils/archiveBlocks.ts +76 -130
  287. package/src/chain/blocks/importBlock.ts +8 -7
  288. package/src/chain/blocks/importExecutionPayload.ts +15 -22
  289. package/src/chain/blocks/index.ts +6 -2
  290. package/src/chain/blocks/payloadEnvelopeProcessor.ts +35 -24
  291. package/src/chain/blocks/types.ts +4 -1
  292. package/src/chain/blocks/verifyBlock.ts +31 -16
  293. package/src/chain/blocks/verifyBlocksDataAvailability.ts +10 -1
  294. package/src/chain/blocks/verifyBlocksSignatures.ts +7 -5
  295. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +14 -6
  296. package/src/chain/bls/interface.ts +2 -0
  297. package/src/chain/bls/multithread/index.ts +14 -10
  298. package/src/chain/bls/multithread/types.ts +1 -1
  299. package/src/chain/bls/multithread/worker.ts +1 -5
  300. package/src/chain/bls/singleThread.ts +1 -1
  301. package/src/chain/bls/utils.ts +1 -1
  302. package/src/chain/chain.ts +5 -5
  303. package/src/chain/errors/blockError.ts +1 -1
  304. package/src/chain/errors/executionPayloadEnvelope.ts +8 -0
  305. package/src/chain/interface.ts +2 -3
  306. package/src/chain/opPools/aggregatedAttestationPool.ts +25 -9
  307. package/src/chain/opPools/attestationPool.ts +16 -4
  308. package/src/chain/opPools/inclusionListStore.ts +3 -3
  309. package/src/chain/opPools/payloadAttestationPool.ts +18 -7
  310. package/src/chain/opPools/syncCommitteeMessagePool.ts +10 -3
  311. package/src/chain/opPools/syncContributionAndProofPool.ts +13 -3
  312. package/src/chain/opPools/utils.ts +1 -1
  313. package/src/chain/options.ts +0 -2
  314. package/src/chain/produceBlock/produceBlockBody.ts +0 -1
  315. package/src/chain/regen/interface.ts +0 -1
  316. package/src/chain/validation/executionPayloadBid.ts +14 -193
  317. package/src/chain/validation/executionPayloadEnvelope.ts +68 -1
  318. package/src/chain/validation/inclusionList.ts +11 -2
  319. package/src/db/beacon.ts +44 -0
  320. package/src/db/dataColumnStore.ts +2 -4
  321. package/src/db/flatFileStore/flatFileStore.ts +7 -7
  322. package/src/db/flatFileStore/slotIndex.ts +4 -3
  323. package/src/db/interface.ts +2 -0
  324. package/src/db/repositories/dataColumnSidecarArchive.ts +20 -0
  325. package/src/execution/builder/apiClient.ts +16 -13
  326. package/src/execution/builder/http.ts +4 -0
  327. package/src/execution/engine/blobVersionedHashes.ts +1 -1
  328. package/src/execution/engine/http.ts +0 -1
  329. package/src/execution/engine/index.ts +1 -1
  330. package/src/execution/engine/interface.ts +1 -1
  331. package/src/execution/engine/mock.ts +6 -4
  332. package/src/execution/engine/payloadIdCache.ts +6 -7
  333. package/src/execution/engine/types.ts +11 -9
  334. package/src/execution/engine/utils.ts +4 -2
  335. package/src/index.ts +2 -0
  336. package/src/metrics/metrics/lodestar.ts +15 -0
  337. package/src/metrics/server/http.ts +5 -5
  338. package/src/monitoring/service.ts +1 -1
  339. package/src/network/core/networkCore.ts +5 -0
  340. package/src/network/core/networkCoreWorker.ts +1 -0
  341. package/src/network/core/networkCoreWorkerHandler.ts +4 -0
  342. package/src/network/core/types.ts +2 -0
  343. package/src/network/gossip/gossipsub.ts +11 -0
  344. package/src/network/interface.ts +2 -0
  345. package/src/network/libp2p/index.ts +5 -1
  346. package/src/network/network.ts +8 -1
  347. package/src/network/options.ts +2 -0
  348. package/src/network/peers/peerManager.ts +30 -3
  349. package/src/network/peers/utils/assertPeerRelevance.ts +39 -23
  350. package/src/network/peers/utils/prioritizePeers.ts +14 -22
  351. package/src/network/processor/gossipHandlers.ts +69 -40
  352. package/src/network/processor/index.ts +22 -23
  353. package/src/network/processor/types.ts +1 -1
  354. package/src/node/nodejs.ts +58 -22
  355. package/src/node/options.ts +9 -6
  356. package/src/sync/interface.ts +1 -0
  357. package/src/sync/sync.ts +65 -4
  358. package/src/sync/unknownBlock.ts +47 -28
  359. package/src/util/file.ts +8 -9
  360. package/src/util/queue/itemQueue.ts +1 -1
  361. package/src/util/sszBytes.ts +42 -2
@@ -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,32 @@ 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
601
+ .getActiveSubnets()
602
+ .map((request) => {
603
+ const subscribers = this.gossipsub.getSubscribersWithOutboundStream({
604
+ type: GossipType.beacon_attestation,
605
+ boundary,
606
+ subnet: request.subnet,
607
+ });
608
+ let peerCount = 0;
609
+ for (const peer of subscribers) {
610
+ if (connectedHealthyPeerIds.has(peer)) peerCount++;
611
+ }
612
+ return {...request, peerCount};
613
+ }),
614
+ this.syncnetsService.getActiveSubnets().map((request) => {
615
+ const subscribers = this.gossipsub.getSubscribersWithOutboundStream({
616
+ type: GossipType.sync_committee,
617
+ boundary,
618
+ subnet: request.subnet,
619
+ });
620
+ let peerCount = 0;
621
+ for (const peer of subscribers) {
622
+ if (connectedHealthyPeerIds.has(peer)) peerCount++;
623
+ }
624
+ return {...request, peerCount};
625
+ }),
599
626
  // ignore samplingGroups for pre-fulu forks
600
627
  forkSeq >= ForkSeq.fulu ? this.networkConfig.custodyConfig.sampleGroups : undefined,
601
628
  {
@@ -893,7 +920,7 @@ export class PeerManager {
893
920
  }
894
921
  }
895
922
 
896
- private async goodbyeAndDisconnect(peer: PeerId, goodbye: GoodByeReasonCode): Promise<void> {
923
+ async goodbyeAndDisconnect(peer: PeerId, goodbye: GoodByeReasonCode): Promise<void> {
897
924
  const reason = GOODBYE_KNOWN_CODES[goodbye.toString()] || "";
898
925
  const peerIdStr = peer.toString();
899
926
  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
  }
@@ -24,6 +24,7 @@ import {
24
24
  deneb,
25
25
  fulu,
26
26
  gloas,
27
+ isGloasBeaconBlock,
27
28
  isGloasDataColumnSidecar,
28
29
  ssz,
29
30
  sszTypesFor,
@@ -65,7 +66,10 @@ import {
65
66
  validateGossipGloasDataColumnSidecar,
66
67
  } from "../../chain/validation/dataColumnSidecar.js";
67
68
  import {validateGossipExecutionPayloadBid} from "../../chain/validation/executionPayloadBid.js";
68
- import {validateGossipExecutionPayloadEnvelope} from "../../chain/validation/executionPayloadEnvelope.js";
69
+ import {
70
+ validateGossipExecutionPayloadEnvelope,
71
+ validateGossipExecutionPayloadEnvelopeSerialized,
72
+ } from "../../chain/validation/executionPayloadEnvelope.js";
69
73
  import {InclusionListValidationResult, validateGossipInclusionList} from "../../chain/validation/inclusionList.js";
70
74
  import {
71
75
  AggregateAndProofValidationResult,
@@ -150,6 +154,31 @@ export function getGossipHandlers(modules: ValidatorFnsModules, options: GossipH
150
154
  */
151
155
  function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): SequentialGossipHandlers {
152
156
  const {chain, config, metrics, logger, core} = modules;
157
+ const incompletePayloadWaits = new WeakSet<PayloadEnvelopeInput>();
158
+
159
+ function scheduleIncompletePayloadEnvelope(payloadInput: PayloadEnvelopeInput, peer: string): void {
160
+ if (payloadInput.isComplete() || incompletePayloadWaits.has(payloadInput)) {
161
+ return;
162
+ }
163
+ incompletePayloadWaits.add(payloadInput);
164
+
165
+ const fork = config.getForkName(payloadInput.slot);
166
+ const cutoffTimeMs = getCutoffTimeMs(chain, payloadInput.slot, config.getPayloadDueMs(fork));
167
+ payloadInput.waitForEnvelopeAndAllData(cutoffTimeMs).catch(() => {
168
+ if (
169
+ payloadInput.isComplete() ||
170
+ chain.seenPayloadEnvelopeInputCache.get(payloadInput.blockRootHex) !== payloadInput
171
+ ) {
172
+ return;
173
+ }
174
+ chain.logger.debug("Payload envelope incomplete at payload deadline", payloadInput.getLogMeta());
175
+ chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
176
+ payloadInput,
177
+ peer,
178
+ source: BlockInputSource.gossip,
179
+ });
180
+ });
181
+ }
153
182
 
154
183
  /**
155
184
  * Add a gossip block to the seen caches. The proposer signature of the block MUST be verified.
@@ -679,10 +708,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
679
708
 
680
709
  // Immediately attempt fetch of data columns from execution engine as the bid contains kzg commitments
681
710
  // which is all the information we need so there is no reason to delay until execution payload arrives
682
- // TODO GLOAS: If we want EL retries after this initial attempt, add an explicit retry policy here
683
- // (for example later in the slot). Do not couple retries to incoming gossip columns.
684
- // Columns fetched here feed payloadInput.addColumn, which resolves waitForAllData for any
685
- // 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.
686
713
  chain.getBlobsTracker.triggerGetBlobs(payloadInput);
687
714
  }
688
715
  })
@@ -692,11 +719,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
692
719
 
693
720
  if (e instanceof BlockError) {
694
721
  switch (e.type.code) {
695
- case BlockErrorCode.DATA_UNAVAILABLE: {
696
- // 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
697
724
  logLevel = LogLevel.debug;
698
725
  break;
699
- }
700
726
  // ALREADY_KNOWN should not happen with ignoreIfKnown=true above
701
727
  // PARENT_BLOCK_UNKNOWN should not happen, we handled this in validateBeaconBlock() function above
702
728
  case BlockErrorCode.ALREADY_KNOWN:
@@ -764,7 +790,12 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
764
790
  // roots per proposer and slot, which bounds full imports over gossip to one alternate
765
791
  chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root) &&
766
792
  // A sibling with an unknown parent cannot be imported, sync fetches it if its branch becomes relevant
767
- chain.forkChoice.getBlockHexDefaultStatus(toRootHex(signedBlock.message.parentRoot)) !== null
793
+ chain.forkChoice.getBlockHexDefaultStatus(toRootHex(signedBlock.message.parentRoot)) !== null &&
794
+ (!isGloasBeaconBlock(signedBlock.message) ||
795
+ chain.forkChoice.getBlockHexAndBlockHash(
796
+ toRootHex(signedBlock.message.parentRoot),
797
+ toRootHex(signedBlock.message.body.signedExecutionPayloadBid.message.parentBlockHash)
798
+ ) !== null)
768
799
  ) {
769
800
  const blockInput = cacheSignatureVerifiedBlock(
770
801
  signedBlock,
@@ -899,28 +930,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
899
930
  }
900
931
 
901
932
  // NOTE: we do NOT call chain.processExecutionPayload here. That is triggered only by
902
- // envelope arrival (gossip or API). An in-flight importExecutionPayload is awaiting
933
+ // envelope arrival (gossip or API). A pending payload import is awaiting
903
934
  // payloadInput.waitForAllData(); addColumn above will resolve it once hasAllData flips.
904
935
 
905
- if (!payloadInput.isComplete()) {
906
- const cutoffTimeMs = getCutoffTimeMs(chain, dataColumnSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
907
- // do not await here to not delay gossip validation
908
- payloadInput.waitForEnvelopeAndAllData(cutoffTimeMs).catch((_e) => {
909
- chain.logger.debug(
910
- "Waited for envelope and data after receiving gossip column. Cut-off reached so emitting incompletePayloadEnvelope",
911
- {
912
- dataColumnIndex: index,
913
- ...payloadInputMeta,
914
- }
915
- );
916
- // TODO GLOAS: UnknownBlockSync to handle this event
917
- chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
918
- payloadInput,
919
- peer: peerIdStr,
920
- source: BlockInputSource.gossip,
921
- });
922
- });
923
- }
936
+ scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
924
937
  } catch (e) {
925
938
  logger.debug(
926
939
  "Error handling gossip data column",
@@ -1266,6 +1279,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1266
1279
  seenTimestampSec,
1267
1280
  }: GossipHandlerParamGeneric<GossipType.execution_payload>) => {
1268
1281
  const {serializedData} = gossipData;
1282
+ validateGossipExecutionPayloadEnvelopeSerialized(chain, serializedData);
1269
1283
  const signedEnvelope = sszDeserialize(topic, serializedData);
1270
1284
  const envelope = signedEnvelope.message;
1271
1285
 
@@ -1318,17 +1332,23 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1318
1332
  });
1319
1333
  }
1320
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
+
1321
1348
  // Handler - deferred to next event loop so the validation result propagates first
1322
1349
  callInNextEventLoop(() => {
1323
1350
  try {
1324
- chain.serializedCache.set(signedEnvelope, serializedData);
1325
-
1326
- payloadInput.addPayloadEnvelope({
1327
- envelope: signedEnvelope,
1328
- source: PayloadEnvelopeInputSource.gossip,
1329
- seenTimestampSec,
1330
- peerIdStr,
1331
- });
1351
+ scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
1332
1352
 
1333
1353
  chain.emitter.emit(routes.events.EventType.executionPayloadGossip, {
1334
1354
  slot,
@@ -1337,12 +1357,18 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1337
1357
  blockRoot: blockRootHex,
1338
1358
  });
1339
1359
 
1340
- 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) => {
1341
1363
  // Adjust verbosity based on error type
1342
1364
  let logLevel: LogLevel;
1343
1365
 
1344
1366
  if (e instanceof PayloadError) {
1345
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;
1346
1372
  // BLOCK_NOT_IN_FORK_CHOICE should not happen, validateGossipExecutionPayloadEnvelope above
1347
1373
  // already verified the block is in fork choice
1348
1374
  case PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE:
@@ -1351,11 +1377,14 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1351
1377
  // Errors might indicate an issue with our node or the connected EL client
1352
1378
  logLevel = LogLevel.error;
1353
1379
  break;
1354
- // INVALID_SIGNATURE should not happen, signature is verified during gossip validation
1380
+ // INVALID_SIGNATURE only happens for an envelope added by another source
1355
1381
  case PayloadErrorCode.INVALID_SIGNATURE:
1356
1382
  case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
1357
1383
  case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
1358
- core.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadGossipPayload");
1384
+ // Penalize only when the stored envelope is the one this peer sent, not one added by another source
1385
+ if (validSignature) {
1386
+ core.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadGossipPayload");
1387
+ }
1359
1388
  // The builder may have signed another envelope that is valid, keeping this one would make
1360
1389
  // by-root and range sync reuse it and never import the payload
1361
1390
  chain.seenPayloadEnvelopeInputCache.removeInvalid(payloadInput);
@@ -867,19 +867,20 @@ export class NetworkProcessor {
867
867
  const nowSec = Date.now() / 1000;
868
868
  const minSlot = clockSlot - MAX_UNKNOWN_ROOTS_SLOT_CACHE_SIZE;
869
869
 
870
- for (const [slot, searchedRoots] of this.searchedRootsBySlot) {
870
+ for (const [slot, bufferedRoots] of this.bufferedRootsBySlot) {
871
871
  if (slot > minSlot) continue;
872
872
 
873
- // expire messages awaiting an unknown block for these roots. Only roots this slot did a BLOCK search
874
- // for (blockPeerIds set) have block waits keyed here; skipping the rest avoids deleting a payload wait
875
- // that a newer slot created for the same root (block/envelope searches share searchedRootsBySlot).
876
- for (const [rootHex, entry] of searchedRoots) {
877
- if (entry.blockPeerIds === undefined) continue;
873
+ for (const rootHex of bufferedRoots) {
878
874
  const messagesByTopic = this.awaitingMessagesByBlockRoot.get(rootHex);
879
875
  if (messagesByTopic === undefined) continue;
880
- let removed = 0;
876
+ let remaining = 0;
881
877
  for (const messages of messagesByTopic.values()) {
882
878
  for (const message of messages) {
879
+ // the same root may be buffered again from a newer slot, keep those messages.
880
+ // msgSlot is always set before buffering, a missing one expires rather than leaks
881
+ if ((message.msgSlot ?? minSlot) > minSlot) continue;
882
+ messages.delete(message);
883
+ this.awaitingBlockMessageCount--;
883
884
  const topicType = message.topic.type;
884
885
  this.metrics?.awaitingBlockGossipMessages.reject.inc({
885
886
  topic: topicType,
@@ -891,22 +892,22 @@ export class NetworkProcessor {
891
892
  );
892
893
  // No need to report the dropped job to gossip. It will be eventually pruned from the mcache
893
894
  }
894
- removed += messages.size;
895
- }
896
- if (this.awaitingMessagesByBlockRoot.delete(rootHex)) {
897
- this.awaitingBlockMessageCount -= removed;
895
+ remaining += messages.size;
898
896
  }
897
+ if (remaining === 0) this.awaitingMessagesByBlockRoot.delete(rootHex);
899
898
  }
900
899
 
901
- // expire messages awaiting an unknown payload envelope for these roots. Symmetric to the block pass:
902
- // only roots this slot did an ENVELOPE search for (envelopePeerIds set) have payload waits keyed here.
903
- for (const [rootHex, entry] of searchedRoots) {
904
- if (entry.envelopePeerIds === undefined) continue;
900
+ for (const rootHex of bufferedRoots) {
905
901
  const messagesByTopic = this.awaitingMessagesByPayloadBlockRoot.get(rootHex);
906
902
  if (messagesByTopic === undefined) continue;
907
- let removed = 0;
903
+ let remaining = 0;
908
904
  for (const messages of messagesByTopic.values()) {
909
905
  for (const message of messages) {
906
+ // the same root may be buffered again from a newer slot, keep those messages.
907
+ // msgSlot is always set before buffering, a missing one expires rather than leaks
908
+ if ((message.msgSlot ?? minSlot) > minSlot) continue;
909
+ messages.delete(message);
910
+ this.awaitingPayloadMessageCount--;
910
911
  const topicType = message.topic.type;
911
912
  this.metrics?.awaitingPayloadGossipMessages.reject.inc({
912
913
  topic: topicType,
@@ -918,18 +919,16 @@ export class NetworkProcessor {
918
919
  );
919
920
  // No need to report the dropped job to gossip. It will be eventually pruned from the mcache
920
921
  }
921
- removed += messages.size;
922
- }
923
- if (this.awaitingMessagesByPayloadBlockRoot.delete(rootHex)) {
924
- this.awaitingPayloadMessageCount -= removed;
922
+ remaining += messages.size;
925
923
  }
924
+ if (remaining === 0) this.awaitingMessagesByPayloadBlockRoot.delete(rootHex);
926
925
  }
927
926
 
928
- this.searchedRootsBySlot.delete(slot);
927
+ this.bufferedRootsBySlot.delete(slot);
929
928
  }
930
929
 
931
- for (const slot of this.bufferedRootsBySlot.keys()) {
932
- if (slot <= minSlot) this.bufferedRootsBySlot.delete(slot);
930
+ for (const slot of this.searchedRootsBySlot.keys()) {
931
+ if (slot <= minSlot) this.searchedRootsBySlot.delete(slot);
933
932
  }
934
933
 
935
934
  for (const [peer, slot] of this.fatalPeers) {
@@ -11,7 +11,7 @@ export type GossipAttestationsWork = {
11
11
  export type PendingGossipsubMessage = {
12
12
  topic: GossipTopic;
13
13
  msg: Message;
14
- // only available for beacon_attestation and aggregate_and_proof
14
+ // set for every topic with a slot, held messages expire by it
15
15
  msgSlot?: Slot;
16
16
  msgId: string;
17
17
  propagationSource: PeerIdStr;