@lodestar/beacon-node 1.50.0-dev.033e6b7138 → 1.50.0-dev.03c05fa09a

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 (411) 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/pool/index.js +4 -4
  8. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  9. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  10. package/lib/api/impl/beacon/state/index.js +28 -6
  11. package/lib/api/impl/beacon/state/index.js.map +1 -1
  12. package/lib/api/impl/debug/index.d.ts.map +1 -1
  13. package/lib/api/impl/debug/index.js +26 -18
  14. package/lib/api/impl/debug/index.js.map +1 -1
  15. package/lib/api/impl/validator/index.d.ts +1 -0
  16. package/lib/api/impl/validator/index.d.ts.map +1 -1
  17. package/lib/api/impl/validator/index.js +80 -18
  18. package/lib/api/impl/validator/index.js.map +1 -1
  19. package/lib/chain/ColumnReconstructionTracker.d.ts +0 -2
  20. package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
  21. package/lib/chain/ColumnReconstructionTracker.js +4 -5
  22. package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
  23. package/lib/chain/archiveStore/archiveStore.d.ts +6 -0
  24. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  25. package/lib/chain/archiveStore/archiveStore.js +18 -24
  26. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  27. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts +2 -2
  28. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
  29. package/lib/chain/archiveStore/historicalState/getHistoricalState.js +5 -7
  30. package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
  31. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -1
  32. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
  33. package/lib/chain/archiveStore/historicalState/types.d.ts +2 -2
  34. package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
  35. package/lib/chain/archiveStore/historicalState/worker.js +1 -1
  36. package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
  37. package/lib/chain/archiveStore/interface.d.ts +1 -1
  38. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  39. package/lib/chain/archiveStore/utils/pruneHistory.d.ts +4 -1
  40. package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
  41. package/lib/chain/archiveStore/utils/pruneHistory.js +5 -3
  42. package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
  43. package/lib/chain/beaconProposerCache.d.ts +6 -0
  44. package/lib/chain/beaconProposerCache.d.ts.map +1 -1
  45. package/lib/chain/beaconProposerCache.js +16 -0
  46. package/lib/chain/beaconProposerCache.js.map +1 -1
  47. package/lib/chain/blocks/blockInput/blockInput.d.ts +1 -1
  48. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  49. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  50. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  51. package/lib/chain/blocks/importBlock.js +25 -12
  52. package/lib/chain/blocks/importBlock.js.map +1 -1
  53. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +2 -1
  54. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  55. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  56. package/lib/chain/blocks/verifyBlock.js +7 -7
  57. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  58. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts +2 -1
  59. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  60. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +5 -4
  61. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  62. package/lib/chain/chain.d.ts +10 -5
  63. package/lib/chain/chain.d.ts.map +1 -1
  64. package/lib/chain/chain.js +108 -38
  65. package/lib/chain/chain.js.map +1 -1
  66. package/lib/chain/emitter.d.ts +7 -1
  67. package/lib/chain/emitter.d.ts.map +1 -1
  68. package/lib/chain/emitter.js +5 -0
  69. package/lib/chain/emitter.js.map +1 -1
  70. package/lib/chain/errors/envelopeReconstructionError.d.ts +5 -0
  71. package/lib/chain/errors/envelopeReconstructionError.d.ts.map +1 -1
  72. package/lib/chain/errors/envelopeReconstructionError.js +2 -0
  73. package/lib/chain/errors/envelopeReconstructionError.js.map +1 -1
  74. package/lib/chain/errors/gossipValidation.d.ts +3 -1
  75. package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
  76. package/lib/chain/errors/gossipValidation.js +2 -0
  77. package/lib/chain/errors/gossipValidation.js.map +1 -1
  78. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  79. package/lib/chain/forkChoice/index.js +2 -0
  80. package/lib/chain/forkChoice/index.js.map +1 -1
  81. package/lib/chain/initState.d.ts +2 -9
  82. package/lib/chain/initState.d.ts.map +1 -1
  83. package/lib/chain/initState.js +5 -38
  84. package/lib/chain/initState.js.map +1 -1
  85. package/lib/chain/interface.d.ts +6 -3
  86. package/lib/chain/interface.d.ts.map +1 -1
  87. package/lib/chain/opPools/aggregatedAttestationPool.d.ts +4 -2
  88. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  89. package/lib/chain/opPools/aggregatedAttestationPool.js +30 -8
  90. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  91. package/lib/chain/opPools/opPool.d.ts +5 -4
  92. package/lib/chain/opPools/opPool.d.ts.map +1 -1
  93. package/lib/chain/opPools/opPool.js +60 -38
  94. package/lib/chain/opPools/opPool.js.map +1 -1
  95. package/lib/chain/opPools/proposerPreferencesPool.d.ts +8 -4
  96. package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
  97. package/lib/chain/opPools/proposerPreferencesPool.js +27 -12
  98. package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
  99. package/lib/chain/opPools/utils.d.ts +15 -1
  100. package/lib/chain/opPools/utils.d.ts.map +1 -1
  101. package/lib/chain/opPools/utils.js +33 -1
  102. package/lib/chain/opPools/utils.js.map +1 -1
  103. package/lib/chain/options.d.ts +2 -1
  104. package/lib/chain/options.d.ts.map +1 -1
  105. package/lib/chain/options.js +1 -1
  106. package/lib/chain/options.js.map +1 -1
  107. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  108. package/lib/chain/prepareNextSlot.js +20 -8
  109. package/lib/chain/prepareNextSlot.js.map +1 -1
  110. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  111. package/lib/chain/produceBlock/computeNewStateRoot.js +1 -1
  112. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  113. package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -1
  114. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  115. package/lib/chain/produceBlock/produceBlockBody.js +54 -36
  116. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  117. package/lib/chain/regen/regen.d.ts +2 -0
  118. package/lib/chain/regen/regen.d.ts.map +1 -1
  119. package/lib/chain/regen/regen.js +10 -4
  120. package/lib/chain/regen/regen.js.map +1 -1
  121. package/lib/chain/reprocess.d.ts +2 -1
  122. package/lib/chain/reprocess.d.ts.map +1 -1
  123. package/lib/chain/reprocess.js +2 -1
  124. package/lib/chain/reprocess.js.map +1 -1
  125. package/lib/chain/seenCache/seenGossipBlockInput.d.ts +7 -0
  126. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  127. package/lib/chain/seenCache/seenGossipBlockInput.js +22 -1
  128. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  129. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +9 -2
  130. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  131. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +23 -13
  132. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  133. package/lib/chain/shufflingCache.d.ts +18 -8
  134. package/lib/chain/shufflingCache.d.ts.map +1 -1
  135. package/lib/chain/shufflingCache.js +72 -18
  136. package/lib/chain/shufflingCache.js.map +1 -1
  137. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  138. package/lib/chain/stateCache/persistentCheckpointsCache.js +1 -1
  139. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  140. package/lib/chain/validation/attesterSlashing.d.ts +4 -4
  141. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  142. package/lib/chain/validation/attesterSlashing.js +3 -0
  143. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  144. package/lib/chain/validation/proposerSlashing.d.ts +3 -3
  145. package/lib/chain/validation/proposerSlashing.d.ts.map +1 -1
  146. package/lib/chain/validation/proposerSlashing.js +3 -0
  147. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  148. package/lib/chain/validatorMonitor.d.ts +5 -1
  149. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  150. package/lib/chain/validatorMonitor.js +70 -58
  151. package/lib/chain/validatorMonitor.js.map +1 -1
  152. package/lib/constants/constants.d.ts +1 -0
  153. package/lib/constants/constants.d.ts.map +1 -1
  154. package/lib/constants/constants.js +1 -0
  155. package/lib/constants/constants.js.map +1 -1
  156. package/lib/db/beacon.d.ts +4 -1
  157. package/lib/db/beacon.d.ts.map +1 -1
  158. package/lib/db/beacon.js +8 -1
  159. package/lib/db/beacon.js.map +1 -1
  160. package/lib/db/buckets.d.ts +3 -1
  161. package/lib/db/buckets.d.ts.map +1 -1
  162. package/lib/db/buckets.js +2 -0
  163. package/lib/db/buckets.js.map +1 -1
  164. package/lib/db/interface.d.ts +4 -1
  165. package/lib/db/interface.d.ts.map +1 -1
  166. package/lib/db/repositories/blockArchive.js +2 -2
  167. package/lib/db/repositories/blockArchive.js.map +1 -1
  168. package/lib/db/repositories/blockArchiveIndex.d.ts +3 -3
  169. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  170. package/lib/db/repositories/blockArchiveIndex.js +1 -2
  171. package/lib/db/repositories/blockArchiveIndex.js.map +1 -1
  172. package/lib/db/repositories/earliestAvailableSlot.d.ts +11 -0
  173. package/lib/db/repositories/earliestAvailableSlot.d.ts.map +1 -0
  174. package/lib/db/repositories/earliestAvailableSlot.js +19 -0
  175. package/lib/db/repositories/earliestAvailableSlot.js.map +1 -0
  176. package/lib/db/repositories/index.d.ts +1 -0
  177. package/lib/db/repositories/index.d.ts.map +1 -1
  178. package/lib/db/repositories/index.js +1 -0
  179. package/lib/db/repositories/index.js.map +1 -1
  180. package/lib/db/repositories/proposerPreferences.d.ts +14 -0
  181. package/lib/db/repositories/proposerPreferences.d.ts.map +1 -0
  182. package/lib/db/repositories/proposerPreferences.js +21 -0
  183. package/lib/db/repositories/proposerPreferences.js.map +1 -0
  184. package/lib/db/repositories/proposerSlashing.d.ts +1 -0
  185. package/lib/db/repositories/proposerSlashing.d.ts.map +1 -1
  186. package/lib/db/repositories/proposerSlashing.js +5 -1
  187. package/lib/db/repositories/proposerSlashing.js.map +1 -1
  188. package/lib/execution/engine/blobVersionedHashes.d.ts +9 -0
  189. package/lib/execution/engine/blobVersionedHashes.d.ts.map +1 -0
  190. package/lib/execution/engine/blobVersionedHashes.js +74 -0
  191. package/lib/execution/engine/blobVersionedHashes.js.map +1 -0
  192. package/lib/execution/engine/disabled.d.ts +0 -2
  193. package/lib/execution/engine/disabled.d.ts.map +1 -1
  194. package/lib/execution/engine/disabled.js +0 -6
  195. package/lib/execution/engine/disabled.js.map +1 -1
  196. package/lib/execution/engine/http.d.ts +46 -16
  197. package/lib/execution/engine/http.d.ts.map +1 -1
  198. package/lib/execution/engine/http.js +236 -213
  199. package/lib/execution/engine/http.js.map +1 -1
  200. package/lib/execution/engine/index.d.ts +3 -2
  201. package/lib/execution/engine/index.d.ts.map +1 -1
  202. package/lib/execution/engine/index.js +33 -8
  203. package/lib/execution/engine/index.js.map +1 -1
  204. package/lib/execution/engine/interface.d.ts +2 -4
  205. package/lib/execution/engine/interface.d.ts.map +1 -1
  206. package/lib/execution/engine/jsonRpcTransport.d.ts +25 -0
  207. package/lib/execution/engine/jsonRpcTransport.d.ts.map +1 -0
  208. package/lib/execution/engine/jsonRpcTransport.js +158 -0
  209. package/lib/execution/engine/jsonRpcTransport.js.map +1 -0
  210. package/lib/execution/engine/mock.d.ts +0 -2
  211. package/lib/execution/engine/mock.d.ts.map +1 -1
  212. package/lib/execution/engine/mock.js +0 -8
  213. package/lib/execution/engine/mock.js.map +1 -1
  214. package/lib/execution/engine/restHttpClient.d.ts +71 -0
  215. package/lib/execution/engine/restHttpClient.d.ts.map +1 -0
  216. package/lib/execution/engine/restHttpClient.js +201 -0
  217. package/lib/execution/engine/restHttpClient.js.map +1 -0
  218. package/lib/execution/engine/restTransport.d.ts +46 -0
  219. package/lib/execution/engine/restTransport.d.ts.map +1 -0
  220. package/lib/execution/engine/restTransport.js +399 -0
  221. package/lib/execution/engine/restTransport.js.map +1 -0
  222. package/lib/execution/engine/sszTypes.d.ts +1261 -0
  223. package/lib/execution/engine/sszTypes.d.ts.map +1 -0
  224. package/lib/execution/engine/sszTypes.js +216 -0
  225. package/lib/execution/engine/sszTypes.js.map +1 -0
  226. package/lib/execution/engine/transport.d.ts +39 -0
  227. package/lib/execution/engine/transport.d.ts.map +1 -0
  228. package/lib/execution/engine/transport.js +2 -0
  229. package/lib/execution/engine/transport.js.map +1 -0
  230. package/lib/execution/engine/types.d.ts +2 -8
  231. package/lib/execution/engine/types.d.ts.map +1 -1
  232. package/lib/execution/engine/types.js +31 -63
  233. package/lib/execution/engine/types.js.map +1 -1
  234. package/lib/execution/engine/utils.d.ts.map +1 -1
  235. package/lib/execution/engine/utils.js +9 -2
  236. package/lib/execution/engine/utils.js.map +1 -1
  237. package/lib/index.d.ts +1 -1
  238. package/lib/index.d.ts.map +1 -1
  239. package/lib/index.js +1 -1
  240. package/lib/index.js.map +1 -1
  241. package/lib/metrics/metrics/lodestar.d.ts +10 -0
  242. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  243. package/lib/metrics/metrics/lodestar.js +22 -0
  244. package/lib/metrics/metrics/lodestar.js.map +1 -1
  245. package/lib/metrics/metrics.d.ts +7 -3
  246. package/lib/metrics/metrics.d.ts.map +1 -1
  247. package/lib/metrics/metrics.js +4 -4
  248. package/lib/metrics/metrics.js.map +1 -1
  249. package/lib/network/core/events.d.ts +5 -1
  250. package/lib/network/core/events.d.ts.map +1 -1
  251. package/lib/network/core/events.js +8 -0
  252. package/lib/network/core/events.js.map +1 -1
  253. package/lib/network/gossip/topic.d.ts +0 -14
  254. package/lib/network/gossip/topic.d.ts.map +1 -1
  255. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  256. package/lib/network/processor/gossipHandlers.js +67 -68
  257. package/lib/network/processor/gossipHandlers.js.map +1 -1
  258. package/lib/network/processor/gossipValidatorFn.d.ts +7 -3
  259. package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
  260. package/lib/network/processor/gossipValidatorFn.js +7 -3
  261. package/lib/network/processor/gossipValidatorFn.js.map +1 -1
  262. package/lib/network/processor/index.d.ts +9 -0
  263. package/lib/network/processor/index.d.ts.map +1 -1
  264. package/lib/network/processor/index.js +80 -13
  265. package/lib/network/processor/index.js.map +1 -1
  266. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +1 -1
  267. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  268. package/lib/network/reqresp/rateLimit.js +2 -2
  269. package/lib/network/reqresp/rateLimit.js.map +1 -1
  270. package/lib/network/subnets/attnetsService.d.ts.map +1 -1
  271. package/lib/network/subnets/attnetsService.js +3 -1
  272. package/lib/network/subnets/attnetsService.js.map +1 -1
  273. package/lib/node/nodejs.d.ts +3 -1
  274. package/lib/node/nodejs.d.ts.map +1 -1
  275. package/lib/node/nodejs.js +27 -4
  276. package/lib/node/nodejs.js.map +1 -1
  277. package/lib/node/notifier.d.ts.map +1 -1
  278. package/lib/node/notifier.js +12 -13
  279. package/lib/node/notifier.js.map +1 -1
  280. package/lib/node/options.d.ts +3 -2
  281. package/lib/node/options.d.ts.map +1 -1
  282. package/lib/node/options.js +2 -2
  283. package/lib/node/options.js.map +1 -1
  284. package/lib/sync/range/batch.d.ts +11 -5
  285. package/lib/sync/range/batch.d.ts.map +1 -1
  286. package/lib/sync/range/batch.js +21 -17
  287. package/lib/sync/range/batch.js.map +1 -1
  288. package/lib/sync/range/chain.d.ts +4 -4
  289. package/lib/sync/range/chain.d.ts.map +1 -1
  290. package/lib/sync/range/chain.js +12 -6
  291. package/lib/sync/range/chain.js.map +1 -1
  292. package/lib/sync/range/range.d.ts.map +1 -1
  293. package/lib/sync/range/range.js +75 -29
  294. package/lib/sync/range/range.js.map +1 -1
  295. package/lib/sync/unknownBlock.d.ts +14 -7
  296. package/lib/sync/unknownBlock.d.ts.map +1 -1
  297. package/lib/sync/unknownBlock.js +135 -68
  298. package/lib/sync/unknownBlock.js.map +1 -1
  299. package/lib/sync/utils/downloadByRange.d.ts +38 -14
  300. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  301. package/lib/sync/utils/downloadByRange.js +84 -39
  302. package/lib/sync/utils/downloadByRange.js.map +1 -1
  303. package/lib/util/asyncIterableToEvents.d.ts +10 -2
  304. package/lib/util/asyncIterableToEvents.d.ts.map +1 -1
  305. package/lib/util/asyncIterableToEvents.js +29 -3
  306. package/lib/util/asyncIterableToEvents.js.map +1 -1
  307. package/lib/util/clock.d.ts.map +1 -1
  308. package/lib/util/clock.js +3 -4
  309. package/lib/util/clock.js.map +1 -1
  310. package/lib/util/execution.d.ts +9 -11
  311. package/lib/util/execution.d.ts.map +1 -1
  312. package/lib/util/execution.js +5 -1
  313. package/lib/util/execution.js.map +1 -1
  314. package/lib/util/metadata.d.ts.map +1 -1
  315. package/lib/util/metadata.js +2 -1
  316. package/lib/util/metadata.js.map +1 -1
  317. package/lib/util/sszBytes.d.ts +2 -2
  318. package/lib/util/sszBytes.d.ts.map +1 -1
  319. package/lib/util/sszBytes.js +22 -14
  320. package/lib/util/sszBytes.js.map +1 -1
  321. package/package.json +18 -17
  322. package/src/api/impl/beacon/blocks/index.ts +17 -7
  323. package/src/api/impl/beacon/index.ts +15 -0
  324. package/src/api/impl/beacon/pool/index.ts +4 -4
  325. package/src/api/impl/beacon/state/index.ts +43 -6
  326. package/src/api/impl/debug/index.ts +28 -19
  327. package/src/api/impl/validator/index.ts +102 -21
  328. package/src/chain/ColumnReconstructionTracker.ts +4 -6
  329. package/src/chain/archiveStore/archiveStore.ts +26 -26
  330. package/src/chain/archiveStore/historicalState/getHistoricalState.ts +5 -7
  331. package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -1
  332. package/src/chain/archiveStore/historicalState/types.ts +2 -2
  333. package/src/chain/archiveStore/historicalState/worker.ts +1 -2
  334. package/src/chain/archiveStore/interface.ts +1 -1
  335. package/src/chain/archiveStore/utils/pruneHistory.ts +9 -4
  336. package/src/chain/beaconProposerCache.ts +19 -1
  337. package/src/chain/blocks/blockInput/blockInput.ts +1 -1
  338. package/src/chain/blocks/importBlock.ts +29 -11
  339. package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
  340. package/src/chain/blocks/verifyBlock.ts +8 -6
  341. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +6 -3
  342. package/src/chain/chain.ts +138 -40
  343. package/src/chain/emitter.ts +7 -1
  344. package/src/chain/errors/envelopeReconstructionError.ts +3 -0
  345. package/src/chain/errors/gossipValidation.ts +2 -0
  346. package/src/chain/forkChoice/index.ts +2 -0
  347. package/src/chain/initState.ts +8 -60
  348. package/src/chain/interface.ts +7 -3
  349. package/src/chain/opPools/aggregatedAttestationPool.ts +34 -10
  350. package/src/chain/opPools/opPool.ts +89 -46
  351. package/src/chain/opPools/proposerPreferencesPool.ts +34 -11
  352. package/src/chain/opPools/utils.ts +62 -3
  353. package/src/chain/options.ts +3 -3
  354. package/src/chain/prepareNextSlot.ts +28 -9
  355. package/src/chain/produceBlock/computeNewStateRoot.ts +10 -3
  356. package/src/chain/produceBlock/produceBlockBody.ts +86 -40
  357. package/src/chain/regen/regen.ts +12 -4
  358. package/src/chain/reprocess.ts +2 -1
  359. package/src/chain/seenCache/seenGossipBlockInput.ts +25 -1
  360. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +31 -13
  361. package/src/chain/shufflingCache.ts +84 -22
  362. package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
  363. package/src/chain/validation/attesterSlashing.ts +7 -4
  364. package/src/chain/validation/proposerSlashing.ts +7 -4
  365. package/src/chain/validatorMonitor.ts +82 -61
  366. package/src/constants/constants.ts +1 -0
  367. package/src/db/beacon.ts +8 -0
  368. package/src/db/buckets.ts +2 -0
  369. package/src/db/interface.ts +4 -0
  370. package/src/db/repositories/blockArchive.ts +2 -2
  371. package/src/db/repositories/blockArchiveIndex.ts +2 -3
  372. package/src/db/repositories/earliestAvailableSlot.ts +19 -0
  373. package/src/db/repositories/index.ts +1 -0
  374. package/src/db/repositories/proposerPreferences.ts +23 -0
  375. package/src/db/repositories/proposerSlashing.ts +6 -1
  376. package/src/execution/engine/blobVersionedHashes.ts +72 -0
  377. package/src/execution/engine/disabled.ts +0 -8
  378. package/src/execution/engine/http.ts +304 -300
  379. package/src/execution/engine/index.ts +41 -7
  380. package/src/execution/engine/interface.ts +2 -6
  381. package/src/execution/engine/jsonRpcTransport.ts +247 -0
  382. package/src/execution/engine/mock.ts +1 -19
  383. package/src/execution/engine/restHttpClient.ts +269 -0
  384. package/src/execution/engine/restTransport.ts +544 -0
  385. package/src/execution/engine/sszTypes.ts +354 -0
  386. package/src/execution/engine/transport.ts +61 -0
  387. package/src/execution/engine/types.ts +42 -90
  388. package/src/execution/engine/utils.ts +12 -2
  389. package/src/index.ts +1 -1
  390. package/src/metrics/metrics/lodestar.ts +23 -0
  391. package/src/metrics/metrics.ts +21 -6
  392. package/src/network/core/events.ts +16 -1
  393. package/src/network/processor/gossipHandlers.ts +98 -81
  394. package/src/network/processor/gossipValidatorFn.ts +13 -3
  395. package/src/network/processor/index.ts +92 -13
  396. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +1 -1
  397. package/src/network/reqresp/rateLimit.ts +2 -2
  398. package/src/network/subnets/attnetsService.ts +8 -3
  399. package/src/node/nodejs.ts +35 -3
  400. package/src/node/notifier.ts +14 -13
  401. package/src/node/options.ts +10 -1
  402. package/src/sync/range/batch.ts +25 -19
  403. package/src/sync/range/chain.ts +15 -8
  404. package/src/sync/range/range.ts +76 -30
  405. package/src/sync/unknownBlock.ts +159 -73
  406. package/src/sync/utils/downloadByRange.ts +123 -58
  407. package/src/util/asyncIterableToEvents.ts +44 -5
  408. package/src/util/clock.ts +3 -4
  409. package/src/util/execution.ts +16 -8
  410. package/src/util/metadata.ts +2 -1
  411. package/src/util/sszBytes.ts +25 -12
