@lodestar/beacon-node 1.47.0-dev.7481aa5850 → 1.47.0-dev.7aa8c9c93a

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 (237) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +3 -2
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +8 -1
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +2 -1
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  10. package/lib/api/impl/events/index.d.ts +1 -1
  11. package/lib/api/impl/events/index.d.ts.map +1 -1
  12. package/lib/api/impl/events/index.js +12 -3
  13. package/lib/api/impl/events/index.js.map +1 -1
  14. package/lib/api/rest/base.d.ts.map +1 -1
  15. package/lib/api/rest/base.js +7 -0
  16. package/lib/api/rest/base.js.map +1 -1
  17. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  18. package/lib/chain/blocks/importBlock.js +2 -7
  19. package/lib/chain/blocks/importBlock.js.map +1 -1
  20. package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
  21. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  22. package/lib/chain/blocks/importExecutionPayload.js +11 -9
  23. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  24. package/lib/chain/blocks/index.d.ts.map +1 -1
  25. package/lib/chain/blocks/index.js +14 -6
  26. package/lib/chain/blocks/index.js.map +1 -1
  27. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
  28. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  29. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
  30. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  31. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
  32. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  33. package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
  34. package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -1
  35. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  36. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
  37. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  38. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  39. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  40. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  41. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  42. package/lib/chain/bls/index.d.ts +1 -1
  43. package/lib/chain/bls/index.d.ts.map +1 -1
  44. package/lib/chain/bls/interface.d.ts +5 -5
  45. package/lib/chain/bls/interface.d.ts.map +1 -1
  46. package/lib/chain/bls/multithread/index.d.ts +5 -11
  47. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  48. package/lib/chain/bls/multithread/index.js +116 -101
  49. package/lib/chain/bls/multithread/index.js.map +1 -1
  50. package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
  51. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  52. package/lib/chain/bls/multithread/jobItem.js +10 -65
  53. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  54. package/lib/chain/bls/multithread/types.d.ts +29 -8
  55. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  56. package/lib/chain/bls/multithread/types.js +12 -0
  57. package/lib/chain/bls/multithread/types.js.map +1 -1
  58. package/lib/chain/bls/multithread/utils.d.ts +4 -0
  59. package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
  60. package/lib/chain/bls/multithread/utils.js +10 -0
  61. package/lib/chain/bls/multithread/utils.js.map +1 -1
  62. package/lib/chain/bls/multithread/worker.js +49 -23
  63. package/lib/chain/bls/multithread/worker.js.map +1 -1
  64. package/lib/chain/bls/singleThread.d.ts +4 -10
  65. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  66. package/lib/chain/bls/singleThread.js +8 -45
  67. package/lib/chain/bls/singleThread.js.map +1 -1
  68. package/lib/chain/bls/utils.d.ts +4 -4
  69. package/lib/chain/bls/utils.d.ts.map +1 -1
  70. package/lib/chain/bls/utils.js +18 -19
  71. package/lib/chain/bls/utils.js.map +1 -1
  72. package/lib/chain/chain.d.ts +2 -1
  73. package/lib/chain/chain.d.ts.map +1 -1
  74. package/lib/chain/chain.js +12 -5
  75. package/lib/chain/chain.js.map +1 -1
  76. package/lib/chain/errors/blockError.d.ts +1 -0
  77. package/lib/chain/errors/blockError.d.ts.map +1 -1
  78. package/lib/chain/errors/blockError.js +6 -1
  79. package/lib/chain/errors/blockError.js.map +1 -1
  80. package/lib/chain/errors/proposerPreferences.d.ts +6 -0
  81. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
  82. package/lib/chain/errors/proposerPreferences.js +1 -0
  83. package/lib/chain/errors/proposerPreferences.js.map +1 -1
  84. package/lib/chain/interface.d.ts +2 -1
  85. package/lib/chain/interface.d.ts.map +1 -1
  86. package/lib/chain/interface.js.map +1 -1
  87. package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
  88. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  89. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  90. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  91. package/lib/chain/opPools/attestationPool.js +1 -1
  92. package/lib/chain/opPools/attestationPool.js.map +1 -1
  93. package/lib/chain/opPools/payloadAttestationPool.js +3 -3
  94. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  95. package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
  96. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  97. package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
  98. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  99. package/lib/chain/opPools/utils.d.ts +1 -1
  100. package/lib/chain/opPools/utils.d.ts.map +1 -1
  101. package/lib/chain/opPools/utils.js +1 -1
  102. package/lib/chain/opPools/utils.js.map +1 -1
  103. package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
  104. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  105. package/lib/chain/seenCache/seenAttesters.js +25 -4
  106. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  107. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +30 -1
  108. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  109. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +123 -13
  110. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  111. package/lib/chain/validation/attestation.d.ts.map +1 -1
  112. package/lib/chain/validation/attestation.js +1 -4
  113. package/lib/chain/validation/attestation.js.map +1 -1
  114. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  115. package/lib/chain/validation/attesterSlashing.js +1 -1
  116. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  117. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  118. package/lib/chain/validation/executionPayloadBid.js +1 -2
  119. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  120. package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
  121. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  122. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  123. package/lib/chain/validation/payloadAttestationMessage.js +5 -14
  124. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  125. package/lib/chain/validation/proposerPreferences.d.ts +1 -1
  126. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
  127. package/lib/chain/validation/proposerPreferences.js +13 -4
  128. package/lib/chain/validation/proposerPreferences.js.map +1 -1
  129. package/lib/chain/validation/proposerSlashing.js +1 -1
  130. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  131. package/lib/metrics/metrics/lodestar.d.ts +45 -20
  132. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  133. package/lib/metrics/metrics/lodestar.js +87 -51
  134. package/lib/metrics/metrics/lodestar.js.map +1 -1
  135. package/lib/network/gossip/topic.d.ts +13 -0
  136. package/lib/network/gossip/topic.d.ts.map +1 -1
  137. package/lib/network/gossip/topic.js +37 -0
  138. package/lib/network/gossip/topic.js.map +1 -1
  139. package/lib/network/libp2p/index.d.ts.map +1 -1
  140. package/lib/network/libp2p/index.js +10 -2
  141. package/lib/network/libp2p/index.js.map +1 -1
  142. package/lib/network/network.d.ts.map +1 -1
  143. package/lib/network/network.js +22 -43
  144. package/lib/network/network.js.map +1 -1
  145. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  146. package/lib/network/processor/gossipHandlers.js +5 -1
  147. package/lib/network/processor/gossipHandlers.js.map +1 -1
  148. package/lib/network/reqresp/score.d.ts.map +1 -1
  149. package/lib/network/reqresp/score.js +5 -11
  150. package/lib/network/reqresp/score.js.map +1 -1
  151. package/lib/network/util.d.ts +0 -1
  152. package/lib/network/util.d.ts.map +1 -1
  153. package/lib/network/util.js +0 -4
  154. package/lib/network/util.js.map +1 -1
  155. package/lib/node/nodejs.d.ts +2 -1
  156. package/lib/node/nodejs.d.ts.map +1 -1
  157. package/lib/node/nodejs.js.map +1 -1
  158. package/lib/sync/range/batch.d.ts +23 -5
  159. package/lib/sync/range/batch.d.ts.map +1 -1
  160. package/lib/sync/range/batch.js +61 -22
  161. package/lib/sync/range/batch.js.map +1 -1
  162. package/lib/sync/range/chain.d.ts +2 -1
  163. package/lib/sync/range/chain.d.ts.map +1 -1
  164. package/lib/sync/range/chain.js +23 -10
  165. package/lib/sync/range/chain.js.map +1 -1
  166. package/lib/sync/types.d.ts.map +1 -1
  167. package/lib/sync/types.js.map +1 -1
  168. package/lib/sync/unknownBlock.d.ts +9 -0
  169. package/lib/sync/unknownBlock.d.ts.map +1 -1
  170. package/lib/sync/unknownBlock.js +99 -21
  171. package/lib/sync/unknownBlock.js.map +1 -1
  172. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  173. package/lib/sync/utils/downloadByRange.js +16 -11
  174. package/lib/sync/utils/downloadByRange.js.map +1 -1
  175. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  176. package/lib/sync/utils/downloadByRoot.js +3 -1
  177. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  178. package/package.json +35 -35
  179. package/src/api/impl/beacon/blocks/index.ts +3 -2
  180. package/src/api/impl/beacon/pool/index.ts +7 -1
  181. package/src/api/impl/beacon/state/utils.ts +2 -1
  182. package/src/api/impl/events/index.ts +12 -4
  183. package/src/api/rest/base.ts +7 -0
  184. package/src/chain/blocks/importBlock.ts +1 -6
  185. package/src/chain/blocks/importExecutionPayload.ts +12 -11
  186. package/src/chain/blocks/index.ts +18 -6
  187. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
  188. package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
  189. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
  190. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
  191. package/src/chain/bls/index.ts +1 -1
  192. package/src/chain/bls/interface.ts +7 -3
  193. package/src/chain/bls/multithread/index.ts +148 -120
  194. package/src/chain/bls/multithread/jobItem.ts +12 -82
  195. package/src/chain/bls/multithread/types.ts +33 -8
  196. package/src/chain/bls/multithread/utils.ts +11 -0
  197. package/src/chain/bls/multithread/worker.ts +85 -27
  198. package/src/chain/bls/singleThread.ts +11 -55
  199. package/src/chain/bls/utils.ts +23 -24
  200. package/src/chain/chain.ts +13 -6
  201. package/src/chain/errors/blockError.ts +8 -2
  202. package/src/chain/errors/proposerPreferences.ts +7 -0
  203. package/src/chain/interface.ts +2 -1
  204. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  205. package/src/chain/opPools/attestationPool.ts +1 -1
  206. package/src/chain/opPools/payloadAttestationPool.ts +3 -3
  207. package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
  208. package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
  209. package/src/chain/opPools/utils.ts +1 -1
  210. package/src/chain/seenCache/seenAttesters.ts +31 -5
  211. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +145 -14
  212. package/src/chain/validation/attestation.ts +1 -7
  213. package/src/chain/validation/attesterSlashing.ts +1 -8
  214. package/src/chain/validation/executionPayloadBid.ts +1 -2
  215. package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
  216. package/src/chain/validation/payloadAttestationMessage.ts +6 -17
  217. package/src/chain/validation/proposerPreferences.ts +15 -5
  218. package/src/chain/validation/proposerSlashing.ts +1 -1
  219. package/src/metrics/metrics/lodestar.ts +97 -54
  220. package/src/network/gossip/topic.ts +38 -0
  221. package/src/network/libp2p/index.ts +11 -2
  222. package/src/network/network.ts +27 -55
  223. package/src/network/processor/gossipHandlers.ts +5 -1
  224. package/src/network/reqresp/score.ts +5 -11
  225. package/src/network/util.ts +0 -5
  226. package/src/node/nodejs.ts +2 -1
  227. package/src/sync/range/batch.ts +83 -28
  228. package/src/sync/range/chain.ts +26 -11
  229. package/src/sync/types.ts +3 -1
  230. package/src/sync/unknownBlock.ts +115 -26
  231. package/src/sync/utils/downloadByRange.ts +21 -12
  232. package/src/sync/utils/downloadByRoot.ts +3 -1
  233. package/lib/chain/bls/maybeBatch.d.ts +0 -12
  234. package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
  235. package/lib/chain/bls/maybeBatch.js +0 -35
  236. package/lib/chain/bls/maybeBatch.js.map +0 -1
  237. package/src/chain/bls/maybeBatch.ts +0 -45
