@lodestar/beacon-node 1.50.0-dev.456b75a81e → 1.50.0-dev.4b00f7bf39

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 (389) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +13 -3
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/index.js +13 -0
  6. package/lib/api/impl/beacon/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  8. package/lib/api/impl/beacon/state/index.js +28 -6
  9. package/lib/api/impl/beacon/state/index.js.map +1 -1
  10. package/lib/api/impl/debug/index.d.ts.map +1 -1
  11. package/lib/api/impl/debug/index.js +26 -18
  12. package/lib/api/impl/debug/index.js.map +1 -1
  13. package/lib/api/impl/validator/index.d.ts +1 -0
  14. package/lib/api/impl/validator/index.d.ts.map +1 -1
  15. package/lib/api/impl/validator/index.js +80 -18
  16. package/lib/api/impl/validator/index.js.map +1 -1
  17. package/lib/chain/ColumnReconstructionTracker.d.ts +0 -2
  18. package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
  19. package/lib/chain/ColumnReconstructionTracker.js +4 -5
  20. package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
  21. package/lib/chain/archiveStore/archiveStore.d.ts +5 -0
  22. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  23. package/lib/chain/archiveStore/archiveStore.js +14 -24
  24. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  25. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts +2 -2
  26. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
  27. package/lib/chain/archiveStore/historicalState/getHistoricalState.js +5 -7
  28. package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
  29. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -1
  30. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
  31. package/lib/chain/archiveStore/historicalState/types.d.ts +2 -2
  32. package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
  33. package/lib/chain/archiveStore/historicalState/worker.js +1 -1
  34. package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
  35. package/lib/chain/archiveStore/interface.d.ts +1 -1
  36. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  37. package/lib/chain/archiveStore/utils/pruneHistory.d.ts +1 -1
  38. package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
  39. package/lib/chain/archiveStore/utils/pruneHistory.js +2 -1
  40. package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
  41. package/lib/chain/beaconProposerCache.d.ts +6 -0
  42. package/lib/chain/beaconProposerCache.d.ts.map +1 -1
  43. package/lib/chain/beaconProposerCache.js +16 -0
  44. package/lib/chain/beaconProposerCache.js.map +1 -1
  45. package/lib/chain/blocks/blockInput/blockInput.d.ts +1 -1
  46. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  47. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  48. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  49. package/lib/chain/blocks/importBlock.js +21 -12
  50. package/lib/chain/blocks/importBlock.js.map +1 -1
  51. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +2 -1
  52. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  53. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  54. package/lib/chain/blocks/verifyBlock.js +7 -7
  55. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  56. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts +2 -1
  57. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  58. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +5 -4
  59. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  60. package/lib/chain/chain.d.ts +10 -5
  61. package/lib/chain/chain.d.ts.map +1 -1
  62. package/lib/chain/chain.js +105 -35
  63. package/lib/chain/chain.js.map +1 -1
  64. package/lib/chain/emitter.d.ts +7 -1
  65. package/lib/chain/emitter.d.ts.map +1 -1
  66. package/lib/chain/emitter.js +5 -0
  67. package/lib/chain/emitter.js.map +1 -1
  68. package/lib/chain/errors/envelopeReconstructionError.d.ts +5 -0
  69. package/lib/chain/errors/envelopeReconstructionError.d.ts.map +1 -1
  70. package/lib/chain/errors/envelopeReconstructionError.js +2 -0
  71. package/lib/chain/errors/envelopeReconstructionError.js.map +1 -1
  72. package/lib/chain/errors/gossipValidation.d.ts +1 -0
  73. package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
  74. package/lib/chain/errors/gossipValidation.js +1 -0
  75. package/lib/chain/errors/gossipValidation.js.map +1 -1
  76. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  77. package/lib/chain/forkChoice/index.js +2 -0
  78. package/lib/chain/forkChoice/index.js.map +1 -1
  79. package/lib/chain/interface.d.ts +6 -3
  80. package/lib/chain/interface.d.ts.map +1 -1
  81. package/lib/chain/opPools/aggregatedAttestationPool.d.ts +4 -2
  82. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  83. package/lib/chain/opPools/aggregatedAttestationPool.js +30 -8
  84. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  85. package/lib/chain/opPools/opPool.d.ts.map +1 -1
  86. package/lib/chain/opPools/opPool.js +1 -23
  87. package/lib/chain/opPools/opPool.js.map +1 -1
  88. package/lib/chain/opPools/proposerPreferencesPool.d.ts +8 -4
  89. package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
  90. package/lib/chain/opPools/proposerPreferencesPool.js +27 -12
  91. package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
  92. package/lib/chain/opPools/utils.d.ts +11 -0
  93. package/lib/chain/opPools/utils.d.ts.map +1 -1
  94. package/lib/chain/opPools/utils.js +22 -0
  95. package/lib/chain/opPools/utils.js.map +1 -1
  96. package/lib/chain/options.d.ts +2 -1
  97. package/lib/chain/options.d.ts.map +1 -1
  98. package/lib/chain/options.js +1 -1
  99. package/lib/chain/options.js.map +1 -1
  100. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  101. package/lib/chain/prepareNextSlot.js +20 -8
  102. package/lib/chain/prepareNextSlot.js.map +1 -1
  103. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  104. package/lib/chain/produceBlock/computeNewStateRoot.js +1 -1
  105. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  106. package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -1
  107. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  108. package/lib/chain/produceBlock/produceBlockBody.js +54 -36
  109. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  110. package/lib/chain/regen/regen.d.ts +2 -0
  111. package/lib/chain/regen/regen.d.ts.map +1 -1
  112. package/lib/chain/regen/regen.js +10 -4
  113. package/lib/chain/regen/regen.js.map +1 -1
  114. package/lib/chain/reprocess.d.ts +2 -1
  115. package/lib/chain/reprocess.d.ts.map +1 -1
  116. package/lib/chain/reprocess.js +2 -1
  117. package/lib/chain/reprocess.js.map +1 -1
  118. package/lib/chain/seenCache/seenGossipBlockInput.d.ts +7 -0
  119. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  120. package/lib/chain/seenCache/seenGossipBlockInput.js +22 -1
  121. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  122. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +9 -2
  123. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  124. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +23 -13
  125. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  126. package/lib/chain/shufflingCache.d.ts +18 -8
  127. package/lib/chain/shufflingCache.d.ts.map +1 -1
  128. package/lib/chain/shufflingCache.js +72 -18
  129. package/lib/chain/shufflingCache.js.map +1 -1
  130. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  131. package/lib/chain/stateCache/persistentCheckpointsCache.js +1 -1
  132. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  133. package/lib/chain/validatorMonitor.d.ts +5 -1
  134. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  135. package/lib/chain/validatorMonitor.js +70 -58
  136. package/lib/chain/validatorMonitor.js.map +1 -1
  137. package/lib/constants/constants.d.ts +1 -0
  138. package/lib/constants/constants.d.ts.map +1 -1
  139. package/lib/constants/constants.js +1 -0
  140. package/lib/constants/constants.js.map +1 -1
  141. package/lib/db/beacon.d.ts +4 -1
  142. package/lib/db/beacon.d.ts.map +1 -1
  143. package/lib/db/beacon.js +6 -1
  144. package/lib/db/beacon.js.map +1 -1
  145. package/lib/db/buckets.d.ts +3 -1
  146. package/lib/db/buckets.d.ts.map +1 -1
  147. package/lib/db/buckets.js +2 -0
  148. package/lib/db/buckets.js.map +1 -1
  149. package/lib/db/interface.d.ts +4 -1
  150. package/lib/db/interface.d.ts.map +1 -1
  151. package/lib/db/repositories/blockArchive.js +2 -2
  152. package/lib/db/repositories/blockArchive.js.map +1 -1
  153. package/lib/db/repositories/blockArchiveIndex.d.ts +3 -3
  154. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  155. package/lib/db/repositories/blockArchiveIndex.js +1 -2
  156. package/lib/db/repositories/blockArchiveIndex.js.map +1 -1
  157. package/lib/db/repositories/earliestAvailableSlot.d.ts +11 -0
  158. package/lib/db/repositories/earliestAvailableSlot.d.ts.map +1 -0
  159. package/lib/db/repositories/earliestAvailableSlot.js +19 -0
  160. package/lib/db/repositories/earliestAvailableSlot.js.map +1 -0
  161. package/lib/db/repositories/index.d.ts +1 -0
  162. package/lib/db/repositories/index.d.ts.map +1 -1
  163. package/lib/db/repositories/index.js +1 -0
  164. package/lib/db/repositories/index.js.map +1 -1
  165. package/lib/db/repositories/proposerPreferences.d.ts +14 -0
  166. package/lib/db/repositories/proposerPreferences.d.ts.map +1 -0
  167. package/lib/db/repositories/proposerPreferences.js +21 -0
  168. package/lib/db/repositories/proposerPreferences.js.map +1 -0
  169. package/lib/execution/engine/blobVersionedHashes.d.ts +9 -0
  170. package/lib/execution/engine/blobVersionedHashes.d.ts.map +1 -0
  171. package/lib/execution/engine/blobVersionedHashes.js +74 -0
  172. package/lib/execution/engine/blobVersionedHashes.js.map +1 -0
  173. package/lib/execution/engine/disabled.d.ts +0 -2
  174. package/lib/execution/engine/disabled.d.ts.map +1 -1
  175. package/lib/execution/engine/disabled.js +0 -6
  176. package/lib/execution/engine/disabled.js.map +1 -1
  177. package/lib/execution/engine/http.d.ts +46 -16
  178. package/lib/execution/engine/http.d.ts.map +1 -1
  179. package/lib/execution/engine/http.js +236 -213
  180. package/lib/execution/engine/http.js.map +1 -1
  181. package/lib/execution/engine/index.d.ts +3 -2
  182. package/lib/execution/engine/index.d.ts.map +1 -1
  183. package/lib/execution/engine/index.js +33 -8
  184. package/lib/execution/engine/index.js.map +1 -1
  185. package/lib/execution/engine/interface.d.ts +2 -4
  186. package/lib/execution/engine/interface.d.ts.map +1 -1
  187. package/lib/execution/engine/jsonRpcHttpClient.d.ts.map +1 -1
  188. package/lib/execution/engine/jsonRpcHttpClient.js +14 -4
  189. package/lib/execution/engine/jsonRpcHttpClient.js.map +1 -1
  190. package/lib/execution/engine/jsonRpcTransport.d.ts +25 -0
  191. package/lib/execution/engine/jsonRpcTransport.d.ts.map +1 -0
  192. package/lib/execution/engine/jsonRpcTransport.js +158 -0
  193. package/lib/execution/engine/jsonRpcTransport.js.map +1 -0
  194. package/lib/execution/engine/mock.d.ts +0 -2
  195. package/lib/execution/engine/mock.d.ts.map +1 -1
  196. package/lib/execution/engine/mock.js +0 -8
  197. package/lib/execution/engine/mock.js.map +1 -1
  198. package/lib/execution/engine/restHttpClient.d.ts +71 -0
  199. package/lib/execution/engine/restHttpClient.d.ts.map +1 -0
  200. package/lib/execution/engine/restHttpClient.js +201 -0
  201. package/lib/execution/engine/restHttpClient.js.map +1 -0
  202. package/lib/execution/engine/restTransport.d.ts +48 -0
  203. package/lib/execution/engine/restTransport.d.ts.map +1 -0
  204. package/lib/execution/engine/restTransport.js +411 -0
  205. package/lib/execution/engine/restTransport.js.map +1 -0
  206. package/lib/execution/engine/sszTypes.d.ts +1261 -0
  207. package/lib/execution/engine/sszTypes.d.ts.map +1 -0
  208. package/lib/execution/engine/sszTypes.js +216 -0
  209. package/lib/execution/engine/sszTypes.js.map +1 -0
  210. package/lib/execution/engine/transport.d.ts +39 -0
  211. package/lib/execution/engine/transport.d.ts.map +1 -0
  212. package/lib/execution/engine/transport.js +2 -0
  213. package/lib/execution/engine/transport.js.map +1 -0
  214. package/lib/execution/engine/transportMetrics.d.ts +5 -1
  215. package/lib/execution/engine/transportMetrics.d.ts.map +1 -1
  216. package/lib/execution/engine/types.d.ts +2 -8
  217. package/lib/execution/engine/types.d.ts.map +1 -1
  218. package/lib/execution/engine/types.js +31 -63
  219. package/lib/execution/engine/types.js.map +1 -1
  220. package/lib/execution/engine/utils.d.ts.map +1 -1
  221. package/lib/execution/engine/utils.js +9 -2
  222. package/lib/execution/engine/utils.js.map +1 -1
  223. package/lib/metrics/metrics/lodestar.d.ts +14 -0
  224. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  225. package/lib/metrics/metrics/lodestar.js +29 -1
  226. package/lib/metrics/metrics/lodestar.js.map +1 -1
  227. package/lib/metrics/metrics.d.ts +7 -3
  228. package/lib/metrics/metrics.d.ts.map +1 -1
  229. package/lib/metrics/metrics.js +4 -4
  230. package/lib/metrics/metrics.js.map +1 -1
  231. package/lib/network/core/events.d.ts +5 -1
  232. package/lib/network/core/events.d.ts.map +1 -1
  233. package/lib/network/core/events.js +8 -0
  234. package/lib/network/core/events.js.map +1 -1
  235. package/lib/network/gossip/topic.d.ts +0 -14
  236. package/lib/network/gossip/topic.d.ts.map +1 -1
  237. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  238. package/lib/network/processor/gossipHandlers.js +63 -64
  239. package/lib/network/processor/gossipHandlers.js.map +1 -1
  240. package/lib/network/processor/gossipValidatorFn.d.ts +4 -2
  241. package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
  242. package/lib/network/processor/gossipValidatorFn.js +6 -2
  243. package/lib/network/processor/gossipValidatorFn.js.map +1 -1
  244. package/lib/network/processor/index.d.ts +8 -0
  245. package/lib/network/processor/index.d.ts.map +1 -1
  246. package/lib/network/processor/index.js +52 -5
  247. package/lib/network/processor/index.js.map +1 -1
  248. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +1 -1
  249. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  250. package/lib/network/reqresp/rateLimit.js +2 -2
  251. package/lib/network/reqresp/rateLimit.js.map +1 -1
  252. package/lib/network/subnets/attnetsService.d.ts.map +1 -1
  253. package/lib/network/subnets/attnetsService.js +3 -1
  254. package/lib/network/subnets/attnetsService.js.map +1 -1
  255. package/lib/node/nodejs.d.ts +3 -1
  256. package/lib/node/nodejs.d.ts.map +1 -1
  257. package/lib/node/nodejs.js +27 -4
  258. package/lib/node/nodejs.js.map +1 -1
  259. package/lib/node/notifier.d.ts.map +1 -1
  260. package/lib/node/notifier.js +12 -13
  261. package/lib/node/notifier.js.map +1 -1
  262. package/lib/node/options.d.ts +3 -2
  263. package/lib/node/options.d.ts.map +1 -1
  264. package/lib/node/options.js +2 -2
  265. package/lib/node/options.js.map +1 -1
  266. package/lib/sync/range/batch.d.ts +11 -5
  267. package/lib/sync/range/batch.d.ts.map +1 -1
  268. package/lib/sync/range/batch.js +21 -17
  269. package/lib/sync/range/batch.js.map +1 -1
  270. package/lib/sync/range/chain.d.ts +4 -4
  271. package/lib/sync/range/chain.d.ts.map +1 -1
  272. package/lib/sync/range/chain.js +12 -6
  273. package/lib/sync/range/chain.js.map +1 -1
  274. package/lib/sync/range/range.d.ts.map +1 -1
  275. package/lib/sync/range/range.js +75 -29
  276. package/lib/sync/range/range.js.map +1 -1
  277. package/lib/sync/unknownBlock.d.ts +5 -2
  278. package/lib/sync/unknownBlock.d.ts.map +1 -1
  279. package/lib/sync/unknownBlock.js +52 -26
  280. package/lib/sync/unknownBlock.js.map +1 -1
  281. package/lib/sync/utils/downloadByRange.d.ts +38 -14
  282. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  283. package/lib/sync/utils/downloadByRange.js +84 -39
  284. package/lib/sync/utils/downloadByRange.js.map +1 -1
  285. package/lib/util/asyncIterableToEvents.d.ts +10 -2
  286. package/lib/util/asyncIterableToEvents.d.ts.map +1 -1
  287. package/lib/util/asyncIterableToEvents.js +29 -3
  288. package/lib/util/asyncIterableToEvents.js.map +1 -1
  289. package/lib/util/clock.d.ts.map +1 -1
  290. package/lib/util/clock.js +3 -4
  291. package/lib/util/clock.js.map +1 -1
  292. package/lib/util/execution.d.ts +9 -11
  293. package/lib/util/execution.d.ts.map +1 -1
  294. package/lib/util/execution.js +5 -1
  295. package/lib/util/execution.js.map +1 -1
  296. package/lib/util/metadata.d.ts.map +1 -1
  297. package/lib/util/metadata.js +2 -1
  298. package/lib/util/metadata.js.map +1 -1
  299. package/lib/util/sszBytes.d.ts +2 -2
  300. package/lib/util/sszBytes.d.ts.map +1 -1
  301. package/lib/util/sszBytes.js +22 -14
  302. package/lib/util/sszBytes.js.map +1 -1
  303. package/package.json +18 -17
  304. package/src/api/impl/beacon/blocks/index.ts +17 -7
  305. package/src/api/impl/beacon/index.ts +15 -0
  306. package/src/api/impl/beacon/state/index.ts +43 -6
  307. package/src/api/impl/debug/index.ts +28 -19
  308. package/src/api/impl/validator/index.ts +102 -21
  309. package/src/chain/ColumnReconstructionTracker.ts +4 -6
  310. package/src/chain/archiveStore/archiveStore.ts +19 -25
  311. package/src/chain/archiveStore/historicalState/getHistoricalState.ts +5 -7
  312. package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -1
  313. package/src/chain/archiveStore/historicalState/types.ts +2 -2
  314. package/src/chain/archiveStore/historicalState/worker.ts +1 -2
  315. package/src/chain/archiveStore/interface.ts +1 -1
  316. package/src/chain/archiveStore/utils/pruneHistory.ts +4 -1
  317. package/src/chain/beaconProposerCache.ts +19 -1
  318. package/src/chain/blocks/blockInput/blockInput.ts +1 -1
  319. package/src/chain/blocks/importBlock.ts +25 -11
  320. package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
  321. package/src/chain/blocks/verifyBlock.ts +8 -6
  322. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +6 -3
  323. package/src/chain/chain.ts +135 -37
  324. package/src/chain/emitter.ts +7 -1
  325. package/src/chain/errors/envelopeReconstructionError.ts +3 -0
  326. package/src/chain/errors/gossipValidation.ts +1 -0
  327. package/src/chain/forkChoice/index.ts +2 -0
  328. package/src/chain/interface.ts +7 -3
  329. package/src/chain/opPools/aggregatedAttestationPool.ts +34 -10
  330. package/src/chain/opPools/opPool.ts +1 -31
  331. package/src/chain/opPools/proposerPreferencesPool.ts +34 -11
  332. package/src/chain/opPools/utils.ts +31 -0
  333. package/src/chain/options.ts +3 -3
  334. package/src/chain/prepareNextSlot.ts +28 -9
  335. package/src/chain/produceBlock/computeNewStateRoot.ts +10 -3
  336. package/src/chain/produceBlock/produceBlockBody.ts +86 -40
  337. package/src/chain/regen/regen.ts +12 -4
  338. package/src/chain/reprocess.ts +2 -1
  339. package/src/chain/seenCache/seenGossipBlockInput.ts +25 -1
  340. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +31 -13
  341. package/src/chain/shufflingCache.ts +84 -22
  342. package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
  343. package/src/chain/validatorMonitor.ts +82 -61
  344. package/src/constants/constants.ts +1 -0
  345. package/src/db/beacon.ts +6 -0
  346. package/src/db/buckets.ts +2 -0
  347. package/src/db/interface.ts +4 -0
  348. package/src/db/repositories/blockArchive.ts +2 -2
  349. package/src/db/repositories/blockArchiveIndex.ts +2 -3
  350. package/src/db/repositories/earliestAvailableSlot.ts +19 -0
  351. package/src/db/repositories/index.ts +1 -0
  352. package/src/db/repositories/proposerPreferences.ts +23 -0
  353. package/src/execution/engine/blobVersionedHashes.ts +72 -0
  354. package/src/execution/engine/disabled.ts +0 -8
  355. package/src/execution/engine/http.ts +304 -300
  356. package/src/execution/engine/index.ts +42 -7
  357. package/src/execution/engine/interface.ts +2 -6
  358. package/src/execution/engine/jsonRpcHttpClient.ts +12 -5
  359. package/src/execution/engine/jsonRpcTransport.ts +247 -0
  360. package/src/execution/engine/mock.ts +1 -19
  361. package/src/execution/engine/restHttpClient.ts +269 -0
  362. package/src/execution/engine/restTransport.ts +575 -0
  363. package/src/execution/engine/sszTypes.ts +354 -0
  364. package/src/execution/engine/transport.ts +61 -0
  365. package/src/execution/engine/transportMetrics.ts +2 -1
  366. package/src/execution/engine/types.ts +42 -90
  367. package/src/execution/engine/utils.ts +12 -2
  368. package/src/metrics/metrics/lodestar.ts +30 -1
  369. package/src/metrics/metrics.ts +21 -6
  370. package/src/network/core/events.ts +16 -1
  371. package/src/network/processor/gossipHandlers.ts +94 -77
  372. package/src/network/processor/gossipValidatorFn.ts +12 -2
  373. package/src/network/processor/index.ts +58 -5
  374. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +1 -1
  375. package/src/network/reqresp/rateLimit.ts +2 -2
  376. package/src/network/subnets/attnetsService.ts +8 -3
  377. package/src/node/nodejs.ts +35 -3
  378. package/src/node/notifier.ts +14 -13
  379. package/src/node/options.ts +10 -1
  380. package/src/sync/range/batch.ts +25 -19
  381. package/src/sync/range/chain.ts +15 -8
  382. package/src/sync/range/range.ts +76 -30
  383. package/src/sync/unknownBlock.ts +65 -27
  384. package/src/sync/utils/downloadByRange.ts +123 -58
  385. package/src/util/asyncIterableToEvents.ts +44 -5
  386. package/src/util/clock.ts +3 -4
  387. package/src/util/execution.ts +16 -8
  388. package/src/util/metadata.ts +2 -1
  389. package/src/util/sszBytes.ts +25 -12