@@ -2,9 +2,10 @@ import {EventEmitter} from "node:events";
2
2
  import {StrictEventEmitter} from "strict-event-emitter-types";
3
3
  import {BeaconConfig} from "@lodestar/config";
4
4
  import {IBeaconStateViewGloas, computeStartSlotAtEpoch, isStatePostGloas} from "@lodestar/state-transition";
5
- import {Epoch, Status, fulu} from "@lodestar/types";
6
- import {Logger, prettyPrintIndices, toRootHex} from "@lodestar/utils";
5
+ import {Epoch, Status, fulu, ssz} from "@lodestar/types";
6
+ import {Logger, byteArrayEquals, prettyPrintIndices, toRootHex} from "@lodestar/utils";
7
7
  import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
8
+ import {PayloadError, PayloadErrorCode} from "../../chain/blocks/importExecutionPayload.js";
8
9
  import {AttestationImportOpt, ImportBlockOpts} from "../../chain/blocks/index.js";
9
10
  import {assertLinearChainSegment} from "../../chain/blocks/utils/chainSegment.js";
10
11
  import {BlockError} from "../../chain/errors/index.js";
@@ -15,6 +16,7 @@ import {PeerIdStr} from "../../util/peerId.js";
15
16
  import {
16
17
  DownloadByRangeError,
17
18
  DownloadByRangeErrorCode,
19
+ ParentPayload,
18
20
  cacheByRangeResponses,
19
21
  downloadByRange,
20
22
  } from "../utils/downloadByRange.js";