@@ -4,7 +4,10 @@ import {ArchiveStoreTask} from "../../chain/archiveStore/archiveStore.js";
4
4
  import {FrequencyStateArchiveStep} from "../../chain/archiveStore/strategies/frequencyStateArchiveStrategy.js";
5
5
  import {BlockInputSource} from "../../chain/blocks/blockInput/index.js";
6
6
  import {PayloadErrorCode} from "../../chain/blocks/importExecutionPayload.js";
7
- import {PayloadEnvelopeInputSource} from "../../chain/blocks/payloadEnvelopeInput/index.js";
7
+ import {
8
+ PayloadEnvelopeInputPruneReason,
9
+ PayloadEnvelopeInputSource,
10
+ } from "../../chain/blocks/payloadEnvelopeInput/index.js";
8
11
  import {JobQueueItemType} from "../../chain/bls/index.js";
9
12
  import {AttestationErrorCode, BlockErrorCode} from "../../chain/errors/index.js";
10
13
  import {
@@ -31,6 +34,10 @@ import {RegistryMetricCreator} from "../utils/registryMetricCreator.js";
31
34
 
32
35
  export type LodestarMetrics = ReturnType<typeof createLodestarMetrics>;
33
36
 
37
+ type BlsJobOutcome = "valid" | "invalid" | "prepError" | "verifyError" | "workerError";
38
+ type BlsBufferFlushReason = "size" | "timeout";
39
+ type BlsVerificationCallOperation = "batch" | "single" | "fallback" | "same_message";
40
+
34
41
  /**
35
42
  * Extra Lodestar custom metrics
36
43
  */
@@ -396,86 +403,108 @@ export function createLodestarMetrics(
396
403
  // BLS verifier thread pool and queue
397
404
 
398
405
  bls: {
399
- aggregatedPubkeys: register.gauge({
406
+ aggregatedPubkeys: register.counter({
400
407
  name: "lodestar_bls_aggregated_pubkeys_total",
401
- help: "Total aggregated pubkeys for BLS validation",
408
+ help: "Total validator public keys used as inputs to aggregate signature sets",
409
+ }),
410
+ pubkeyCacheSize: register.gauge({
411
+ name: "lodestar_bls_pubkey_cache_size",
412
+ help: "Current number of validator public keys in the native cache",
413
+ }),
414
+ pubkeyCacheCapacity: register.gauge({
415
+ name: "lodestar_bls_pubkey_cache_capacity",
416
+ help: "Number of validator public keys the native cache can hold without growing",
402
417
  }),
403
418
  },
404
419
 
405
420
  blsThreadPool: {
406
- jobsWorkerTime: register.gauge<{workerId: number}>({
421
+ jobsWorkerTime: register.counter<{workerId: number}>({
407
422
  name: "lodestar_bls_thread_pool_time_seconds_sum",
408
- help: "Total time spent verifying signature sets measured on the worker",
423
+ help: "Cumulative wall time spent processing BLS dispatch groups by worker",
409
424
  labelNames: ["workerId"],
410
425
  }),
411
- successJobsSignatureSetsCount: register.gauge({
426
+ successJobsSignatureSetsCount: register.counter({
412
427
  name: "lodestar_bls_thread_pool_success_jobs_signature_sets_count",
413
- help: "Count of total verified signature sets",
414
- }),
415
- errorAggregateSignatureSetsCount: register.gauge<{type: JobQueueItemType}>({
416
- name: "lodestar_bls_thread_pool_error_aggregate_signature_sets_count",
417
- help: "Count of error when aggregating pubkeys or signatures",
418
- labelNames: ["type"],
428
+ help: "Count of signature sets completed without an operational error",
419
429
  }),
420
- errorJobsSignatureSetsCount: register.gauge({
430
+ errorJobsSignatureSetsCount: register.counter({
421
431
  name: "lodestar_bls_thread_pool_error_jobs_signature_sets_count",
422
- help: "Count of total error-ed signature sets",
432
+ help: "Count of signature sets that ended in an input, binding, or worker error",
423
433
  }),
424
- jobWaitTime: register.histogram({
434
+ jobWaitTime: register.histogram<{type: JobQueueItemType}>({
425
435
  name: "lodestar_bls_thread_pool_queue_job_wait_time_seconds",
426
- help: "Time from job added to the queue to starting the job in seconds",
427
- buckets: [0.01, 0.02, 0.1, 0.3, 0.5, 1],
436
+ help: "Time from adding a BLS job until it is selected for a worker dispatch group",
437
+ labelNames: ["type"],
438
+ buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2],
439
+ }),
440
+ jobDuration: register.histogram<{type: JobQueueItemType}>({
441
+ name: "lodestar_bls_thread_pool_job_duration_seconds",
442
+ help: "End-to-end duration of a BLS job from submission through completion",
443
+ labelNames: ["type"],
444
+ buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2],
445
+ }),
446
+ jobResults: register.counter<{type: JobQueueItemType; outcome: BlsJobOutcome}>({
447
+ name: "lodestar_bls_thread_pool_job_results_total",
448
+ help: "Count of completed BLS jobs by cryptographic or operational outcome",
449
+ labelNames: ["type", "outcome"],
428
450
  }),
429
451
  queueLength: register.gauge({
430
452
  name: "lodestar_bls_thread_pool_queue_length",
431
- help: "Count of total block processor queue length",
453
+ help: "Count of ready BLS jobs waiting for a worker",
454
+ }),
455
+ bufferedQueueLength: register.gauge({
456
+ name: "lodestar_bls_thread_pool_buffered_queue_length",
457
+ help: "Count of BLS jobs waiting in the intentional batching buffer",
432
458
  }),
433
459
  workersBusy: register.gauge({
434
460
  name: "lodestar_bls_thread_pool_workers_busy",
435
461
  help: "Count of current busy workers",
436
462
  }),
437
- totalJobsGroupsStarted: register.gauge({
463
+ totalJobsGroupsStarted: register.counter({
438
464
  name: "lodestar_bls_thread_pool_job_groups_started_total",
439
- help: "Count of total jobs groups started in bls thread pool, job groups include +1 jobs",
465
+ help: "Count of worker dispatch groups started by the BLS thread pool",
440
466
  }),
441
- totalJobsStarted: register.gauge<{type: JobQueueItemType}>({
467
+ totalJobsStarted: register.counter<{type: JobQueueItemType}>({
442
468
  name: "lodestar_bls_thread_pool_jobs_started_total",
443
- help: "Count of total jobs started in bls thread pool, jobs include +1 signature sets",
469
+ help: "Count of jobs started by the BLS thread pool",
444
470
  labelNames: ["type"],
445
471
  }),
446
- totalSigSetsStarted: register.gauge<{type: JobQueueItemType}>({
472
+ totalSigSetsStarted: register.counter<{type: JobQueueItemType}>({
447
473
  name: "lodestar_bls_thread_pool_sig_sets_started_total",
448
- help: "Count of total signature sets started in bls thread pool, sig sets include 1 pk, msg, sig",
474
+ help: "Count of signature sets started by the BLS thread pool",
449
475
  labelNames: ["type"],
450
476
  }),
451
477
  // Re-verifying a batch means doing double work. This number must be very low or it can be a waste of CPU resources
452
- batchRetries: register.gauge({
478
+ batchRetries: register.counter({
453
479
  name: "lodestar_bls_thread_pool_batch_retries_total",
454
- help: "Count of total batches that failed and had to be verified again.",
480
+ help: "Count of combined batches that failed and required per-job fallback",
455
481
  }),
456
482
  // To count how many sigs are being validated with the optimization of batching them
457
- batchSigsSuccess: register.gauge({
483
+ batchSigsSuccess: register.counter({
458
484
  name: "lodestar_bls_thread_pool_batch_sigs_success_total",
459
- help: "Count of total batches that failed and had to be verified again.",
485
+ help: "Count of signature sets accepted by combined batch verification without fallback",
460
486
  }),
461
- sameMessageRetryJobs: register.gauge({
462
- name: "lodestar_bls_thread_pool_same_message_jobs_retries_total",
463
- help: "Count of total same message jobs that failed and had to be verified again.",
487
+ bufferFlushes: register.counter<{reason: BlsBufferFlushReason}>({
488
+ name: "lodestar_bls_thread_pool_buffer_flushes_total",
489
+ help: "Count of batching-buffer flushes by trigger",
490
+ labelNames: ["reason"],
464
491
  }),
465
- sameMessageRetrySets: register.gauge({
466
- name: "lodestar_bls_thread_pool_same_message_sets_retries_total",
467
- help: "Count of total same message sets that failed and had to be verified again.",
492
+ bufferedSignatureSets: register.histogram({
493
+ name: "lodestar_bls_thread_pool_buffered_signature_sets",
494
+ help: "Count of signature sets included in each batching-buffer flush",
495
+ buckets: [1, 8, 16, 24, 28, 32, 36, 40, 44, 48, 64, 128],
468
496
  }),
469
497
  // To measure the time cost of main thread <-> worker message passing
470
498
  latencyToWorker: register.histogram({
471
499
  name: "lodestar_bls_thread_pool_latency_to_worker",
472
500
  help: "Time from sending the job to the worker and the worker receiving it",
473
- buckets: [0.001, 0.003, 0.01, 0.03, 0.1],
501
+ // The dashboard treats 20ms as slow; values above 100ms only need severe-stall classification.
502
+ buckets: [0.00025, 0.001, 0.005, 0.02, 0.1],
474
503
  }),
475
504
  latencyFromWorker: register.histogram({
476
505
  name: "lodestar_bls_thread_pool_latency_from_worker",
477
506
  help: "Time from the worker sending the result and the main thread receiving it",
478
- buckets: [0.001, 0.003, 0.01, 0.03, 0.1],
507
+ buckets: [0.00025, 0.001, 0.005, 0.02, 0.1],
479
508
  }),
480
509
  mainThreadDurationInThreadPool: register.histogram({
481
510
  name: "lodestar_bls_thread_pool_main_thread_time_seconds",
@@ -485,32 +514,40 @@ export function createLodestarMetrics(
485
514
  }),
486
515
  timePerSigSet: register.histogram({
487
516
  name: "lodestar_bls_worker_thread_time_per_sigset_seconds",
488
- help: "Time to verify each sigset with worker thread mode",
517
+ help: "Average BLS worker dispatch wall time per original signature set",
489
518
  // Time per sig ~0.9ms on good machines
490
- buckets: [0.5e-3, 0.75e-3, 1e-3, 1.5e-3, 2e-3, 5e-3],
491
- }),
492
- totalSigSets: register.gauge({
519
+ buckets: [0.5e-3, 0.75e-3, 1e-3, 1.5e-3, 2e-3, 5e-3, 10e-3, 20e-3, 50e-3, 100e-3],
520
+ }),
521
+ workRequestPreparationDuration: register.histogram({
522
+ name: "lodestar_bls_thread_pool_work_request_preparation_duration_seconds",
523
+ help: "Main-thread time spent converting one worker dispatch group to binding inputs",
524
+ // Normal requests take microseconds; the dashboard treats 1ms as a main-thread stall.
525
+ buckets: [0.000005, 0.000025, 0.0001, 0.0005, 0.001, 0.005, 0.025],
526
+ }),
527
+ verificationCallDuration: register.histogram<{operation: BlsVerificationCallOperation}>({
528
+ name: "lodestar_bls_thread_pool_verification_call_duration_seconds",
529
+ help: "Duration of one worker-side lodestar-z verification binding call, including input conversion",
530
+ labelNames: ["operation"],
531
+ // Verification ranges from sub-millisecond calls to large batches; above 500ms is uniformly severe.
532
+ buckets: [0.00025, 0.001, 0.005, 0.02, 0.1, 0.5],
533
+ }),
534
+ verificationCallSignatureSets: register.counter<{operation: BlsVerificationCallOperation}>({
535
+ name: "lodestar_bls_thread_pool_verification_call_signature_sets_total",
536
+ help: "Count of signature sets passed to worker-side lodestar-z verification binding calls",
537
+ labelNames: ["operation"],
538
+ }),
539
+ totalSigSets: register.counter({
493
540
  name: "lodestar_bls_thread_pool_sig_sets_total",
494
541
  help: "Count of total signature sets",
495
542
  }),
496
- prioritizedSigSets: register.gauge({
543
+ prioritizedSigSets: register.counter({
497
544
  name: "lodestar_bls_thread_pool_prioritized_sig_sets_total",
498
545
  help: "Count of total prioritized signature sets",
499
546
  }),
500
- batchableSigSets: register.gauge({
547
+ batchableSigSets: register.counter({
501
548
  name: "lodestar_bls_thread_pool_batchable_sig_sets_total",
502
549
  help: "Count of total batchable signature sets",
503
550
  }),
504
- aggregateWithRandomnessAsyncDuration: register.histogram({
505
- name: "lodestar_bls_thread_pool_aggregate_with_randomness_async_time_seconds",
506
- help: "Total time performing aggregateWithRandomness async",
507
- buckets: [0.001, 0.005, 0.01, 0.1, 0.3],
508
- }),
509
- pubkeysAggregationMainThreadDuration: register.histogram({
510
- name: "lodestar_bls_thread_pool_pubkeys_aggregation_main_thread_time_seconds",
511
- help: "Total time spent aggregating pubkeys on main thread",
512
- buckets: [0.001, 0.005, 0.01, 0.1],
513
- }),
514
551
  },
515
552
 
516
553
  // BLS time on single thread mode
@@ -1609,9 +1646,15 @@ export function createLodestarMetrics(
1609
1646
  name: "lodestar_seen_payload_envelope_input_cache_serialized_object_refs",
1610
1647
  help: "Number of serialized-cache object refs retained by cached PayloadEnvelopeInputs",
1611
1648
  }),
1612
- created: register.counter({
1649
+ created: register.counter<{source: PayloadEnvelopeInputSource}>({
1613
1650
  name: "lodestar_seen_payload_envelope_input_cache_items_created_total",
1614
- help: "Number of PayloadEnvelopeInputs created",
1651
+ help: "Number of PayloadEnvelopeInputs created by source",
1652
+ labelNames: ["source"],
1653
+ }),
1654
+ pruned: register.counter<{reason: PayloadEnvelopeInputPruneReason}>({
1655
+ name: "lodestar_seen_payload_envelope_input_cache_items_pruned_total",
1656
+ help: "Number of PayloadEnvelopeInputs evicted by reason",
1657
+ labelNames: ["reason"],
1615
1658
  }),
1616
1659
  },
1617
1660
  },
@@ -414,3 +414,41 @@ export const gossipTopicIgnoreDuplicatePublishError: Record<GossipType, boolean>
414
414
  [GossipType.execution_payload_bid]: true,
415
415
  [GossipType.proposer_preferences]: true,
416
416
  };
417
+
418
+ /**
419
+ * Whether a publish that reached zero subscribed peers is an acceptable outcome for a topic.
420
+ *
421
+ * Publishing to a topic with no subscribed peers throws `PublishError.NoPeersSubscribedToTopic`, which
422
+ * propagates to the caller and, for messages submitted through the beacon API, is surfaced to the
423
+ * validator client. That is the right default: a message that reached nobody is a failed broadcast, and a
424
+ * VC configured with several beacon nodes can fall back to another one.
425
+ *
426
+ * Only topics that have a concrete reason to tolerate it opt out here, ie. are set to `true`, and the
427
+ * reason is named on the entry. Everything else is `false` and keeps raising. Note this is applied per
428
+ * publish, a topic set to `false` still honors the global `--network.allowPublishToZeroPeers` flag.
429
+ */
430
+ export const gossipTopicAllowPublishToZeroPeers: Record<GossipType, boolean> = {
431
+ [GossipType.beacon_block]: false,
432
+ [GossipType.blob_sidecar]: false,
433
+ // data_column_sidecar: we ensure having all topic peers via prioritizePeers(). Even with 0 peers on the
434
+ // topic the overall publish can still succeed, because a supernode rebuilds and publishes the missing
435
+ // columns for us, so track sent peers as 0 instead of raising
436
+ [GossipType.data_column_sidecar]: true,
437
+ [GossipType.beacon_aggregate_and_proof]: false,
438
+ [GossipType.beacon_attestation]: false,
439
+ [GossipType.voluntary_exit]: false,
440
+ [GossipType.proposer_slashing]: false,
441
+ [GossipType.attester_slashing]: false,
442
+ [GossipType.sync_committee_contribution_and_proof]: false,
443
+ [GossipType.sync_committee]: false,
444
+ // light_client_finality_update and light_client_optimistic_update: non-mandatory route on most of the
445
+ // network as of Oct 2022, there may be no peer subscribed to the topic at all. Reason carried over from
446
+ // the handlers in network.ts, which used to swallow the error instead
447
+ [GossipType.light_client_finality_update]: true,
448
+ [GossipType.light_client_optimistic_update]: true,
449
+ [GossipType.bls_to_execution_change]: false,
450
+ [GossipType.execution_payload]: false,
451
+ [GossipType.payload_attestation_message]: false,
452
+ [GossipType.execution_payload_bid]: false,
453
+ [GossipType.proposer_preferences]: false,
454
+ };
@@ -1,3 +1,4 @@
1
+ import {getCiphers} from "node:crypto";
1
2
  import {bootstrap} from "@libp2p/bootstrap";
2
3
  import {identify} from "@libp2p/identify";
3
4
  import type {PrivateKey} from "@libp2p/interface";
@@ -9,12 +10,20 @@ import {Libp2pInit, createLibp2p} from "libp2p";
9
10
  import {Registry} from "prom-client";
10
11
  import {ENR} from "@chainsafe/enr";
11
12
  import {noise} from "@chainsafe/libp2p-noise";
12
- import {defaultCrypto} from "@chainsafe/libp2p-noise/crypto";
13
+ import {asCrypto, defaultCrypto} from "@chainsafe/libp2p-noise/crypto";
13
14
  import {quic} from "@chainsafe/libp2p-quic";
14
15
  import {Libp2p, LodestarComponents} from "../interface.js";
15
16
  import {NetworkOptions, defaultNetworkOptions} from "../options.js";
16
17
  import {Eth2PeerDataStore} from "../peers/datastore.js";
17
18
 
19
+ const noiseCrypto = getCiphers().includes("chacha20-poly1305")
20
+ ? defaultCrypto
21
+ : {
22
+ ...defaultCrypto,
23
+ chaCha20Poly1305Encrypt: asCrypto.chaCha20Poly1305Encrypt,
24
+ chaCha20Poly1305Decrypt: asCrypto.chaCha20Poly1305Decrypt,
25
+ };
26
+
18
27
  export type NodeJsLibp2pOpts = {
19
28
  peerStoreDir?: string;
20
29
  disablePeerDiscovery?: boolean;
@@ -122,7 +131,7 @@ export async function createNodeJsLibp2p(
122
131
  listen: localMultiaddrs,
123
132
  announce: [],
124
133
  },
125
- connectionEncrypters: [noise({crypto: defaultCrypto})],
134
+ connectionEncrypters: [noise({crypto: noiseCrypto})],
126
135
  transports,
127
136
  streamMuxers: [mplex({disconnectThreshold})],
128
137
  peerDiscovery,
@@ -49,7 +49,12 @@ import {INetworkCore, NetworkCore, WorkerNetworkCore} from "./core/index.js";
49
49
  import {INetworkEventBus, NetworkEvent, NetworkEventBus, NetworkEventData} from "./events.js";
50
50
  import {getActiveForkBoundaries} from "./forks.js";
51
51
  import {GossipHandlers, GossipTopicMap, GossipType, GossipTypeMap} from "./gossip/index.js";
52
- import {getGossipSSZType, gossipTopicIgnoreDuplicatePublishError, stringifyGossipTopic} from "./gossip/topic.js";
52
+ import {
53
+ getGossipSSZType,
54
+ gossipTopicAllowPublishToZeroPeers,
55
+ gossipTopicIgnoreDuplicatePublishError,
56
+ stringifyGossipTopic,
57
+ } from "./gossip/topic.js";
53
58
  import {INetwork} from "./interface.js";
54
59
  import {NetworkOptions} from "./options.js";
55
60
  import {PeerAction, PeerScoreStats} from "./peers/index.js";
@@ -65,7 +70,7 @@ import {
65
70
  } from "./reqresp/utils/collect.js";
66
71
  import {collectSequentialBlocksInRange} from "./reqresp/utils/collectSequentialBlocksInRange.js";
67
72
  import {CommitteeSubscription} from "./subnets/index.js";
68
- import {isPublishDuplicateError, isPublishToZeroPeersError, prettyPrintPeerIdStr} from "./util.js";
73
+ import {isPublishDuplicateError, prettyPrintPeerIdStr} from "./util.js";
69
74
 
70
75
  type NetworkModules = {
71
76
  opts: NetworkOptions;
@@ -352,9 +357,7 @@ export class Network implements INetwork {
352
357
  const epoch = computeEpochAtSlot(signedBlock.message.slot);
353
358
  const boundary = this.config.getForkBoundaryAtEpoch(epoch);
354
359
 
355
- return this.publishGossip<GossipType.beacon_block>({type: GossipType.beacon_block, boundary}, signedBlock, {
356
- ignoreDuplicatePublishError: true,
357
- });
360
+ return this.publishGossip<GossipType.beacon_block>({type: GossipType.beacon_block, boundary}, signedBlock);
358
361
  }
359
362
 
360
363
  async publishBlobSidecar(blobSidecar: deneb.BlobSidecar): Promise<number> {
@@ -363,9 +366,7 @@ export class Network implements INetwork {
363
366
 
364
367
  const subnet = blobSidecar.index;
365
368
 
366
- return this.publishGossip<GossipType.blob_sidecar>({type: GossipType.blob_sidecar, boundary, subnet}, blobSidecar, {
367
- ignoreDuplicatePublishError: true,
368
- });
369
+ return this.publishGossip<GossipType.blob_sidecar>({type: GossipType.blob_sidecar, boundary, subnet}, blobSidecar);
369
370
  }
370
371
 
371
372
  async publishDataColumnSidecar(
@@ -381,14 +382,7 @@ export class Network implements INetwork {
381
382
  try {
382
383
  const sentPeers = await this.publishGossip<GossipType.data_column_sidecar>(
383
384
  {type: GossipType.data_column_sidecar, boundary, subnet},
384
- dataColumnSidecar,
385
- {
386
- // we ensure having all topic peers via prioritizePeers() function
387
- // in the worse case, if there is 0 peer on the topic, the overall publish operation could be still a success
388
- // because supernode will rebuild and publish missing data column sidecars for us
389
- // hence we want to track sent peers as 0 instead of an error
390
- allowPublishToZeroTopicPeers: true,
391
- }
385
+ dataColumnSidecar
392
386
  );
393
387
  return {sentPeers, alreadyPublished: false};
394
388
  } catch (e) {
@@ -405,8 +399,7 @@ export class Network implements INetwork {
405
399
 
406
400
  return this.publishGossip<GossipType.beacon_aggregate_and_proof>(
407
401
  {type: GossipType.beacon_aggregate_and_proof, boundary},
408
- aggregateAndProof,
409
- {ignoreDuplicatePublishError: true}
402
+ aggregateAndProof
410
403
  );
411
404
  }
412
405
 
@@ -416,8 +409,7 @@ export class Network implements INetwork {
416
409
 
417
410
  return this.publishGossip<GossipType.beacon_attestation>(
418
411
  {type: GossipType.beacon_attestation, boundary, subnet},
419
- attestation,
420
- {ignoreDuplicatePublishError: true}
412
+ attestation
421
413
  );
422
414
  }
423
415
 
@@ -425,9 +417,7 @@ export class Network implements INetwork {
425
417
  const epoch = voluntaryExit.message.epoch;
426
418
  const boundary = this.config.getForkBoundaryAtEpoch(epoch);
427
419
 
428
- return this.publishGossip<GossipType.voluntary_exit>({type: GossipType.voluntary_exit, boundary}, voluntaryExit, {
429
- ignoreDuplicatePublishError: true,
430
- });
420
+ return this.publishGossip<GossipType.voluntary_exit>({type: GossipType.voluntary_exit, boundary}, voluntaryExit);
431
421
  }
432
422
 
433
423
  async publishBlsToExecutionChange(blsToExecutionChange: capella.SignedBLSToExecutionChange): Promise<number> {
@@ -438,8 +428,7 @@ export class Network implements INetwork {
438
428
  if (fork >= ForkSeq.capella) {
439
429
  const publishPromise = this.publishGossip<GossipType.bls_to_execution_change>(
440
430
  {type: GossipType.bls_to_execution_change, boundary},
441
- blsToExecutionChange,
442
- {ignoreDuplicatePublishError: true}
431
+ blsToExecutionChange
443
432
  );
444
433
  publishChanges.push(publishPromise);
445
434
  }
@@ -457,8 +446,7 @@ export class Network implements INetwork {
457
446
 
458
447
  return this.publishGossip<GossipType.proposer_slashing>(
459
448
  {type: GossipType.proposer_slashing, boundary},
460
- proposerSlashing,
461
- {ignoreDuplicatePublishError: true}
449
+ proposerSlashing
462
450
  );
463
451
  }
464
452
 
@@ -478,10 +466,7 @@ export class Network implements INetwork {
478
466
 
479
467
  return this.publishGossip<GossipType.sync_committee>(
480
468
  {type: GossipType.sync_committee, boundary, subnet},
481
- signature,
482
- {
483
- ignoreDuplicatePublishError: true,
484
- }
469
+ signature
485
470
  );
486
471
  }
487
472
 
@@ -491,8 +476,7 @@ export class Network implements INetwork {
491
476
 
492
477
  return this.publishGossip<GossipType.sync_committee_contribution_and_proof>(
493
478
  {type: GossipType.sync_committee_contribution_and_proof, boundary},
494
- contributionAndProof,
495
- {ignoreDuplicatePublishError: true}
479
+ contributionAndProof
496
480
  );
497
481
  }
498
482
 
@@ -522,8 +506,7 @@ export class Network implements INetwork {
522
506
 
523
507
  return this.publishGossip<GossipType.execution_payload>(
524
508
  {type: GossipType.execution_payload, boundary},
525
- signedEnvelope,
526
- {ignoreDuplicatePublishError: true}
509
+ signedEnvelope
527
510
  );
528
511
  }
529
512
 
@@ -533,8 +516,7 @@ export class Network implements INetwork {
533
516
 
534
517
  return this.publishGossip<GossipType.execution_payload_bid>(
535
518
  {type: GossipType.execution_payload_bid, boundary},
536
- signedBid,
537
- {ignoreDuplicatePublishError: true}
519
+ signedBid
538
520
  );
539
521
  }
540
522
 
@@ -544,8 +526,7 @@ export class Network implements INetwork {
544
526
 
545
527
  return this.publishGossip<GossipType.payload_attestation_message>(
546
528
  {type: GossipType.payload_attestation_message, boundary},
547
- payloadAttestationMessage,
548
- {ignoreDuplicatePublishError: true}
529
+ payloadAttestationMessage
549
530
  );
550
531
  }
551
532
 
@@ -555,22 +536,21 @@ export class Network implements INetwork {
555
536
 
556
537
  return this.publishGossip<GossipType.proposer_preferences>(
557
538
  {type: GossipType.proposer_preferences, boundary},
558
- signedProposerPreferences,
559
- {ignoreDuplicatePublishError: true}
539
+ signedProposerPreferences
560
540
  );
561
541
  }
562
542
 
563
543
  private async publishGossip<K extends GossipType>(
564
544
  topic: GossipTopicMap[K],
565
- object: GossipTypeMap[K],
566
- opts?: PublishOpts | undefined
545
+ object: GossipTypeMap[K]
567
546
  ): Promise<number> {
568
547
  const topicStr = stringifyGossipTopic(this.config, topic);
569
548
  const sszType = getGossipSSZType(topic);
570
549
  const messageData = (sszType.serialize as (object: GossipTypeMap[GossipType]) => Uint8Array)(object);
571
- opts = {
572
- ...opts,
550
+ const opts: PublishOpts = {
573
551
  ignoreDuplicatePublishError: gossipTopicIgnoreDuplicatePublishError[topic.type],
552
+ // Leave undefined unless the topic opts out, so `--network.allowPublishToZeroPeers` still applies
553
+ allowPublishToZeroTopicPeers: gossipTopicAllowPublishToZeroPeers[topic.type] ? true : undefined,
574
554
  };
575
555
  const sentPeers = await this.core.publishGossip(topicStr, messageData, opts);
576
556
 
@@ -813,11 +793,7 @@ export class Network implements INetwork {
813
793
  await this.waitForSyncMessageCutoff(finalityUpdate.signatureSlot);
814
794
  await this.publishLightClientFinalityUpdate(finalityUpdate);
815
795
  } catch (e) {
816
- // Non-mandatory route on most of network as of Oct 2022. May not have found any peers on topic yet
817
- // Remove once https://github.com/ChainSafe/js-libp2p-gossipsub/issues/367
818
- if (!isPublishToZeroPeersError(e as Error)) {
819
- this.logger.debug("Error on BeaconGossipHandler.onLightclientFinalityUpdate", {}, e as Error);
820
- }
796
+ this.logger.debug("Error on BeaconGossipHandler.onLightclientFinalityUpdate", {}, e as Error);
821
797
  }
822
798
  };
823
799
 
@@ -830,11 +806,7 @@ export class Network implements INetwork {
830
806
  await this.waitForSyncMessageCutoff(optimisticUpdate.signatureSlot);
831
807
  await this.publishLightClientOptimisticUpdate(optimisticUpdate);
832
808
  } catch (e) {
833
- // Non-mandatory route on most of network as of Oct 2022. May not have found any peers on topic yet
834
- // Remove once https://github.com/ChainSafe/js-libp2p-gossipsub/issues/367
835
- if (!isPublishToZeroPeersError(e as Error)) {
836
- this.logger.debug("Error on BeaconGossipHandler.onLightclientOptimisticUpdate", {}, e as Error);
837
- }
809
+ this.logger.debug("Error on BeaconGossipHandler.onLightclientOptimisticUpdate", {}, e as Error);
838
810
  }
839
811
  };
840
812
 
@@ -196,7 +196,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
196
196
  forkName: fork,
197
197
  sampledColumns: chain.custodyConfig.sampledColumns,
198
198
  custodyColumns: chain.custodyConfig.custodyColumns,
199
- timeCreatedSec: seenTimestampSec,
199
+ seenTimestampSec,
200
+ source: PayloadEnvelopeInputSource.gossip,
200
201
  });
201
202
  }
202
203
 
@@ -640,6 +641,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
640
641
  metrics?.gossipBlock.elapsedTimeTillProcessed.observe(delaySec);
641
642
 
642
643
  if (isForkPostGloas(blockInput.forkName)) {
644
+ // we should have the payloadInput in the seen cache so no need getOrReload() here
643
645
  const payloadInput = chain.seenPayloadEnvelopeInputCache.get(blockInput.blockRootHex);
644
646
  // This payloadInput should have been created just after gossip validation
645
647
  if (!payloadInput) {
@@ -1189,6 +1191,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1189
1191
  chain.validatorMonitor?.registerExecutionPayloadEnvelope(OpSource.gossip, delaySec, signedEnvelope);
1190
1192
 
1191
1193
  const blockRootHex = toRootHex(envelope.beaconBlockRoot);
1194
+ // a gossip payload cannot be `MAX_PAYLOAD_ENVELOPE_INPUT_CACHE_SIZE` slots after the block
1195
+ // otherwise it'll get to UnknownBlockInput flow
1192
1196
  const payloadInput = chain.seenPayloadEnvelopeInputCache.get(blockRootHex);
1193
1197
 
1194
1198
  if (!payloadInput) {
@@ -44,17 +44,11 @@ export function onOutgoingReqRespError(e: RequestError, method: ReqRespMethod):
44
44
  // failure, so keep the stronger penalty (Fatal for Ping, as before).
45
45
  return method === ReqRespMethod.Ping ? PeerAction.Fatal : PeerAction.LowToleranceError;
46
46
  }
47
- switch (method) {
48
- // Ping and Status are liveness probes; their dial timeouts are dominated by transient
49
- // network congestion rather than peer misbehavior, so penalize leniently to avoid
50
- // self-inflicted peer starvation (https://github.com/ChainSafe/lodestar/issues/9562),
51
- // while still applying some penalty so genuinely dead peers eventually free the slot.
52
- case ReqRespMethod.Ping:
53
- case ReqRespMethod.Status:
54
- return PeerAction.HighToleranceError;
55
- default:
56
- return PeerAction.LowToleranceError;
57
- }
47
+ // A dial failure means we could not open a stream. That is evidence about the transport, not
48
+ // about the peer's behavior, and it is dominated by transient congestion on our side, so
49
+ // penalize leniently for every method to avoid self-inflicted peer starvation (#9562). A
50
+ // genuinely dead peer still accumulates penalty and is eventually evicted, freeing the slot.
51
+ return PeerAction.HighToleranceError;
58
52
  // TODO: Detect SSZDecodeError and return PeerAction.Fatal
59
53
 
60
54
  case RequestErrorCode.RESP_TIMEOUT:
@@ -23,11 +23,6 @@ export function getConnection(libp2p: Libp2p, peerIdStr: string): Connection | u
23
23
  return getConnectionsMap(libp2p).get(peerIdStr)?.value[0] ?? undefined;
24
24
  }
25
25
 
26
- // https://github.com/libp2p/js-libp2p/blob/f87cba928991736d9646b3e054c367f55cab315c/packages/gossipsub/src/gossipsub.ts#L2076
27
- export function isPublishToZeroPeersError(e: Error): boolean {
28
- return e.message.includes("PublishError.NoPeersSubscribedToTopic");
29
- }
30
-
31
26
  // https://github.com/libp2p/js-libp2p/blob/f87cba928991736d9646b3e054c367f55cab315c/packages/gossipsub/src/gossipsub.ts#L2076
32
27
  export function isPublishDuplicateError(e: Error): boolean {
33
28
  return e.message.includes("PublishError.Duplicate");
@@ -1,12 +1,13 @@
1
1
  import {setMaxListeners} from "node:events";
2
2
  import {PrivateKey} from "@libp2p/interface";
3
3
  import {Registry} from "prom-client";
4
+ import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
4
5
  import {hasher} from "@chainsafe/persistent-merkle-tree";
5
6
  import {BeaconApiMethods} from "@lodestar/api/beacon/server";
6
7
  import {BeaconConfig} from "@lodestar/config";
7
8
  import type {LoggerNode} from "@lodestar/logger/node";
8
9
  import {ZERO_HASH_HEX} from "@lodestar/params";
9
- import {IBeaconStateView, PubkeyCache, isStatePostBellatrix, isStatePostGloas} from "@lodestar/state-transition";
10
+ import {IBeaconStateView, isStatePostBellatrix, isStatePostGloas} from "@lodestar/state-transition";
10
11
  import {phase0} from "@lodestar/types";
11
12
  import {sleep, toRootHex} from "@lodestar/utils";
12
13
  import {ProcessShutdownCallback} from "@lodestar/validator";