@@ -8,6 +8,7 @@ import {
8
8
  JsonRpcHttpClientEvent,
9
9
  JsonRpcHttpClientEventEmitter,
10
10
  } from "./jsonRpcHttpClient.js";
11
+ import {EngineRestError, EngineRestResponseError} from "./restHttpClient.js";
11
12
 
12
13
  /** QUANTITY as defined in ethereum execution layer JSON RPC https://eth.wiki/json-rpc/API */
13
14
  export type QUANTITY = string;
@@ -191,12 +192,21 @@ function getExecutionEngineStateForPayloadError(
191
192
  return oldState;
192
193
  }
193
194
 
195
+ if (payloadError instanceof EngineRestError && (payloadError.status === 401 || payloadError.status === 403)) {
196
+ return ExecutionEngineState.AUTH_FAILED;
197
+ }
198
+
194
199
  // Originally this case was handled with {status: ExecutePayloadStatus.ELERROR}
195
- if (payloadError instanceof HttpRpcError || payloadError instanceof ErrorJsonRpcResponse) {
200
+ if (
201
+ payloadError instanceof HttpRpcError ||
202
+ payloadError instanceof ErrorJsonRpcResponse ||
203
+ payloadError instanceof EngineRestError ||
204
+ payloadError instanceof EngineRestResponseError
205
+ ) {
196
206
  return ExecutionEngineState.SYNCING;
197
207
  }
198
208
 
199
- if (payloadError && isFetchError(payloadError) && HTTP_FATAL_ERROR_CODES.includes(payloadError.code)) {
209
+ if (isFetchError(payloadError) && HTTP_FATAL_ERROR_CODES.includes(payloadError.code)) {
200
210
  return ExecutionEngineState.OFFLINE;
201
211
  }
202
212
 
@@ -20,6 +20,7 @@ import {InsertOutcome} from "../../chain/opPools/types.js";
20
20
  import {RegenCaller, RegenFnName} from "../../chain/regen/interface.js";
21
21
  import {ReprocessStatus} from "../../chain/reprocess.js";
22
22
  import {RejectReason} from "../../chain/seenCache/seenAttestationData.js";
23
+ import type {ShufflingPromiseCancelReason} from "../../chain/shufflingCache.js";
23
24
  import {CacheItemType} from "../../chain/stateCache/types.js";
24
25
  import {OpSource} from "../../chain/validatorMonitor.js";
25
26
  import type {FlatFileStoreOperation} from "../../db/flatFileStore/metrics.js";
@@ -1176,6 +1177,11 @@ export function createLodestarMetrics(
1176
1177
  help: "The total result of calling notifyForkchoiceUpdate execution engine api",
1177
1178
  labelNames: ["result"],
1178
1179
  }),
1180
+ engineApiRequests: register.counter<{transport: string}>({
1181
+ name: "lodestar_execution_engine_api_requests_total",
1182
+ help: "Total engine API requests by transport",
1183
+ labelNames: ["transport"],
1184
+ }),
1179
1185
  opPool: {
1180
1186
  aggregatedAttestationPool: {
1181
1187
  size: register.gauge({
@@ -1281,6 +1287,10 @@ export function createLodestarMetrics(
1281
1287
  name: "lodestar_oppool_aggregated_attestation_pool_packed_attestations_seen_committees_total",
1282
1288
  help: "Total number of committees for which all members are seen when producing packed attestations",
1283
1289
  }),
1290
+ missingShufflingCommittees: register.gauge({
1291
+ name: "lodestar_oppool_aggregated_attestation_pool_packed_attestations_missing_shuffling_committees_total",
1292
+ help: "Total number of committees skipped due to missing shuffling when producing packed attestations",
1293
+ }),
1284
1294
  },
1285
1295
  },
1286
1296
  attestationPool: {
@@ -1614,6 +1624,19 @@ export function createLodestarMetrics(
1614
1624
  name: "lodestar_shuffling_cache_size",
1615
1625
  help: "Shuffling cache size",
1616
1626
  }),
1627
+ epochs: register.gauge({
1628
+ name: "lodestar_shuffling_cache_epochs",
1629
+ help: "Number of epochs in shuffling cache",
1630
+ }),
1631
+ prunedShufflings: register.counter({
1632
+ name: "lodestar_shuffling_cache_pruned_shufflings_total",
1633
+ help: "Total number of shufflings pruned from shuffling cache",
1634
+ }),
1635
+ cancelledPromises: register.counter<{reason: ShufflingPromiseCancelReason}>({
1636
+ name: "lodestar_shuffling_cache_cancelled_promises_total",
1637
+ help: "Total number of shuffling promises resolved with null",
1638
+ labelNames: ["reason"],
1639
+ }),
1617
1640
  insertPromiseCount: register.gauge({
1618
1641
  name: "lodestar_shuffling_cache_insert_promise_count",
1619
1642
  help: "Total number of times insertPromise is called",
@@ -2038,11 +2061,17 @@ export function createLodestarMetrics(
2038
2061
  }),
2039
2062
  streamTime: register.histogram<{routeId: string}>({
2040
2063
  name: "lodestar_execution_engine_http_client_stream_time_seconds",
2041
- help: "ExecutionEngineHttp client - streaming time by routeId",
2064
+ help: "ExecutionEngineHttp client - response body consumption time, including failures and excluding parsing",
2042
2065
  labelNames: ["routeId"],
2043
2066
  // Provide max resolution on problematic values around 1 second
2044
2067
  buckets: [0.1, 0.5, 1, 2, 5, 15],
2045
2068
  }),
2069
+ responseParseTime: register.histogram<{routeId: string; encoding: "json" | "ssz"}>({
2070
+ name: "lodestar_execution_engine_http_client_response_parse_time_seconds",
2071
+ help: "ExecutionEngineHttp client - JSON.parse or SSZ deserialize time, including failures, excluding body reads and subsequent value conversion",
2072
+ labelNames: ["routeId", "encoding"],
2073
+ buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1],
2074
+ }),
2046
2075
  requestErrors: register.gauge<{routeId: string}>({
2047
2076
  name: "lodestar_execution_engine_http_client_request_errors_total",
2048
2077
  help: "ExecutionEngineHttp client - total count of request errors",
@@ -9,27 +9,42 @@ import {RegistryMetricCreator} from "./utils/registryMetricCreator.js";
9
9
 
10
10
  export type Metrics = BeaconMetrics &
11
11
  ForkChoiceMetrics &
12
- BeaconStateTransitionMetrics &
13
- LodestarMetrics & {register: RegistryMetricCreator; close: () => void};
12
+ LodestarMetrics & {
13
+ /** Null when we use native state transition metrics instead */
14
+ stateTransition: BeaconStateTransitionMetrics | null;
15
+ register: RegistryMetricCreator;
16
+ close: () => void;
17
+ };
18
+
19
+ export type CreateMetricsOptions = {
20
+ /*
21
+ * Toggle inclusion of state transition metrics.
22
+ *
23
+ * False when native state transition is used, so we
24
+ * can grab metrics from the native implementation instead.
25
+ * */
26
+ includeStateTransitionMetrics?: boolean;
27
+ collectNodeMetrics?: boolean;
28
+ };
14
29
 
15
30
  export function createMetrics(
16
31
  opts: MetricsOptions,
17
32
  genesisTime: number,
18
33
  externalRegistries: Registry[] = [],
19
- {collectNodeMetrics = true}: {collectNodeMetrics?: boolean} = {}
34
+ createOpts: CreateMetricsOptions = {}
20
35
  ): Metrics {
21
36
  const register = new RegistryMetricCreator();
22
37
  const beacon = createBeaconMetrics(register);
23
38
  const forkChoice = getForkChoiceMetrics(register);
24
39
  const lodestar = createLodestarMetrics(register, opts.metadata, genesisTime);
25
- const stateTransition = getMetrics(register);
40
+ const stateTransition = createOpts.includeStateTransitionMetrics === false ? null : getMetrics(register);
26
41
 
27
42
  const onUnhandledRejection = (_error: unknown): void => {
28
43
  lodestar.unhandledPromiseRejections.inc();
29
44
  };
30
45
  process.on("unhandledRejection", onUnhandledRejection);
31
46
 
32
- const nodeJsMetricsClose = collectNodeMetrics ? collectNodeJSMetrics(register) : (): void => {};
47
+ const nodeJsMetricsClose = createOpts.collectNodeMetrics === false ? (): void => {} : collectNodeJSMetrics(register);
33
48
  const close = (): void => {
34
49
  process.removeListener("unhandledRejection", onUnhandledRejection);
35
50
  nodeJsMetricsClose();
@@ -46,7 +61,7 @@ export function createMetrics(
46
61
  ...beacon,
47
62
  ...forkChoice,
48
63
  ...lodestar,
49
- ...stateTransition,
64
+ stateTransition,
50
65
  register,
51
66
  close,
52
67
  };
@@ -1,21 +1,30 @@
1
1
  import EventEmitter from "node:events";
2
2
  import {ResponseIncoming, ResponseOutgoing} from "@lodestar/reqresp";
3
- import {AsyncIterableEventBus, IteratorEvent, RequestEvent} from "../../util/asyncIterableToEvents.js";
3
+ import {
4
+ AsyncIterableEventBus,
5
+ IteratorEvent,
6
+ RequestCancelEvent,
7
+ RequestEvent,
8
+ } from "../../util/asyncIterableToEvents.js";
4
9
  import {StrictEventEmitterSingleArg} from "../../util/strictEvents.js";
5
10
  import {EventDirection} from "../events.js";
6
11
  import {IncomingRequestArgs, OutgoingRequestArgs} from "../reqresp/types.js";
7
12
 
8
13
  export enum ReqRespBridgeEvent {
9
14
  outgoingRequest = "reqresp.outgoingRequest",
15
+ outgoingRequestCancel = "reqresp.outgoingRequestCancel",
10
16
  outgoingResponse = "reqresp.outgoingResponse",
11
17
  incomingRequest = "reqresp.incomingRequest",
18
+ incomingRequestCancel = "reqresp.incomingRequestCancel",
12
19
  incomingResponse = "reqresp.incomingResponse",
13
20
  }
14
21
 
15
22
  export type ReqRespBridgeEventData = {
16
23
  [ReqRespBridgeEvent.outgoingRequest]: RequestEvent<OutgoingRequestArgs>;
24
+ [ReqRespBridgeEvent.outgoingRequestCancel]: RequestCancelEvent;
17
25
  [ReqRespBridgeEvent.outgoingResponse]: IteratorEvent<ResponseOutgoing>;
18
26
  [ReqRespBridgeEvent.incomingRequest]: RequestEvent<IncomingRequestArgs>;
27
+ [ReqRespBridgeEvent.incomingRequestCancel]: RequestCancelEvent;
19
28
  [ReqRespBridgeEvent.incomingResponse]: IteratorEvent<ResponseIncoming>;
20
29
  };
21
30
 
@@ -26,8 +35,10 @@ export class ReqRespBridgeEventBus extends (EventEmitter as {new (): IReqRespBri
26
35
  // NOTE: If the same event is on this two arrays it can create an infinite cycle
27
36
  export const reqRespBridgeEventDirection: Record<ReqRespBridgeEvent, EventDirection> = {
28
37
  [ReqRespBridgeEvent.outgoingRequest]: EventDirection.mainToWorker,
38
+ [ReqRespBridgeEvent.outgoingRequestCancel]: EventDirection.mainToWorker,
29
39
  [ReqRespBridgeEvent.outgoingResponse]: EventDirection.mainToWorker,
30
40
  [ReqRespBridgeEvent.incomingRequest]: EventDirection.workerToMain,
41
+ [ReqRespBridgeEvent.incomingRequestCancel]: EventDirection.workerToMain,
31
42
  [ReqRespBridgeEvent.incomingResponse]: EventDirection.workerToMain,
32
43
  };
33
44
 
@@ -36,8 +47,10 @@ export function getReqRespBridgeReqEvents(
36
47
  ): AsyncIterableEventBus<OutgoingRequestArgs, ResponseIncoming> {
37
48
  return {
38
49
  emitRequest: (data) => events.emit(ReqRespBridgeEvent.outgoingRequest, data),
50
+ emitRequestCancel: (data) => events.emit(ReqRespBridgeEvent.outgoingRequestCancel, data),
39
51
  emitResponse: (data) => events.emit(ReqRespBridgeEvent.incomingResponse, data),
40
52
  onRequest: (cb) => events.on(ReqRespBridgeEvent.outgoingRequest, cb),
53
+ onRequestCancel: (cb) => events.on(ReqRespBridgeEvent.outgoingRequestCancel, cb),
41
54
  onResponse: (cb) => events.on(ReqRespBridgeEvent.incomingResponse, cb),
42
55
  };
43
56
  }
@@ -47,8 +60,10 @@ export function getReqRespBridgeRespEvents(
47
60
  ): AsyncIterableEventBus<IncomingRequestArgs, ResponseOutgoing> {
48
61
  return {
49
62
  emitRequest: (data) => events.emit(ReqRespBridgeEvent.incomingRequest, data),
63
+ emitRequestCancel: (data) => events.emit(ReqRespBridgeEvent.incomingRequestCancel, data),
50
64
  emitResponse: (data) => events.emit(ReqRespBridgeEvent.outgoingResponse, data),
51
65
  onRequest: (cb) => events.on(ReqRespBridgeEvent.incomingRequest, cb),
66
+ onRequestCancel: (cb) => events.on(ReqRespBridgeEvent.incomingRequestCancel, cb),
52
67
  onResponse: (cb) => events.on(ReqRespBridgeEvent.outgoingResponse, cb),
53
68
  };
54
69
  }
@@ -12,9 +12,10 @@ import {
12
12
  isForkPostElectra,
13
13
  isForkPostGloas,
14
14
  } from "@lodestar/params";
15
- import {computeTimeAtSlot} from "@lodestar/state-transition";
15
+ import {computeTimeAtSlot, signedBlockToSignedHeader} from "@lodestar/state-transition";
16
16
  import {
17
17
  Root,
18
+ RootHex,
18
19
  SignedBeaconBlock,
19
20
  SingleAttestation,
20
21
  Slot,
@@ -78,6 +79,7 @@ import {
78
79
  validateGossipSyncCommittee,
79
80
  validateGossipVoluntaryExit,
80
81
  validateSyncCommitteeGossipContributionAndProof,
82
+ verifyBlockProposerSignature,
81
83
  } from "../../chain/validation/index.js";
82
84
  import {validateLightClientFinalityUpdate} from "../../chain/validation/lightClientFinalityUpdate.js";
83
85
  import {validateLightClientOptimisticUpdate} from "../../chain/validation/lightClientOptimisticUpdate.js";
@@ -148,37 +150,16 @@ export function getGossipHandlers(modules: ValidatorFnsModules, options: GossipH
148
150
  function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): SequentialGossipHandlers {
149
151
  const {chain, config, metrics, logger, core} = modules;
150
152
 
151
- async function validateBeaconBlock(
153
+ /**
154
+ * Add a gossip block to the seen caches. The proposer signature of the block MUST be verified.
155
+ */
156
+ function cacheSignatureVerifiedBlock(
152
157
  signedBlock: SignedBeaconBlock,
158
+ blockRootHex: RootHex,
153
159
  fork: ForkName,
154
160
  peerIdStr: string,
155
161
  seenTimestampSec: number
156
- ): Promise<IBlockInput> {
157
- const slot = signedBlock.message.slot;
158
- const forkTypes = config.getForkTypes(slot);
159
- const blockRootHex = toRootHex(forkTypes.BeaconBlock.hashTreeRoot(signedBlock.message));
160
- const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec);
161
- const recvToValLatency = Date.now() / 1000 - seenTimestampSec;
162
-
163
- // always set block to seen cache for all forks so that we don't need to download it
164
- // TODO: validate block before adding to cache
165
- // tracked in https://github.com/ChainSafe/lodestar/issues/7957
166
-
167
- const logCtx = {
168
- slot,
169
- root: blockRootHex,
170
- currentSlot: chain.clock.currentSlot,
171
- peerId: peerIdStr,
172
- delaySec,
173
- recvToValLatency,
174
- };
175
-
176
- logger.debug("Received gossip block", {...logCtx});
177
-
178
- // optimistically add gossip block to the seen cache
179
- // if validation fails, we will NOT forward this gossip block to peers
180
- // - if PARENT_BLOCK_UNKNOWN error, blockInput will then be queued inside BlockInputSync. If the gossip block is really invalid, it will be pruned there
181
- // - if other validator errors, blockInput will stay in the seen cache and will be pruned on finalization
162
+ ): BlockInput {
182
163
  const blockInput = chain.seenBlockInputCache.getByBlock({
183
164
  block: signedBlock,
184
165
  blockRootHex,
@@ -187,8 +168,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
187
168
  peerIdStr,
188
169
  });
189
170
 
190
- // Optimistically seed the payload-envelope cache too, mirroring seenBlockInputCache above.
191
- // This ensures we have PayloadEnvelopeInput, even through "PARENT_BLOCK_UNKNOWN" error
171
+ // Also seed the payload-envelope cache, so we have PayloadEnvelopeInput even through "PARENT_BLOCK_UNKNOWN" error
192
172
  // see https://github.com/ChainSafe/lodestar/issues/9475
193
173
  if (isForkPostGloas(fork)) {
194
174
  chain.seenPayloadEnvelopeInputCache.add({
@@ -202,8 +182,37 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
202
182
  });
203
183
  }
204
184
 
185
+ return blockInput;
186
+ }
187
+
188
+ async function validateBeaconBlock(
189
+ signedBlock: SignedBeaconBlock,
190
+ fork: ForkName,
191
+ peerIdStr: string,
192
+ seenTimestampSec: number
193
+ ): Promise<IBlockInput> {
194
+ const slot = signedBlock.message.slot;
195
+ const forkTypes = config.getForkTypes(slot);
196
+ const blockRootHex = toRootHex(forkTypes.BeaconBlock.hashTreeRoot(signedBlock.message));
197
+ const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec);
198
+ const recvToValLatency = Date.now() / 1000 - seenTimestampSec;
199
+
200
+ const logCtx = {
201
+ slot,
202
+ root: blockRootHex,
203
+ currentSlot: chain.clock.currentSlot,
204
+ peerId: peerIdStr,
205
+ delaySec,
206
+ recvToValLatency,
207
+ };
208
+
209
+ logger.debug("Received gossip block", {...logCtx});
210
+
211
+ chain.seenBlockInputCache.markValidatingBlock(blockRootHex);
212
+
205
213
  try {
206
214
  const {skippedSlots} = await validateGossipBlock(config, chain, signedBlock, fork);
215
+ const blockInput = cacheSignatureVerifiedBlock(signedBlock, blockRootHex, fork, peerIdStr, seenTimestampSec);
207
216
 
208
217
  const blockInputMeta = blockInput.getLogMeta();
209
218
 
@@ -229,54 +238,54 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
229
238
  if (e instanceof BlockGossipError) {
230
239
  logger.debug("Gossip block has error", {slot, root: blockRootHex, code: e.type.code});
231
240
  if (
232
- (e.type.code === BlockErrorCode.PARENT_BLOCK_UNKNOWN ||
233
- e.type.code === BlockErrorCode.PARENT_PAYLOAD_UNKNOWN) &&
234
- blockInput
241
+ e.type.code === BlockErrorCode.PARENT_BLOCK_UNKNOWN ||
242
+ e.type.code === BlockErrorCode.PARENT_PAYLOAD_UNKNOWN
235
243
  ) {
244
+ // The block is retained for unknown parent sync without full validation. Authenticate it first, this
245
+ // does not need the parent state
246
+ const proposerIndex = signedBlock.message.proposerIndex;
247
+ await verifyBlockProposerSignature(chain, signedBlock, blockRootHex);
248
+ chain.seenBlockProposers.observeBlockRoot(
249
+ slot,
250
+ proposerIndex,
251
+ blockRootHex,
252
+ signedBlockToSignedHeader(config, signedBlock)
253
+ );
254
+
255
+ // Check again after the signature verification so concurrent proposals cannot both be retained
256
+ if (chain.seenBlockProposers.isKnown(slot, proposerIndex)) {
257
+ if (chain.seenBlockProposers.isRepeatProposal(slot, proposerIndex, blockRootHex)) {
258
+ throw new BlockGossipError(GossipAction.IGNORE, {
259
+ code: BlockErrorCode.REPEAT_PROPOSAL,
260
+ proposerIndex,
261
+ root: blockRootHex,
262
+ });
263
+ }
264
+ throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.ALREADY_KNOWN, root: blockRootHex});
265
+ }
266
+ chain.seenBlockProposers.add(slot, proposerIndex, blockRootHex);
267
+
268
+ const blockInput = cacheSignatureVerifiedBlock(signedBlock, blockRootHex, fork, peerIdStr, seenTimestampSec);
236
269
  chain.emitter.emit(ChainEvent.blockUnknownParent, {
237
270
  blockInput,
238
271
  peer: peerIdStr,
239
272
  source: BlockInputSource.gossip,
240
273
  });
241
- // throw error (don't prune the blockInput)
242
274
  throw e;
243
275
  }
244
276
 
245
- // IGNORE means the block is acceptable (e.g. FUTURE_SLOT, ALREADY_KNOWN), just not propagated.
246
- // Keep the optimistically-added cache entries; they are pruned on finalization. Only REJECT
247
- // (provably invalid), unexpected errors and repeat proposals that are not imported prune.
248
- if (e.action === GossipAction.IGNORE) {
249
- // Only a signature-verified sibling is imported by the beacon_block handler, any other repeat proposal
250
- // is dropped from the caches and re-downloaded by sync if it ever becomes relevant. Its signature was not
251
- // verified, so only its own entry is removed, never its claimed ancestors
252
- if (
253
- e.type.code === BlockErrorCode.REPEAT_PROPOSAL &&
254
- !chain.seenBlockProposers.hasBlockRoot(slot, signedBlock.message.proposerIndex, blockRootHex)
255
- ) {
256
- chain.seenBlockInputCache.remove(blockRootHex);
257
- if (isForkPostGloas(fork)) {
258
- chain.seenPayloadEnvelopeInputCache.remove(blockRootHex);
259
- }
260
- }
261
- throw e;
277
+ if (e.action === GossipAction.REJECT) {
278
+ chain.persistInvalidSszValue(
279
+ forkTypes.SignedBeaconBlock,
280
+ signedBlock,
281
+ `gossip_reject_slot_${slot}`,
282
+ blockRootHex
283
+ );
262
284
  }
263
-
264
- chain.persistInvalidSszValue(
265
- forkTypes.SignedBeaconBlock,
266
- signedBlock,
267
- `gossip_reject_slot_${slot}`,
268
- blockRootHex
269
- );
270
- }
271
-
272
- // REJECT or unexpected (non-BlockGossipError) error: drop the optimistically-added entries from
273
- // both caches, keeping them consistent. The block may carry any parent root, so only its own entry is removed
274
- chain.seenBlockInputCache.remove(blockRootHex);
275
- if (isForkPostGloas(fork)) {
276
- chain.seenPayloadEnvelopeInputCache.remove(blockRootHex);
277
285
  }
278
286
  throw e;
279
287
  } finally {
288
+ chain.seenBlockInputCache.unmarkValidatingBlock(blockRootHex);
280
289
  // The block received from the network may have established an equivocation, either by conflicting
281
290
  // with a previously observed block root (REPEAT_PROPOSAL) or with a root observed during validation
282
291
  const proposerIndex = signedBlock.message.proposerIndex;
@@ -752,18 +761,23 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
752
761
  e.type.code === BlockErrorCode.REPEAT_PROPOSAL &&
753
762
  // Only a signature-verified sibling recorded in the seen cache is imported. The cache holds at most two
754
763
  // roots per proposer and slot, which bounds full imports over gossip to one alternate
755
- chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root)
764
+ chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root) &&
765
+ // A sibling with an unknown parent cannot be imported, sync fetches it if its branch becomes relevant
766
+ chain.forkChoice.getBlockHexDefaultStatus(toRootHex(signedBlock.message.parentRoot)) !== null
756
767
  ) {
757
- // blockInput was optimistically seeded in validateBeaconBlock and retained on IGNORE
758
- const blockInput = chain.seenBlockInputCache.get(e.type.root);
759
- if (blockInput) {
760
- // We're returning IGNORE (thrown below), so this block is not forwarded to peers. Unlike the
761
- // happy path there is no rush to forward, so we don't need to wrap in callInNextEventLoop.
762
- chain.serializedCache.set(signedBlock, serializedData);
763
- // this is technically not a valid gossip block but gossip validation is a cheap subset of checks
764
- // this runs the full state transition, so importing an equivocating-but-valid block here is safe.
765
- handleValidBeaconBlock(blockInput, peerIdStr, seenTimestampSec);
766
- }
768
+ const blockInput = cacheSignatureVerifiedBlock(
769
+ signedBlock,
770
+ e.type.root,
771
+ topic.boundary.fork,
772
+ peerIdStr,
773
+ seenTimestampSec
774
+ );
775
+ // We're returning IGNORE (thrown below), so this block is not forwarded to peers. Unlike the
776
+ // happy path there is no rush to forward, so we don't need to wrap in callInNextEventLoop.
777
+ chain.serializedCache.set(signedBlock, serializedData);
778
+ // this is technically not a valid gossip block but gossip validation is a cheap subset of checks
779
+ // this runs the full state transition, so importing an equivocating-but-valid block here is safe.
780
+ handleValidBeaconBlock(blockInput, peerIdStr, seenTimestampSec);
767
781
  }
768
782
  // rethrow so gossipValidatorFn maps IGNORE -> TopicValidatorResult.Ignore (message not forwarded)
769
783
  throw e;
@@ -1341,6 +1355,9 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1341
1355
  case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
1342
1356
  case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
1343
1357
  core.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadGossipPayload");
1358
+ // The builder may have signed another envelope that is valid, keeping this one would make
1359
+ // by-root and range sync reuse it and never import the payload
1360
+ chain.seenPayloadEnvelopeInputCache.removeInvalid(payloadInput);
1344
1361
  // Misbehaving peer, but could highlight an issue in another client
1345
1362
  logLevel = LogLevel.warn;
1346
1363
  break;
@@ -1378,7 +1395,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1378
1395
  const delaySec = chain.clock.secFromSlot(payloadAttestationMessage.data.slot, seenTimestampSec);
1379
1396
  metrics?.gossipPayloadAttestationMessage.elapsedTimeTillReceived.observe({source: OpSource.gossip}, delaySec);
1380
1397
  const nextSlotProposer = chain.getHeadState().getBeaconProposer(payloadAttestationMessage.data.slot + 1);
1381
- const isNextSlotProposer = chain.beaconProposerCache.get(nextSlotProposer) !== undefined;
1398
+ const isNextSlotProposer = chain.beaconProposerCache.has(nextSlotProposer);
1382
1399
 
1383
1400
  if (isNextSlotProposer) {
1384
1401
  try {
@@ -20,6 +20,7 @@ import {
20
20
  VoluntaryExitErrorCode,
21
21
  } from "../../chain/errors/index.js";
22
22
  import {Metrics} from "../../metrics/index.js";
23
+ import {PeerIdStr} from "../../util/peerId.js";
23
24
  import {INetworkCore} from "../core/index.js";
24
25
  import {
25
26
  BatchGossipHandlerFn,
@@ -40,6 +41,8 @@ export type ValidatorFnModules = {
40
41
  core: INetworkCore;
41
42
  };
42
43
 
44
+ export type OnFatalPeerFn = (peer: PeerIdStr) => void;
45
+
43
46
  type RejectPeerActionRule = {default: PeerAction; byCode?: Record<string, PeerAction>};
44
47
 
45
48
  /**
@@ -123,7 +126,8 @@ export function rejectPeerAction(type: GossipType, code: string): PeerAction {
123
126
  */
124
127
  export function getGossipValidatorBatchFn(
125
128
  gossipHandlers: GossipHandlers,
126
- modules: ValidatorFnModules
129
+ modules: ValidatorFnModules,
130
+ onFatalPeer: OnFatalPeerFn
127
131
  ): GossipValidatorBatchFn {
128
132
  const {logger, metrics, core} = modules;
129
133
 
@@ -173,6 +177,7 @@ export function getGossipValidatorBatchFn(
173
177
  metrics?.networkProcessor.gossipAttestationRejectByReason.inc({reason: e.type.code});
174
178
  const peerAction = rejectPeerAction(type, e.type.code);
175
179
  core.reportPeer(propagationSource, peerAction, e.type.code);
180
+ if (peerAction === PeerAction.Fatal) onFatalPeer(propagationSource);
176
181
  logger.debug(
177
182
  `Gossip validation ${type} rejected`,
178
183
  {peer: propagationSource, clientAgent, clientVersion, peerAction},
@@ -208,7 +213,11 @@ export function getGossipValidatorBatchFn(
208
213
  *
209
214
  * @see getGossipHandlers for reasoning on why GossipHandlerFn are used for gossip validation.
210
215
  */
211
- export function getGossipValidatorFn(gossipHandlers: GossipHandlers, modules: ValidatorFnModules): GossipValidatorFn {
216
+ export function getGossipValidatorFn(
217
+ gossipHandlers: GossipHandlers,
218
+ modules: ValidatorFnModules,
219
+ onFatalPeer: OnFatalPeerFn
220
+ ): GossipValidatorFn {
212
221
  const {logger, metrics, core} = modules;
213
222
 
214
223
  return async function gossipValidatorFn({
@@ -260,6 +269,7 @@ export function getGossipValidatorFn(gossipHandlers: GossipHandlers, modules: Va
260
269
  metrics?.networkProcessor.gossipValidationReject.inc({topic: type});
261
270
  const peerAction = rejectPeerAction(type, e.type.code);
262
271
  core.reportPeer(propagationSource, peerAction, e.type.code);
272
+ if (peerAction === PeerAction.Fatal) onFatalPeer(propagationSource);
263
273
  logger.debug(
264
274
  `Gossip validation ${type} rejected`,
265
275
  {peer: propagationSource, clientAgent, clientVersion, peerAction},
@@ -1,6 +1,6 @@
1
1
  import {TopicValidatorResult} from "@libp2p/gossipsub";
2
2
  import {routes} from "@lodestar/api";
3
- import {ForkSeq, NUMBER_OF_COLUMNS} from "@lodestar/params";
3
+ import {ForkSeq, NUMBER_OF_COLUMNS, isForkPostGloas} from "@lodestar/params";
4
4
  import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
5
5
  import {RootHex, Slot, SlotRootHex} from "@lodestar/types";
6
6
  import {Logger, MapDef, mapValues, sleep} from "@lodestar/utils";
@@ -108,6 +108,12 @@ type SearchedRootEntry = {
108
108
  */
109
109
  const DEFAULT_EARLIEST_PERMISSIBLE_SLOT_DISTANCE = 32;
110
110
 
111
+ /**
112
+ * The network worker bans a Fatal peer only on its next PeerManager heartbeat (30s). Until then the main thread
113
+ * would keep validating that peer's messages, so drop them here. 3 slots (36s) outlasts one heartbeat.
114
+ */
115
+ export const FATAL_PEER_EXPIRY_SLOTS = 3;
116
+
111
117
  type WorkOpts = {
112
118
  bypassQueue?: boolean;
113
119
  };
@@ -263,6 +269,8 @@ export class NetworkProcessor {
263
269
  () => new MapDef<RootHex, SearchedRootEntry>(() => ({}))
264
270
  );
265
271
  private bufferedRootsBySlot = new MapDef<Slot, Set<RootHex>>(() => new Set());
272
+ /** peer -> clock slot when it was Fatal'ed */
273
+ private readonly fatalPeers = new Map<PeerIdStr, Slot>();
266
274
 
267
275
  constructor(
268
276
  modules: NetworkProcessorModules,
@@ -277,10 +285,15 @@ export class NetworkProcessor {
277
285
  this.events = events;
278
286
  this.gossipQueues = createGossipQueues();
279
287
  this.gossipTopicConcurrency = mapValues(this.gossipQueues, () => 0);
280
- this.gossipValidatorFn = getGossipValidatorFn(modules.gossipHandlers ?? getGossipHandlers(modules, opts), modules);
288
+ this.gossipValidatorFn = getGossipValidatorFn(
289
+ modules.gossipHandlers ?? getGossipHandlers(modules, opts),
290
+ modules,
291
+ this.onFatalPeer
292
+ );
281
293
  this.gossipValidatorBatchFn = getGossipValidatorBatchFn(
282
294
  modules.gossipHandlers ?? getGossipHandlers(modules, opts),
283
- modules
295
+ modules,
296
+ this.onFatalPeer
284
297
  );
285
298
 
286
299
  events.on(NetworkEvent.pendingGossipsubMessage, this.onPendingGossipsubMessage);
@@ -414,8 +427,18 @@ export class NetworkProcessor {
414
427
  }
415
428
  }
416
429
 
430
+ private onFatalPeer = (peer: PeerIdStr): void => {
431
+ this.fatalPeers.set(peer, this.chain.clock.currentSlot);
432
+ };
433
+
417
434
  private onPendingGossipsubMessage = (message: PendingGossipsubMessage): void => {
418
435
  const topicType = message.topic.type;
436
+ if (this.fatalPeers.has(message.propagationSource)) {
437
+ this.metrics?.networkProcessor.gossipValidationError.inc({topic: topicType, error: GossipErrorCode.FATAL_PEER});
438
+ // No need to report the dropped job to gossip. It will be eventually pruned from the mcache
439
+ return;
440
+ }
441
+
419
442
  const extractBlockSlotRootFn = this.extractBlockSlotRootFns[topicType];
420
443
  if (extractBlockSlotRootFn === undefined) {
421
444
  // some messages don't have slot and root
@@ -505,9 +528,9 @@ export class NetworkProcessor {
505
528
  const parentRoot = getParentRootFromSignedBeaconBlockSerialized(message.msg.data);
506
529
  if (parentRoot) {
507
530
  let search: SearchUnknownRootTarget | null = null;
508
- if (ForkSeq[fork] >= ForkSeq.gloas) {
531
+ if (isForkPostGloas(fork)) {
509
532
  // GLOAS: also check parent envelope, same logic as execution_payload_bid
510
- const parentBlockHash = getParentBlockHashFromGloasSignedBeaconBlockSerialized(message.msg.data);
533
+ const parentBlockHash = getParentBlockHashFromGloasSignedBeaconBlockSerialized(message.msg.data, fork);
511
534
  if (parentBlockHash && !this.chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHash)) {
512
535
  const protoBlock = this.chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
513
536
  if (protoBlock === null) {
@@ -898,6 +921,10 @@ export class NetworkProcessor {
898
921
  for (const slot of this.bufferedRootsBySlot.keys()) {
899
922
  if (slot <= minSlot) this.bufferedRootsBySlot.delete(slot);
900
923
  }
924
+
925
+ for (const [peer, slot] of this.fatalPeers) {
926
+ if (clockSlot - slot > FATAL_PEER_EXPIRY_SLOTS) this.fatalPeers.delete(peer);
927
+ }
901
928
  };
902
929
 
903
930
  private executeWork(): void {
@@ -953,6 +980,32 @@ export class NetworkProcessor {
953
980
  private async processPendingGossipsubMessage(
954
981
  messageOrArray: PendingGossipsubMessage | PendingGossipsubMessage[]
955
982
  ): Promise<void> {
983
+ // drop messages from peers Fatal'ed after these were queued or started awaiting a block/envelope
984
+ // No need to report the dropped jobs to gossip. They will be eventually pruned from the mcache
985
+ if (this.fatalPeers.size > 0) {
986
+ if (Array.isArray(messageOrArray)) {
987
+ const allowed: PendingGossipsubMessage[] = [];
988
+ for (const msg of messageOrArray) {
989
+ if (this.fatalPeers.has(msg.propagationSource)) {
990
+ this.metrics?.networkProcessor.gossipValidationError.inc({
991
+ topic: msg.topic.type,
992
+ error: GossipErrorCode.FATAL_PEER,
993
+ });
994
+ } else {
995
+ allowed.push(msg);
996
+ }
997
+ }
998
+ if (allowed.length === 0) return;
999
+ messageOrArray = allowed;
1000
+ } else if (this.fatalPeers.has(messageOrArray.propagationSource)) {
1001
+ this.metrics?.networkProcessor.gossipValidationError.inc({
1002
+ topic: messageOrArray.topic.type,
1003
+ error: GossipErrorCode.FATAL_PEER,
1004
+ });
1005
+ return;
1006
+ }
1007
+ }
1008
+
956
1009
  const nowSec = Date.now() / 1000;
957
1010
  if (Array.isArray(messageOrArray)) {
958
1011
  for (const msg of messageOrArray) {
@@ -53,7 +53,7 @@ export async function* onExecutionPayloadEnvelopesByRoot(
53
53
  const batch = requests.slice(i, i + MAX_BODIES_PER_REQUEST);
54
54
  let envelopesBytes: (Uint8Array | null)[];
55
55
  try {
56
- // By-root allows omission, so a mismatched envelope is left out rather than failing the response.
56
+ // By-root allows omission, so an envelope that cannot be rebuilt is left out rather than failing the response.
57
57
  envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(batch, "omit");
58
58
  } catch (e) {
59
59
  if (e instanceof EnvelopeReconstructionError) {