@@ -207,22 +209,50 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
207
209
  blsVerifyOnMainThread: false,
208
210
  };
209
211
 
210
- if (this.opts?.disableProcessAsChainSegment) {
211
- // Should only be used for debugging or testing
212
- for (const block of blocks) {
213
- await this.chain.processBlock(block, flags);
214
- const payloadEnvelope = payloadEnvelopes?.get(block.slot);
215
- if (payloadEnvelope?.hasPayloadEnvelope()) {
216
- await this.chain.processExecutionPayload(payloadEnvelope);
212
+ try {
213
+ if (this.opts?.disableProcessAsChainSegment) {
214
+ // Should only be used for debugging or testing
215
+ for (const block of blocks) {
216
+ await this.chain.processBlock(block, flags);
217
+ const payloadEnvelope = payloadEnvelopes?.get(block.slot);
218
+ if (payloadEnvelope?.hasPayloadEnvelope()) {
219
+ await this.chain.processExecutionPayload(payloadEnvelope);
220
+ }
221
+ }
222
+ } else {
223
+ const {orphaned, skipped} = await this.chain.processChainSegment(blocks, payloadEnvelopes, flags);
224
+ // We log orphaned payloads to work with different clients
225
+ // in the future, consider applying penalties in certain conditions
226
+ // make sure the payload source was from range sync in that case
227
+ for (const {slot, payloadEnvelopeInput} of orphaned) {
228
+ const {peerIdStr, source} = payloadEnvelopeInput.getPayloadEnvelopeSource();
229
+ let client = "unknown";
230
+ if (peerIdStr !== undefined) {
231
+ try {
232
+ client = this.getConnectedPeerSyncMeta(peerIdStr).client;
233
+ } catch {
234
+ // peer disconnected since serving the envelope, keep "unknown"
235
+ }
236
+ }
237
+ this.logger.debug("Orphaned payload envelope in range sync batch", {
238
+ slot,
239
+ root: payloadEnvelopeInput.blockRootHex,
240
+ peer: peerIdStr ?? "unknown",
241
+ source,
242
+ client,
243
+ skipped,
244
+ });
217
245
  }
218
246
  }
219
- } else {
220
- const {orphaned, skipped} = await this.chain.processChainSegment(blocks, payloadEnvelopes, flags);
221
- // We log orphaned payloads to work with different clients
222
- // in the future, consider applying penalties in certain conditions
223
- // make sure the payload source was from range sync in that case
224
- for (const {slot, payloadEnvelopeInput} of orphaned) {
225
- const {peerIdStr, source} = payloadEnvelopeInput.getPayloadEnvelopeSource();
247
+ } catch (e) {
248
+ if (
249
+ e instanceof PayloadError &&
250
+ (e.type.code === PayloadErrorCode.INVALID_SIGNATURE ||
251
+ e.type.code === PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR ||
252
+ e.type.code === PayloadErrorCode.EXECUTION_ENGINE_INVALID)
253
+ ) {
254
+ const {payloadInput} = e;
255
+ const {peerIdStr, source} = payloadInput.getPayloadEnvelopeSource();
226
256
  let client = "unknown";
227
257
  if (peerIdStr !== undefined) {
228
258
  try {
@@ -231,30 +261,32 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
231
261
  // peer disconnected since serving the envelope, keep "unknown"
232
262
  }
233
263
  }
234
- this.logger.debug("Orphaned payload envelope in range sync batch", {
235
- slot,
236
- root: payloadEnvelopeInput.blockRootHex,
264
+ this.logger.debug("Removing invalid payload envelope in range sync batch", {
265
+ slot: payloadInput.slot,
266
+ root: payloadInput.blockRootHex,
237
267
  peer: peerIdStr ?? "unknown",
238
268
  source,
239
269
  client,
240
- skipped,
270
+ code: e.type.code,
241
271
  });
272
+ // The batch is downloaded again, it would otherwise reuse the cached envelope and fail the same way
273
+ this.chain.seenPayloadEnvelopeInputCache.removeInvalid(payloadInput);
242
274
  }
275
+ throw e;
243
276
  }
244
277
  };
245
278
 
246
279
  private downloadByRange: SyncChainFns["downloadByRange"] = async (peer, batch) => {
247
280
  const batchBlocks = batch.getBlocks();
248
281
  const requests = batch.getRequestsForPeer(peer);
249
- const parentRoot = requests.parentPayloadRequest?.envelopeBlockRoot ?? requests.parentPayloadRequest?.blockRoot;
250
- const parentPayloadCommitments = parentRoot ? batch.getParentPayloadCommitments(parentRoot) : undefined;
282
+ const parentPayload = requests.parentPayloadRequest ? batch.getParentPayload() : undefined;
251
283
  const {result, warnings} = await downloadByRange({
252
284
  config: this.config,
253
285
  network: this.network,
254
286
  logger: this.logger,
255
287
  peerIdStr: peer.peerId,
256
288
  batchBlocks,
257
- parentPayloadCommitments,
289
+ parentPayload,
258
290
  peerDasMetrics: this.chain.metrics?.peerDas,
259
291
  ...requests,
260
292
  });
@@ -267,6 +299,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
267
299
  batchBlocks,
268
300
  downloadedPayloadEnvelopes,
269
301
  existingPayloadEnvelopes: batch.getPayloadEnvelopes(),
302
+ parentPayload,
270
303
  custodyConfig: this.chain.custodyConfig,
271
304
  seenTimestampSec: Date.now() / 1000,
272
305
  });
@@ -344,13 +377,26 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
344
377
  private addPeerOrCreateChain(startEpoch: Epoch, target: ChainTarget, peer: PeerIdStr, syncType: RangeSyncType): void {
345
378
  let syncChain = this.chains.get(syncType);
346
379
  if (!syncChain) {
347
- // The first batch of a new sync chain may need to detect whether the parent block was an
348
- // gloas "empty" block (no envelope produced). It does so by comparing the first
349
- // downloaded block's `bid.parentBlockHash` against the head state's `latestExecutionPayloadBid.blockHash`.
380
+ // The first block of the first batch may build on the head's FULL variant before its payload is imported,
381
+ // the batch then downloads the head's payload as dangling parent and validates it against the bid
350
382
  const headState = this.chain.getHeadState();
351
- const latestBid = isStatePostGloas(headState)
352
- ? (headState as IBeaconStateViewGloas).latestExecutionPayloadBid
353
- : undefined;
383
+ let parentPayload: ParentPayload | undefined;
384
+ if (isStatePostGloas(headState) && headState.latestBlockHeader.slot > 0) {
385
+ const header = ssz.phase0.BeaconBlockHeader.clone(headState.latestBlockHeader);
386
+ if (byteArrayEquals(header.stateRoot, ssz.Root.defaultValue())) {
387
+ header.stateRoot = headState.hashTreeRoot();
388
+ }
389
+ const headRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(header);
390
+ const headSlot = headState.latestBlockHeader.slot;
391
+ parentPayload = {
392
+ blockRoot: headRoot,
393
+ blockRootHex: toRootHex(headRoot),
394
+ slot: headSlot,
395
+ proposerIndex: headState.latestBlockHeader.proposerIndex,
396
+ forkName: this.config.getForkName(headSlot),
397
+ bid: (headState as IBeaconStateViewGloas).latestExecutionPayloadBid,
398
+ };
399
+ }
354
400
 
355
401
  syncChain = new SyncChain(
356
402
  startEpoch,
@@ -371,7 +417,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
371
417
  custodyConfig: this.chain.custodyConfig,
372
418
  metrics: this.metrics,
373
419
  },
374
- latestBid
420
+ parentPayload
375
421
  );
376
422
  this.chains.set(syncType, syncChain);
377
423
 
@@ -15,7 +15,7 @@ import {ChainEvent, ChainEventData, IBeaconChain} from "../chain/index.js";
15
15
  import {validateGloasBlockDataColumnSidecars} from "../chain/validation/dataColumnSidecar.js";
16
16
  import {validateGossipExecutionPayloadEnvelope} from "../chain/validation/executionPayloadEnvelope.js";
17
17
  import {Metrics} from "../metrics/index.js";
18
- import {INetwork, NetworkEvent, NetworkEventData, prettyPrintPeerIdStr} from "../network/index.js";
18
+ import {INetwork, NetworkEvent, NetworkEventData, PeerAction, prettyPrintPeerIdStr} from "../network/index.js";
19
19
  import {PeerSyncMeta} from "../network/peers/peersData.js";
20
20
  import {MAX_PEERS_PER_ROOT} from "../network/processor/constants.js";
21
21
  import {ClockEvent} from "../util/clock.js";
@@ -73,7 +73,11 @@ type AdvancePendingBlockResult =
73
73
  | "removed";
74
74
 
75
75
  class UnknownBlockRateLimitedError extends Error {
76
- constructor(message: string) {
76
+ constructor(
77
+ message: string,
78
+ /** Earliest backoff expiry seen when the download was deferred, it is retried once that has passed */
79
+ readonly retryAt: number
80
+ ) {
77
81
  super(message);
78
82
  this.name = "UnknownBlockRateLimitedError";
79
83
  }
@@ -442,6 +446,11 @@ export class BlockInputSync {
442
446
  };
443
447
 
444
448
  private addByRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr): boolean => {
449
+ if (this.knownBadBlocks.has(rootHex)) {
450
+ this.logger.debug("Ignoring known bad block root", {root: rootHex, peerIdStr: peerIdStr ?? "unknown peer"});
451
+ return false;
452
+ }
453
+
445
454
  let pendingBlock = this.pendingBlocks.get(rootHex);
446
455
  let added = false;
447
456
  if (!pendingBlock) {
@@ -477,6 +486,11 @@ export class BlockInputSync {
477
486
  };
478
487
 
479
488
  private addByBlockInput = (blockInput: IBlockInput, peerIdStr?: string): void => {
489
+ if (this.knownBadBlocks.has(blockInput.blockRootHex)) {
490
+ this.logger.debug("Ignoring known bad block", {slot: blockInput.slot, root: blockInput.blockRootHex, peerIdStr});
491
+ return;
492
+ }
493
+
480
494
  let pendingBlock = this.pendingBlocks.get(blockInput.blockRootHex);
481
495
  // if entry is missing or was added via rootHex and now we have more complete information overwrite
482
496
  // the existing information with the more complete cache entry
@@ -513,6 +527,15 @@ export class BlockInputSync {
513
527
  };
514
528
 
515
529
  private addByPayloadRootHex = (rootHex: RootHex, peerIdStr?: PeerIdStr, slot?: Slot): boolean => {
530
+ if (this.knownBadBlocks.has(rootHex)) {
531
+ this.logger.debug("Ignoring payload for known bad block root", {
532
+ slot: slot ?? "unknown",
533
+ root: rootHex,
534
+ peerIdStr,
535
+ });
536
+ return false;
537
+ }
538
+
516
539
  let pendingPayload = this.pendingPayloads.get(rootHex);
517
540
  let added = false;
518
541
  if (!pendingPayload) {
@@ -581,6 +604,15 @@ export class BlockInputSync {
581
604
  peerIdStr?: PeerIdStr,
582
605
  envelope?: gloas.SignedExecutionPayloadEnvelope
583
606
  ): void => {
607
+ if (this.knownBadBlocks.has(payloadInput.blockRootHex)) {
608
+ this.logger.debug("Ignoring payload input for known bad block root", {
609
+ slot: payloadInput.slot,
610
+ root: payloadInput.blockRootHex,
611
+ peerIdStr,
612
+ });
613
+ return;
614
+ }
615
+
584
616
  const pendingPayload = this.toPendingPayloadInput(
585
617
  payloadInput,
586
618
  this.pendingPayloads.get(payloadInput.blockRootHex),
@@ -654,6 +686,7 @@ export class BlockInputSync {
654
686
  return {kind: "ready"};
655
687
  }
656
688
 
689
+ // The parent's payload is known but does not match `parentBlockHashHex`
657
690
  if (this.chain.forkChoice.hasPayloadHexUnsafe(parentRootHex)) {
658
691
  return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
659
692
  }
@@ -820,17 +853,20 @@ export class BlockInputSync {
820
853
  }
821
854
  };
822
855
 
823
- private scheduleRateLimitBackoffRetry(): void {
856
+ /**
857
+ * Returns false if there is no backoff left to wait for, in which case no retry is scheduled.
858
+ */
859
+ private scheduleRateLimitBackoffRetry(): boolean {
824
860
  this.clearRateLimitBackoffTimer();
825
861
 
826
862
  if (!this.subscribedToNetworkEvents || (this.pendingBlocks.size === 0 && this.pendingPayloads.size === 0)) {
827
- return;
863
+ return false;
828
864
  }
829
865
 
830
866
  const now = Date.now();
831
867
  const retryAt = this.peerBalancer.getNextRateLimitRetryAt();
832
868
  if (retryAt === null) {
833
- return;
869
+ return false;
834
870
  }
835
871
 
836
872
  this.rateLimitBackoffTimeout = setTimeout(
@@ -841,6 +877,7 @@ export class BlockInputSync {
841
877
  },
842
878
  Math.max(0, retryAt - now)
843
879
  );
880
+ return true;
844
881
  }
845
882
 
846
883
  private clearRateLimitBackoffTimer(): void {
@@ -881,16 +918,17 @@ export class BlockInputSync {
881
918
  * Poll unknown payloads of the current slot.
882
919
  */
883
920
  private async pollPayloadsAtSlot(slot: Slot, signal: AbortSignal): Promise<void> {
921
+ const fork = this.config.getForkName(slot);
884
922
  // fixed tick count so the loop cannot outlive its slot: for mainnet, it's 6 ticks
885
923
  const tickCount = Math.floor(
886
- (this.config.SLOT_DURATION_MS - this.config.getPayloadDueMs()) / PAYLOAD_POLL_INTERVAL_MS
924
+ (this.config.getSlotDurationMs(fork) - this.config.getPayloadDueMs(fork)) / PAYLOAD_POLL_INTERVAL_MS
887
925
  );
888
926
  // a root still missing on several ticks is searched on each of them, recorded once
889
927
  const searchedRoots = new Set<RootHex>();
890
928
  let polls = 0;
891
929
 
892
930
  try {
893
- await sleep(Math.max(0, this.config.getPayloadDueMs() - this.chain.clock.msFromSlot(slot)), signal);
931
+ await sleep(Math.max(0, this.config.getPayloadDueMs(fork) - this.chain.clock.msFromSlot(slot)), signal);
894
932
 
895
933
  for (polls = 0; polls < tickCount; polls++) {
896
934
  let importedCount = 0;
@@ -1032,7 +1070,8 @@ export class BlockInputSync {
1032
1070
  }
1033
1071
  } else if (blockSlot <= finalizedSlot) {
1034
1072
  // the common ancestor of the downloading chain and canonical chain should be at least the finalized slot and
1035
- // we should found it through forkchoice. If not, we should penalize all peers sending us this block chain
1073
+ // we should found it through forkchoice. If not, drop the chain without penalizing peers because pending entries are
1074
+ // block retained on failed download, so finalization can pass the block while it is still pending
1036
1075
  // 0 - 1 - ... - n - finalizedSlot
1037
1076
  // \
1038
1077
  // parent 1 - parent 2 - ... - unknownParent block
@@ -1040,7 +1079,7 @@ export class BlockInputSync {
1040
1079
  ...logCtx2,
1041
1080
  finalizedSlot,
1042
1081
  });
1043
- this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
1082
+ this.removeAllDescendants(block, DroppedItemReason.belowFinalized);
1044
1083
  } else {
1045
1084
  this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
1046
1085
  }
@@ -1051,7 +1090,11 @@ export class BlockInputSync {
1051
1090
  pendingBlock.status = PendingBlockInputStatus.pending;
1052
1091
  }
1053
1092
  this.logger.debug("Deferring unknown block download due to peer rate limit", logCtx, res.err);
1054
- this.scheduleRateLimitBackoffRetry();
1093
+ if (!this.scheduleRateLimitBackoffRetry() || res.err.retryAt <= Date.now()) {
1094
+ // The backoff this download waited for expired in the meantime, a timer is only armed if another
1095
+ // peer is still in backoff and would retry it later than needed
1096
+ this.triggerUnknownBlockSearch();
1097
+ }
1055
1098
  return;
1056
1099
  }
1057
1100
 
@@ -1172,15 +1215,18 @@ export class BlockInputSync {
1172
1215
  break;
1173
1216
 
1174
1217
  case BlockErrorCode.EXECUTION_ENGINE_INVALID:
1175
- // the peer served a bad block
1218
+ // Ban but do not downscore: optimistic-sync peers may forward and serve blocks whose payload is later
1219
+ // rejected by the execution engine. Per the spec, an INVALID execution payload SHOULD NOT cause a peer
1220
+ // to be down-scored or disconnected, only consensus-layer invalidity MAY.
1221
+ // https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
1176
1222
  this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
1177
- this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
1223
+ this.removeAndBanAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
1178
1224
  break;
1179
1225
 
1180
1226
  default:
1181
1227
  // Block is not correct with respect to our chain. Log error loudly
1182
1228
  this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
1183
- this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
1229
+ this.removeAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
1184
1230
  }
1185
1231
  }
1186
1232
 
@@ -1331,6 +1377,14 @@ export class BlockInputSync {
1331
1377
  if (!isPendingPayloadEnvelope(payload)) {
1332
1378
  payload.status = PendingPayloadInputStatus.pending;
1333
1379
  }
1380
+ if (
1381
+ res.err instanceof UnknownBlockRateLimitedError &&
1382
+ (!this.scheduleRateLimitBackoffRetry() || res.err.retryAt <= Date.now())
1383
+ ) {
1384
+ // The backoff this download waited for expired in the meantime, a timer is only armed if another
1385
+ // peer is still in backoff and would retry it later than needed
1386
+ this.triggerUnknownBlockSearch();
1387
+ }
1334
1388
  }
1335
1389
 
1336
1390
  private async processPayload(pendingPayload: PendingPayloadInput): Promise<void> {
@@ -1393,20 +1447,23 @@ export class BlockInputSync {
1393
1447
  pendingPayload.status = PendingPayloadInputStatus.downloaded;
1394
1448
  break;
1395
1449
 
1450
+ // The invalid envelope is evicted from the seen cache in the cases below, otherwise the next
1451
+ // attempt would reuse it instead of fetching another envelope from peers
1396
1452
  case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
1397
1453
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1454
+ this.chain.seenPayloadEnvelopeInputCache.removeInvalid(pendingPayload.payloadInput);
1398
1455
  this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.elInvalid);
1399
1456
  break;
1400
1457
 
1401
1458
  case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
1402
1459
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1460
+ this.chain.seenPayloadEnvelopeInputCache.removeInvalid(pendingPayload.payloadInput);
1403
1461
  this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidEnvelope);
1404
1462
  break;
1405
1463
 
1406
1464
  case PayloadErrorCode.INVALID_SIGNATURE:
1407
- // TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
1408
- // reintroducing envelope replacement / recreation flows.
1409
1465
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1466
+ this.chain.seenPayloadEnvelopeInputCache.removeInvalid(pendingPayload.payloadInput);
1410
1467
  this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
1411
1468
  break;
1412
1469
 
@@ -1452,16 +1509,21 @@ export class BlockInputSync {
1452
1509
  const pendingColumns = payloadInput?.hasAllData()
1453
1510
  ? new Set<number>()
1454
1511
  : new Set(payloadInput?.getMissingSampledColumnMeta().missing ?? []);
1512
+ // Same `now` for both calls, a backoff expiring in between would be reported as no peer available
1513
+ const now = Date.now();
1455
1514
  // prefer peers that gossiped this payload root to us (#9923)
1456
1515
  const peerMeta = this.peerBalancer.bestPeerForPendingColumns(
1457
1516
  pendingColumns,
1458
1517
  excludedPeers,
1459
- cacheItem.peerIdStrings
1518
+ cacheItem.peerIdStrings,
1519
+ now
1460
1520
  );
1461
1521
  if (peerMeta === null) {
1462
- if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
1522
+ const retryAt = this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers, now);
1523
+ if (retryAt !== null) {
1463
1524
  throw new UnknownBlockRateLimitedError(
1464
- `Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: peers with needed columns are rate-limited`
1525
+ `Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: peers with needed columns are rate-limited`,
1526
+ retryAt
1465
1527
  );
1466
1528
  }
1467
1529
 
@@ -1478,11 +1540,11 @@ export class BlockInputSync {
1478
1540
  }
1479
1541
 
1480
1542
  const {peerId, client: peerClient} = peerMeta;
1481
- cacheItem.peerIdStrings.add(peerId);
1482
1543
 
1483
1544
  try {
1484
1545
  if (!envelope) {
1485
1546
  envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
1547
+ cacheItem.peerIdStrings.add(peerId);
1486
1548
  const slotWasUnknown = typeof slot !== "number";
1487
1549
  slot = envelope.message.payload.slotNumber;
1488
1550
  if (slotWasUnknown) {
@@ -1524,6 +1586,8 @@ export class BlockInputSync {
1524
1586
  const missing = pendingPayload.payloadInput.getMissingSampledColumnMeta().missing;
1525
1587
  if (missing.length > 0) {
1526
1588
  const columnSidecars = await this.fetchPayloadColumns(peerMeta, pendingPayload.payloadInput, missing);
1589
+ // toPendingPayloadInput copied cacheItem's set, so add to the object that is carried forward
1590
+ pendingPayload.peerIdStrings.add(peerId);
1527
1591
  const seenTimestampSec = Date.now() / 1000;
1528
1592
  for (const columnSidecar of columnSidecars) {
1529
1593
  if (pendingPayload.payloadInput.hasColumn(columnSidecar.index)) {
@@ -1598,9 +1662,11 @@ export class BlockInputSync {
1598
1662
  );
1599
1663
  this.metrics?.blockInputSync.payloadFetchPeers.set({result: FetchResult.FailureMaxAttempts}, i - 1);
1600
1664
 
1601
- if (deferredByRateLimit && this.peerBalancer.getNextRateLimitRetryAt() !== null) {
1665
+ const retryAt = deferredByRateLimit ? this.peerBalancer.getNextRateLimitRetryAt() : null;
1666
+ if (retryAt !== null) {
1602
1667
  throw new UnknownBlockRateLimitedError(
1603
- `Error fetching payload with slot=${slot} root=${rootHex} after ${i - 1} attempts: peers are rate-limited`
1668
+ `Error fetching payload with slot=${slot} root=${rootHex} after ${i - 1} attempts: peers are rate-limited`,
1669
+ retryAt
1604
1670
  );
1605
1671
  }
1606
1672
  throw Error(`Error fetching payload with slot=${slot} root=${rootHex} after ${i - 1} attempts.`);
@@ -1692,16 +1758,21 @@ export class BlockInputSync {
1692
1758
  isPendingBlockInput(cacheItem) && isBlockInputColumns(cacheItem.blockInput)
1693
1759
  ? new Set(cacheItem.blockInput.getMissingSampledColumnMeta().missing)
1694
1760
  : defaultPendingColumns;
1761
+ // Same `now` for both calls, a backoff expiring in between would be reported as no peer available
1762
+ const now = Date.now();
1695
1763
  // prefer peers that gossiped this block root to us (#9923)
1696
1764
  const peerMeta = this.peerBalancer.bestPeerForPendingColumns(
1697
1765
  pendingColumns,
1698
1766
  excludedPeers,
1699
- cacheItem.peerIdStrings
1767
+ cacheItem.peerIdStrings,
1768
+ now
1700
1769
  );
1701
1770
  if (peerMeta === null) {
1702
- if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
1771
+ const retryAt = this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers, now);
1772
+ if (retryAt !== null) {
1703
1773
  throw new UnknownBlockRateLimitedError(
1704
- `Error fetching UnknownBlockRoot slot=${slot} root=${rootHex} after ${i}: peers with needed columns are rate-limited`
1774
+ `Error fetching UnknownBlockRoot slot=${slot} root=${rootHex} after ${i}: peers with needed columns are rate-limited`,
1775
+ retryAt
1705
1776
  );
1706
1777
  }
1707
1778
 
@@ -1716,8 +1787,6 @@ export class BlockInputSync {
1716
1787
  }
1717
1788
  const {peerId, client: peerClient} = peerMeta;
1718
1789
 
1719
- cacheItem.peerIdStrings.add(peerId);
1720
-
1721
1790
  try {
1722
1791
  const downloadResult = await downloadByRoot({
1723
1792
  config: this.config,
@@ -1728,6 +1797,7 @@ export class BlockInputSync {
1728
1797
  cacheItem,
1729
1798
  });
1730
1799
  cacheItem = downloadResult.result;
1800
+ cacheItem.peerIdStrings.add(peerId);
1731
1801
  if (slot === undefined) {
1732
1802
  slot = cacheItem.blockInput.slot;
1733
1803
  // we were not able to observe the time into slot when starting the fetch, do it now
@@ -1808,8 +1878,9 @@ export class BlockInputSync {
1808
1878
 
1809
1879
  const message = `Error fetching BlockInput with slot=${slot} root=${rootHex} after ${i - 1} attempts.`;
1810
1880
 
1811
- if (deferredByRateLimit && this.peerBalancer.getNextRateLimitRetryAt() !== null) {
1812
- throw new UnknownBlockRateLimitedError(`${message} Peers are rate-limited.`);
1881
+ const retryAt = deferredByRateLimit ? this.peerBalancer.getNextRateLimitRetryAt() : null;
1882
+ if (retryAt !== null) {
1883
+ throw new UnknownBlockRateLimitedError(`${message} Peers are rate-limited.`, retryAt);
1813
1884
  }
1814
1885
 
1815
1886
  if (!isPendingBlockInput(cacheItem)) {
@@ -1843,44 +1914,8 @@ export class BlockInputSync {
1843
1914
  throw Error(message);
1844
1915
  }
1845
1916
 
1846
- /**
1847
- * Gets all descendant blocks of `block` recursively from `pendingBlocks`.
1848
- * Assumes that if a parent block does not exist or is not processable, all descendant blocks are bad too.
1849
- * Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
1850
- * referenced more than one bad block.
1851
- */
1852
- private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
1853
- // Get all blocks that are a descendant of this one
1854
- const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
1855
- // just console log and do not penalize on pending/bad blocks for debugging
1856
- // console.log("removeAndDownscoreAllDescendants", {block});
1857
-
1858
- for (const block of badPendingBlocks) {
1859
- //
1860
- // TODO(fulu): why is this commented out here?
1861
- //
1862
- // this.knownBadBlocks.add(block.blockRootHex);
1863
- // for (const peerIdStr of block.peerIdStrings) {
1864
- // // TODO: Refactor peerRpcScores to work with peerIdStr only
1865
- // this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, "BadBlockByRoot");
1866
- // }
1867
- this.logger.debug("ignored Banning unknown block", {
1868
- slot: getBlockInputSyncCacheItemSlot(block),
1869
- root: getBlockInputSyncCacheItemRootHex(block),
1870
- peerIdStrings: Array.from(block.peerIdStrings)
1871
- .map((id) => prettyPrintPeerIdStr(id))
1872
- .join(","),
1873
- });
1874
- }
1875
-
1876
- // Prune knownBadBlocks
1877
- pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
1878
- }
1879
-
1880
1917
  // Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
1881
1918
  private removePendingPayloadAndDescendants(rootHex: RootHex, headReason: DroppedItemReason): void {
1882
- // Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
1883
- // later validation/finalization logic decides when it can leave memory.
1884
1919
  if (this.pendingPayloads.delete(rootHex)) {
1885
1920
  this.metrics?.blockInputSync.removedPayloads.inc({reason: headReason}, 1);
1886
1921
  }
@@ -1903,13 +1938,61 @@ export class BlockInputSync {
1903
1938
  }
1904
1939
  }
1905
1940
 
1941
+ /**
1942
+ * Same as `removeAndBanAllDescendants`, and downscores every peer that referenced or served a banned item, once per
1943
+ * peer. Only call for consensus-layer invalidity, never for an INVALID execution payload:
1944
+ * https://github.com/ethereum/consensus-specs/blob/master/specs/bellatrix/p2p-interface.md#the-reqresp-domain
1945
+ */
1946
+ private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
1947
+ const peersToReport = new Set<PeerIdStr>();
1948
+ for (const bannedBlock of this.removeAndBanAllDescendants(block, headReason)) {
1949
+ for (const peerIdStr of bannedBlock.peerIdStrings) {
1950
+ peersToReport.add(peerIdStr);
1951
+ }
1952
+ }
1953
+
1954
+ for (const peerIdStr of peersToReport) {
1955
+ this.network.reportPeer(peerIdStr, PeerAction.LowToleranceError, headReason);
1956
+ }
1957
+ }
1958
+
1959
+ /**
1960
+ * Removes `block` and all its pending descendants and bans their roots in `knownBadBlocks`. Only call when the chain
1961
+ * is provably bad: a banned root is never searched for again. Returns the banned items.
1962
+ */
1963
+ private removeAndBanAllDescendants(
1964
+ block: BlockInputSyncCacheItem,
1965
+ headReason: DroppedItemReason
1966
+ ): BlockInputSyncCacheItem[] {
1967
+ const bannedBlocks: BlockInputSyncCacheItem[] = [];
1968
+ for (const badBlock of this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent)) {
1969
+ const rootHex = getBlockInputSyncCacheItemRootHex(badBlock);
1970
+ // a gossip import may race a failing sync path, never ban a root fork choice has imported
1971
+ if (this.chain.forkChoice.hasBlockHex(rootHex)) {
1972
+ continue;
1973
+ }
1974
+ this.knownBadBlocks.add(rootHex);
1975
+ bannedBlocks.push(badBlock);
1976
+ this.logger.debug("Banning unknown block", {
1977
+ slot: getBlockInputSyncCacheItemSlot(badBlock),
1978
+ root: rootHex,
1979
+ reason: headReason,
1980
+ peerIdStrings: Array.from(badBlock.peerIdStrings)
1981
+ .map((id) => prettyPrintPeerIdStr(id))
1982
+ .join(","),
1983
+ });
1984
+ }
1985
+
1986
+ pruneSetToMax(this.knownBadBlocks, MAX_KNOWN_BAD_BLOCKS);
1987
+ return bannedBlocks;
1988
+ }
1989
+
1906
1990
  private removeAllDescendants(
1907
1991
  block: BlockInputSyncCacheItem,
1908
1992
  headReason: DroppedItemReason,
1909
1993
  descendantReason: DroppedItemReason = DroppedItemReason.invalidParent
1910
1994
  ): BlockInputSyncCacheItem[] {
1911
1995
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1912
- const slot = getBlockInputSyncCacheItemSlot(block);
1913
1996
  // Get all blocks that are a descendant of this one (index 0 is the head item itself)
1914
1997
  const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
1915
1998
 
@@ -1926,8 +2009,8 @@ export class BlockInputSync {
1926
2009
  // Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
1927
2010
  // importBlock()-owned lifecycle.
1928
2011
  this.logger.debug("Removing bad/unknown/incomplete BlockInputSyncCacheItem", {
1929
- slot,
1930
- blockRoot: rootHex,
2012
+ slot: getBlockInputSyncCacheItemSlot(block),
2013
+ root: rootHex,
1931
2014
  });
1932
2015
  }
1933
2016
 
@@ -1988,8 +2071,11 @@ export class UnknownBlockPeerBalancer {
1988
2071
  this.rateLimitedUntilByPeer.set(peerId, rateLimitedUntilMs);
1989
2072
  }
1990
2073
 
1991
- getNextRateLimitRetryAt(pendingColumns?: Set<number>, excludedPeers?: Set<PeerIdStr>): number | null {
1992
- const now = Date.now();
2074
+ getNextRateLimitRetryAt(
2075
+ pendingColumns?: Set<number>,
2076
+ excludedPeers?: Set<PeerIdStr>,
2077
+ now = Date.now()
2078
+ ): number | null {
1993
2079
  let retryAt: number | null = null;
1994
2080
 
1995
2081
  for (const [peerId, rateLimitedUntil] of this.rateLimitedUntilByPeer.entries()) {
@@ -2028,9 +2114,10 @@ export class UnknownBlockPeerBalancer {
2028
2114
  bestPeerForPendingColumns(
2029
2115
  pendingColumns: Set<number>,
2030
2116
  excludedPeers: Set<PeerIdStr>,
2031
- preferredPeers?: Set<PeerIdStr>
2117
+ preferredPeers?: Set<PeerIdStr>,
2118
+ now = Date.now()
2032
2119
  ): PeerSyncMeta | null {
2033
- const eligiblePeers = this.filterPeers(pendingColumns, excludedPeers);
2120
+ const eligiblePeers = this.filterPeers(pendingColumns, excludedPeers, now);
2034
2121
  if (eligiblePeers.length === 0) {
2035
2122
  return null;
2036
2123
  }
@@ -2071,8 +2158,7 @@ export class UnknownBlockPeerBalancer {
2071
2158
  return totalActiveRequests;
2072
2159
  }
2073
2160
 
2074
- private filterPeers(pendingDataColumns: Set<number>, excludedPeers: Set<PeerIdStr>): PeerIdStr[] {
2075
- const now = Date.now();
2161
+ private filterPeers(pendingDataColumns: Set<number>, excludedPeers: Set<PeerIdStr>, now: number): PeerIdStr[] {
2076
2162
  let maxColumnCount = 0;
2077
2163
  const considerPeers: {peerId: PeerIdStr; columnCount: number}[] = [];
2078
2164
  for (const [peerId, syncMeta] of this.peersMeta.entries()) {