@aztec/p2p 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2 → 0.76.0

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 (262) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +38 -0
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -0
  3. package/dest/bootstrap/bootstrap.js +31 -38
  4. package/dest/client/factory.d.ts +21 -0
  5. package/dest/client/factory.d.ts.map +1 -0
  6. package/dest/client/factory.js +13 -11
  7. package/dest/client/index.d.ts +3 -0
  8. package/dest/client/index.d.ts.map +1 -0
  9. package/dest/client/index.js +1 -0
  10. package/dest/client/p2p_client.d.ts +332 -0
  11. package/dest/client/p2p_client.d.ts.map +1 -0
  12. package/dest/client/p2p_client.js +535 -513
  13. package/dest/config.d.ts +187 -0
  14. package/dest/config.d.ts.map +1 -0
  15. package/dest/config.js +64 -53
  16. package/dest/errors/reqresp.error.d.ts +28 -0
  17. package/dest/errors/reqresp.error.d.ts.map +1 -0
  18. package/dest/errors/reqresp.error.js +10 -6
  19. package/dest/index.d.ts +9 -0
  20. package/dest/index.d.ts.map +1 -0
  21. package/dest/index.js +1 -0
  22. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +57 -0
  23. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -0
  24. package/dest/mem_pools/attestation_pool/attestation_pool.js +2 -6
  25. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +3 -0
  26. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -0
  27. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +32 -64
  28. package/dest/mem_pools/attestation_pool/index.d.ts +3 -0
  29. package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -0
  30. package/dest/mem_pools/attestation_pool/index.js +1 -0
  31. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +22 -0
  32. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -0
  33. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +19 -22
  34. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +17 -0
  35. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -0
  36. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +26 -22
  37. package/dest/mem_pools/attestation_pool/mocks.d.ts +18 -0
  38. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -0
  39. package/dest/mem_pools/attestation_pool/mocks.js +6 -10
  40. package/dest/mem_pools/epoch_proof_quote_pool/epoch_proof_quote_pool.d.ts +7 -0
  41. package/dest/mem_pools/epoch_proof_quote_pool/epoch_proof_quote_pool.d.ts.map +1 -0
  42. package/dest/mem_pools/epoch_proof_quote_pool/epoch_proof_quote_pool.js +2 -1
  43. package/dest/mem_pools/epoch_proof_quote_pool/index.d.ts +4 -0
  44. package/dest/mem_pools/epoch_proof_quote_pool/index.d.ts.map +1 -0
  45. package/dest/mem_pools/epoch_proof_quote_pool/index.js +1 -0
  46. package/dest/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.d.ts +12 -0
  47. package/dest/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.d.ts.map +1 -0
  48. package/dest/mem_pools/epoch_proof_quote_pool/memory_epoch_proof_quote_pool.js +4 -5
  49. package/dest/mem_pools/epoch_proof_quote_pool/test_utils.d.ts +8 -0
  50. package/dest/mem_pools/epoch_proof_quote_pool/test_utils.d.ts.map +1 -0
  51. package/dest/mem_pools/epoch_proof_quote_pool/test_utils.js +3 -2
  52. package/dest/mem_pools/index.d.ts +5 -0
  53. package/dest/mem_pools/index.d.ts.map +1 -0
  54. package/dest/mem_pools/index.js +2 -1
  55. package/dest/mem_pools/instrumentation.d.ts +31 -0
  56. package/dest/mem_pools/instrumentation.d.ts.map +1 -0
  57. package/dest/mem_pools/instrumentation.js +42 -37
  58. package/dest/mem_pools/interface.d.ts +13 -0
  59. package/dest/mem_pools/interface.d.ts.map +1 -0
  60. package/dest/mem_pools/interface.js +2 -3
  61. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +66 -0
  62. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -0
  63. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +134 -127
  64. package/dest/mem_pools/tx_pool/index.d.ts +4 -0
  65. package/dest/mem_pools/tx_pool/index.d.ts.map +1 -0
  66. package/dest/mem_pools/tx_pool/index.js +1 -0
  67. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +56 -0
  68. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -0
  69. package/dest/mem_pools/tx_pool/memory_tx_pool.js +43 -45
  70. package/dest/mem_pools/tx_pool/priority.d.ts +8 -0
  71. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -0
  72. package/dest/mem_pools/tx_pool/priority.js +3 -1
  73. package/dest/mem_pools/tx_pool/tx_pool.d.ts +66 -0
  74. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -0
  75. package/dest/mem_pools/tx_pool/tx_pool.js +2 -3
  76. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +7 -0
  77. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -0
  78. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +37 -107
  79. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +8 -0
  80. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -0
  81. package/dest/msg_validators/attestation_validator/attestation_validator.js +3 -3
  82. package/dest/msg_validators/attestation_validator/index.d.ts +2 -0
  83. package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -0
  84. package/dest/msg_validators/attestation_validator/index.js +1 -0
  85. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +8 -0
  86. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -0
  87. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +2 -2
  88. package/dest/msg_validators/block_proposal_validator/index.d.ts +2 -0
  89. package/dest/msg_validators/block_proposal_validator/index.d.ts.map +1 -0
  90. package/dest/msg_validators/block_proposal_validator/index.js +1 -0
  91. package/dest/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.d.ts +8 -0
  92. package/dest/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.d.ts.map +1 -0
  93. package/dest/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.js +2 -2
  94. package/dest/msg_validators/epoch_proof_quote_validator/index.d.ts +2 -0
  95. package/dest/msg_validators/epoch_proof_quote_validator/index.d.ts.map +1 -0
  96. package/dest/msg_validators/epoch_proof_quote_validator/index.js +1 -0
  97. package/dest/msg_validators/index.d.ts +4 -0
  98. package/dest/msg_validators/index.d.ts.map +1 -0
  99. package/dest/msg_validators/index.js +1 -0
  100. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +7 -0
  101. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -0
  102. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +11 -9
  103. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +11 -0
  104. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -0
  105. package/dest/msg_validators/tx_validator/block_header_validator.js +12 -17
  106. package/dest/msg_validators/tx_validator/data_validator.d.ts +6 -0
  107. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -0
  108. package/dest/msg_validators/tx_validator/data_validator.js +32 -41
  109. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +12 -0
  110. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -0
  111. package/dest/msg_validators/tx_validator/double_spend_validator.js +14 -22
  112. package/dest/msg_validators/tx_validator/index.d.ts +7 -0
  113. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -0
  114. package/dest/msg_validators/tx_validator/index.js +1 -0
  115. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +10 -0
  116. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -0
  117. package/dest/msg_validators/tx_validator/metadata_validator.js +26 -29
  118. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +8 -0
  119. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -0
  120. package/dest/msg_validators/tx_validator/tx_proof_validator.js +12 -17
  121. package/dest/services/data_store.d.ts +27 -0
  122. package/dest/services/data_store.d.ts.map +1 -0
  123. package/dest/services/data_store.js +57 -57
  124. package/dest/services/discv5/discV5_service.d.ts +40 -0
  125. package/dest/services/discv5/discV5_service.d.ts.map +1 -0
  126. package/dest/services/discv5/discV5_service.js +82 -43
  127. package/dest/services/dummy_service.d.ts +83 -0
  128. package/dest/services/dummy_service.d.ts.map +1 -0
  129. package/dest/services/dummy_service.js +59 -40
  130. package/dest/services/encoding.d.ts +31 -0
  131. package/dest/services/encoding.d.ts.map +1 -0
  132. package/dest/services/encoding.js +9 -10
  133. package/dest/services/index.d.ts +3 -0
  134. package/dest/services/index.d.ts.map +1 -0
  135. package/dest/services/index.js +1 -0
  136. package/dest/services/libp2p/libp2p_logger.d.ts +7 -0
  137. package/dest/services/libp2p/libp2p_logger.d.ts.map +1 -0
  138. package/dest/services/libp2p/libp2p_logger.js +67 -0
  139. package/dest/services/libp2p/libp2p_service.d.ts +225 -0
  140. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -0
  141. package/dest/services/libp2p/libp2p_service.js +727 -709
  142. package/dest/services/peer-manager/metrics.d.ts +12 -0
  143. package/dest/services/peer-manager/metrics.d.ts.map +1 -0
  144. package/dest/services/peer-manager/metrics.js +7 -14
  145. package/dest/services/peer-manager/peer_manager.d.ts +76 -0
  146. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -0
  147. package/dest/services/peer-manager/peer_manager.js +342 -340
  148. package/dest/services/peer-manager/peer_scoring.d.ts +28 -0
  149. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -0
  150. package/dest/services/peer-manager/peer_scoring.js +18 -20
  151. package/dest/services/reqresp/config.d.ts +16 -0
  152. package/dest/services/reqresp/config.d.ts.map +1 -0
  153. package/dest/services/reqresp/config.js +5 -4
  154. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +45 -0
  155. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -0
  156. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +28 -35
  157. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +61 -0
  158. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -0
  159. package/dest/services/reqresp/connection-sampler/connection_sampler.js +59 -60
  160. package/dest/services/reqresp/index.d.ts +6 -0
  161. package/dest/services/reqresp/index.d.ts.map +1 -0
  162. package/dest/services/reqresp/index.js +3 -1
  163. package/dest/services/reqresp/interface.d.ts +116 -0
  164. package/dest/services/reqresp/interface.d.ts.map +1 -0
  165. package/dest/services/reqresp/interface.js +30 -25
  166. package/dest/services/reqresp/metrics.d.ts +15 -0
  167. package/dest/services/reqresp/metrics.d.ts.map +1 -0
  168. package/dest/services/reqresp/metrics.js +10 -23
  169. package/dest/services/reqresp/protocols/block.d.ts +4 -0
  170. package/dest/services/reqresp/protocols/block.d.ts.map +1 -0
  171. package/dest/services/reqresp/protocols/block.js +2 -1
  172. package/dest/services/reqresp/protocols/goodbye.d.ts +51 -0
  173. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -0
  174. package/dest/services/reqresp/protocols/goodbye.js +41 -36
  175. package/dest/services/reqresp/protocols/index.d.ts +9 -0
  176. package/dest/services/reqresp/protocols/index.d.ts.map +1 -0
  177. package/dest/services/reqresp/protocols/index.js +3 -1
  178. package/dest/services/reqresp/protocols/ping.d.ts +9 -0
  179. package/dest/services/reqresp/protocols/ping.d.ts.map +1 -0
  180. package/dest/services/reqresp/protocols/ping.js +3 -1
  181. package/dest/services/reqresp/protocols/status.d.ts +9 -0
  182. package/dest/services/reqresp/protocols/status.d.ts.map +1 -0
  183. package/dest/services/reqresp/protocols/status.js +3 -1
  184. package/dest/services/reqresp/protocols/tx.d.ts +13 -0
  185. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -0
  186. package/dest/services/reqresp/protocols/tx.js +8 -5
  187. package/dest/services/reqresp/rate-limiter/index.d.ts +2 -0
  188. package/dest/services/reqresp/rate-limiter/index.d.ts.map +1 -0
  189. package/dest/services/reqresp/rate-limiter/index.js +1 -0
  190. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +102 -0
  191. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -0
  192. package/dest/services/reqresp/rate-limiter/rate_limiter.js +35 -39
  193. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +3 -0
  194. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -0
  195. package/dest/services/reqresp/rate-limiter/rate_limits.js +17 -16
  196. package/dest/services/reqresp/reqresp.d.ts +166 -0
  197. package/dest/services/reqresp/reqresp.d.ts.map +1 -0
  198. package/dest/services/reqresp/reqresp.js +463 -460
  199. package/dest/services/reqresp/status.d.ts +31 -0
  200. package/dest/services/reqresp/status.d.ts.map +1 -0
  201. package/dest/services/reqresp/status.js +17 -16
  202. package/dest/services/service.d.ts +86 -0
  203. package/dest/services/service.d.ts.map +1 -0
  204. package/dest/services/service.js +4 -3
  205. package/dest/services/types.d.ts +32 -0
  206. package/dest/services/types.d.ts.map +1 -0
  207. package/dest/services/types.js +19 -20
  208. package/dest/test-helpers/generate-peer-id-private-keys.d.ts +7 -0
  209. package/dest/test-helpers/generate-peer-id-private-keys.d.ts.map +1 -0
  210. package/dest/test-helpers/generate-peer-id-private-keys.js +15 -0
  211. package/dest/test-helpers/get-ports.d.ts +7 -0
  212. package/dest/test-helpers/get-ports.d.ts.map +1 -0
  213. package/dest/test-helpers/get-ports.js +8 -0
  214. package/dest/test-helpers/index.d.ts +6 -0
  215. package/dest/test-helpers/index.d.ts.map +1 -0
  216. package/dest/test-helpers/index.js +6 -0
  217. package/dest/test-helpers/make-enrs.d.ts +16 -0
  218. package/dest/test-helpers/make-enrs.d.ts.map +1 -0
  219. package/dest/test-helpers/make-enrs.js +35 -0
  220. package/dest/test-helpers/make-test-p2p-clients.d.ts +37 -0
  221. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -0
  222. package/dest/test-helpers/make-test-p2p-clients.js +71 -0
  223. package/dest/test-helpers/reqresp-nodes.d.ts +55 -0
  224. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -0
  225. package/dest/test-helpers/reqresp-nodes.js +183 -0
  226. package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -0
  227. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -0
  228. package/dest/testbench/p2p_client_testbench_worker.js +125 -0
  229. package/dest/util.d.ts +53 -0
  230. package/dest/util.d.ts.map +1 -0
  231. package/dest/util.js +34 -23
  232. package/dest/versioning.d.ts +12 -0
  233. package/dest/versioning.d.ts.map +1 -0
  234. package/dest/versioning.js +38 -0
  235. package/package.json +11 -9
  236. package/src/bootstrap/bootstrap.ts +9 -3
  237. package/src/client/factory.ts +12 -5
  238. package/src/config.ts +56 -29
  239. package/src/mem_pools/index.ts +3 -3
  240. package/src/mem_pools/instrumentation.ts +2 -3
  241. package/src/msg_validators/attestation_validator/attestation_validator.ts +3 -3
  242. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +3 -3
  243. package/src/msg_validators/epoch_proof_quote_validator/epoch_proof_quote_validator.ts +3 -3
  244. package/src/services/discv5/discV5_service.ts +67 -18
  245. package/src/services/dummy_service.ts +2 -0
  246. package/src/services/libp2p/libp2p_logger.ts +78 -0
  247. package/src/services/libp2p/libp2p_service.ts +47 -10
  248. package/src/services/reqresp/protocols/goodbye.ts +1 -1
  249. package/src/services/reqresp/reqresp.ts +9 -1
  250. package/src/services/service.ts +2 -0
  251. package/src/services/types.ts +2 -10
  252. package/src/test-helpers/generate-peer-id-private-keys.ts +15 -0
  253. package/src/test-helpers/get-ports.ts +8 -0
  254. package/src/test-helpers/index.ts +5 -0
  255. package/src/test-helpers/make-enrs.ts +44 -0
  256. package/src/test-helpers/make-test-p2p-clients.ts +124 -0
  257. package/src/{mocks/index.ts → test-helpers/reqresp-nodes.ts} +10 -5
  258. package/src/testbench/README.md +20 -0
  259. package/src/testbench/p2p_client_testbench_worker.ts +156 -0
  260. package/src/testbench/scripts/run_testbench.sh +7 -0
  261. package/src/versioning.ts +50 -0
  262. package/dest/mocks/index.js +0 -190
@@ -1,9 +1,4 @@
1
- function _ts_decorate(decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- }
1
+ import { __esDecorate, __runInitializers } from "tslib";
7
2
  import { createLogger } from '@aztec/foundation/log';
8
3
  import { trackSpan } from '@aztec/telemetry-client';
9
4
  import { inspect } from 'util';
@@ -16,345 +11,348 @@ const MAX_DIAL_ATTEMPTS = 3;
16
11
  const MAX_CACHED_PEERS = 100;
17
12
  const MAX_CACHED_PEER_AGE_MS = 5 * 60 * 1000; // 5 minutes
18
13
  const FAILED_PEER_BAN_TIME_MS = 5 * 60 * 1000; // 5 minutes timeout after failing MAX_DIAL_ATTEMPTS
19
- export class PeerManager {
20
- libP2PNode;
21
- peerDiscoveryService;
22
- config;
23
- logger;
24
- peerScoring;
25
- reqresp;
26
- cachedPeers;
27
- heartbeatCounter;
28
- displayPeerCountsPeerHeartbeat;
29
- timedOutPeers;
30
- metrics;
31
- discoveredPeerHandler;
32
- constructor(libP2PNode, peerDiscoveryService, config, telemetryClient, logger = createLogger('p2p:peer-manager'), peerScoring, reqresp){
33
- this.libP2PNode = libP2PNode;
34
- this.peerDiscoveryService = peerDiscoveryService;
35
- this.config = config;
36
- this.logger = logger;
37
- this.peerScoring = peerScoring;
38
- this.reqresp = reqresp;
39
- this.cachedPeers = new Map();
40
- this.heartbeatCounter = 0;
41
- this.displayPeerCountsPeerHeartbeat = 0;
42
- this.timedOutPeers = new Map();
43
- this.metrics = new PeerManagerMetrics(telemetryClient, 'PeerManager');
44
- // Handle new established connections
45
- this.libP2PNode.addEventListener(PeerEvent.CONNECTED, this.handleConnectedPeerEvent.bind(this));
46
- // Handle lost connections
47
- this.libP2PNode.addEventListener(PeerEvent.DISCONNECTED, this.handleDisconnectedPeerEvent.bind(this));
48
- // Handle Discovered peers
49
- this.discoveredPeerHandler = (enr)=>this.handleDiscoveredPeer(enr).catch((e)=>this.logger.error('Error handling discovered peer', e));
50
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
51
- this.peerDiscoveryService.on(PeerEvent.DISCOVERED, this.discoveredPeerHandler);
52
- // Display peer counts every 60 seconds
53
- this.displayPeerCountsPeerHeartbeat = Math.floor(60_000 / this.config.peerCheckIntervalMS);
54
- }
55
- get tracer() {
56
- return this.metrics.tracer;
57
- }
58
- heartbeat() {
59
- this.heartbeatCounter++;
60
- this.peerScoring.decayAllScores();
61
- this.cleanupExpiredTimeouts();
62
- this.discover();
63
- }
64
- /**
65
- * Cleans up expired timeouts.
66
- *
67
- * When peers fail to dial after a number of retries, they are temporarily timed out.
68
- * This function removes any peers that have been in the timed out state for too long.
69
- * To give them a chance to reconnect.
70
- */ cleanupExpiredTimeouts() {
71
- // Clean up expired timeouts
72
- const now = Date.now();
73
- for (const [peerId, timedOutPeer] of this.timedOutPeers.entries()){
74
- if (now >= timedOutPeer.timeoutUntilMs) {
75
- this.timedOutPeers.delete(peerId);
14
+ let PeerManager = (() => {
15
+ var _a;
16
+ let _instanceExtraInitializers = [];
17
+ let _heartbeat_decorators;
18
+ return _a = class PeerManager {
19
+ constructor(libP2PNode, peerDiscoveryService, config, telemetryClient, logger = createLogger('p2p:peer-manager'), peerScoring, reqresp) {
20
+ this.libP2PNode = (__runInitializers(this, _instanceExtraInitializers), libP2PNode);
21
+ this.peerDiscoveryService = peerDiscoveryService;
22
+ this.config = config;
23
+ this.logger = logger;
24
+ this.peerScoring = peerScoring;
25
+ this.reqresp = reqresp;
26
+ this.cachedPeers = new Map();
27
+ this.heartbeatCounter = 0;
28
+ this.displayPeerCountsPeerHeartbeat = 0;
29
+ this.timedOutPeers = new Map();
30
+ this.metrics = new PeerManagerMetrics(telemetryClient, 'PeerManager');
31
+ // Handle new established connections
32
+ this.libP2PNode.addEventListener(PeerEvent.CONNECTED, this.handleConnectedPeerEvent.bind(this));
33
+ // Handle lost connections
34
+ this.libP2PNode.addEventListener(PeerEvent.DISCONNECTED, this.handleDisconnectedPeerEvent.bind(this));
35
+ // Handle Discovered peers
36
+ this.discoveredPeerHandler = (enr) => this.handleDiscoveredPeer(enr).catch(e => this.logger.error('Error handling discovered peer', e));
37
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
38
+ this.peerDiscoveryService.on(PeerEvent.DISCOVERED, this.discoveredPeerHandler);
39
+ // Display peer counts every 60 seconds
40
+ this.displayPeerCountsPeerHeartbeat = Math.floor(60000 / this.config.peerCheckIntervalMS);
76
41
  }
77
- }
78
- }
79
- /**
80
- * Simply logs the type of connected peer.
81
- * @param e - The connected peer event.
82
- */ handleConnectedPeerEvent(e) {
83
- const peerId = e.detail;
84
- if (this.peerDiscoveryService.isBootstrapPeer(peerId)) {
85
- this.logger.verbose(`Connected to bootstrap peer ${peerId.toString()}`);
86
- } else {
87
- this.logger.verbose(`Connected to transaction peer ${peerId.toString()}`);
88
- }
89
- }
90
- /**
91
- * Simply logs the type of disconnected peer.
92
- * @param e - The disconnected peer event.
93
- */ handleDisconnectedPeerEvent(e) {
94
- const peerId = e.detail;
95
- if (this.peerDiscoveryService.isBootstrapPeer(peerId)) {
96
- this.logger.verbose(`Disconnected from bootstrap peer ${peerId.toString()}`);
97
- } else {
98
- this.logger.verbose(`Disconnected from transaction peer ${peerId.toString()}`);
99
- }
100
- }
101
- /**
102
- * Handles a goodbye received from a peer.
103
- *
104
- * Used as the reqresp handler when a peer sends us goodbye message.
105
- * @param peerId - The peer ID.
106
- * @param reason - The reason for the goodbye.
107
- */ goodbyeReceived(peerId, reason) {
108
- this.logger.debug(`Goodbye received from peer ${peerId.toString()} with reason ${prettyGoodbyeReason(reason)}`);
109
- this.metrics.recordGoodbyeReceived(reason);
110
- void this.disconnectPeer(peerId);
111
- }
112
- penalizePeer(peerId, penalty) {
113
- this.peerScoring.penalizePeer(peerId, penalty);
114
- }
115
- getPeerScore(peerId) {
116
- return this.peerScoring.getScore(peerId);
117
- }
118
- getPeers(includePending = false) {
119
- const connected = this.libP2PNode.getPeers().map((peer)=>({
120
- id: peer.toString(),
121
- score: this.getPeerScore(peer.toString()),
122
- status: 'connected'
123
- }));
124
- if (!includePending) {
125
- return connected;
126
- }
127
- const dialQueue = this.libP2PNode.getDialQueue().filter((peer)=>!!peer.peerId).map((peer)=>({
128
- id: peer.peerId.toString(),
129
- status: 'dialing',
130
- dialStatus: peer.status,
131
- addresses: peer.multiaddrs.map((m)=>m.toString())
132
- }));
133
- const cachedPeers = Array.from(this.cachedPeers.values()).filter((peer)=>!dialQueue.some((dialPeer)=>dialPeer.id && peer.peerId.toString() === dialPeer.id.toString())).filter((peer)=>!connected.some((connPeer)=>connPeer.id.toString() === peer.peerId.toString())).map((peer)=>({
134
- status: 'cached',
135
- id: peer.peerId.toString(),
136
- addresses: [
137
- peer.multiaddrTcp.toString()
138
- ],
139
- dialAttempts: peer.dialAttempts,
140
- enr: peer.enr.encodeTxt()
141
- }));
142
- return [
143
- ...connected,
144
- ...dialQueue,
145
- ...cachedPeers
146
- ];
147
- }
148
- /**
149
- * Discovers peers.
150
- */ discover() {
151
- const connections = this.libP2PNode.getConnections();
152
- const healthyConnections = this.pruneUnhealthyPeers(connections);
153
- // Calculate how many connections we're looking to make
154
- const peersToConnect = this.config.maxPeerCount - healthyConnections.length;
155
- const logLevel = this.heartbeatCounter % this.displayPeerCountsPeerHeartbeat === 0 ? 'info' : 'debug';
156
- this.logger[logLevel](`Connected to ${connections.length} peers`, {
157
- connections: connections.length,
158
- maxPeerCount: this.config.maxPeerCount,
159
- cachedPeers: this.cachedPeers.size,
160
- ...this.peerScoring.getStats()
161
- });
162
- // Exit if no peers to connect
163
- if (peersToConnect <= 0) {
164
- return;
165
- }
166
- const cachedPeersToDial = [];
167
- const pendingDials = new Set(this.libP2PNode.getDialQueue().map((pendingDial)=>pendingDial.peerId?.toString()).filter(Boolean));
168
- for (const [id, peerData] of this.cachedPeers.entries()){
169
- // if already dialling or connected to, remove from cache
170
- if (pendingDials.has(id) || healthyConnections.some((conn)=>conn.remotePeer.equals(peerData.peerId)) || // if peer has been in cache for the max cache age, remove from cache
171
- Date.now() - peerData.addedUnixMs > MAX_CACHED_PEER_AGE_MS) {
172
- this.cachedPeers.delete(id);
173
- } else {
174
- // cachedPeersToDial.set(id, enr);
175
- cachedPeersToDial.push(peerData);
42
+ get tracer() {
43
+ return this.metrics.tracer;
176
44
  }
177
- }
178
- // reverse to dial older entries first
179
- cachedPeersToDial.reverse();
180
- for (const peer of cachedPeersToDial){
181
- // We remove from the cache before, as dialling will add it back if it fails
182
- this.cachedPeers.delete(peer.peerId.toString());
183
- void this.dialPeer(peer);
184
- }
185
- // if we need more peers, start randomNodesQuery
186
- if (peersToConnect > 0) {
187
- this.logger.trace(`Running random nodes query to connect to ${peersToConnect} peers`);
188
- void this.peerDiscoveryService.runRandomNodesQuery();
189
- }
190
- }
191
- pruneUnhealthyPeers(connections) {
192
- const connectedHealthyPeers = [];
193
- for (const peer of connections){
194
- const score = this.peerScoring.getScoreState(peer.remotePeer.toString());
195
- switch(score){
196
- case PeerScoreState.Banned:
197
- void this.goodbyeAndDisconnectPeer(peer.remotePeer, GoodByeReason.BANNED);
198
- break;
199
- case PeerScoreState.Disconnect:
200
- void this.goodbyeAndDisconnectPeer(peer.remotePeer, GoodByeReason.DISCONNECTED);
201
- break;
202
- case PeerScoreState.Healthy:
203
- connectedHealthyPeers.push(peer);
45
+ heartbeat() {
46
+ this.heartbeatCounter++;
47
+ this.peerScoring.decayAllScores();
48
+ this.cleanupExpiredTimeouts();
49
+ this.discover();
204
50
  }
205
- }
206
- return connectedHealthyPeers;
207
- }
208
- async goodbyeAndDisconnectPeer(peer, reason) {
209
- this.logger.debug(`Disconnecting peer ${peer.toString()} with reason ${prettyGoodbyeReason(reason)}`);
210
- this.metrics.recordGoodbyeSent(reason);
211
- try {
212
- await this.reqresp.sendRequestToPeer(peer, ReqRespSubProtocol.GOODBYE, Buffer.from([
213
- reason
214
- ]));
215
- } catch (error) {
216
- this.logger.debug(`Failed to send goodbye to peer ${peer.toString()}: ${error}`);
217
- } finally{
218
- await this.disconnectPeer(peer);
219
- }
220
- }
221
- async disconnectPeer(peer) {
222
- try {
223
- await this.libP2PNode.hangUp(peer);
224
- } catch (error) {
225
- this.logger.debug(`Failed to disconnect peer ${peer.toString()}`, {
226
- error: inspect(error)
227
- });
228
- }
229
- }
230
- /**
231
- * Handles a discovered peer.
232
- * @param enr - The discovered peer's ENR.
233
- */ async handleDiscoveredPeer(enr) {
234
- // Check that the peer has not already been banned
235
- const peerId = await enr.peerId();
236
- const peerIdString = peerId.toString();
237
- // Check if peer is temporarily timed out
238
- const timedOutPeer = this.timedOutPeers.get(peerIdString);
239
- if (timedOutPeer) {
240
- if (Date.now() < timedOutPeer.timeoutUntilMs) {
241
- this.logger.trace(`Skipping timed out peer ${peerId}`);
242
- return;
51
+ /**
52
+ * Cleans up expired timeouts.
53
+ *
54
+ * When peers fail to dial after a number of retries, they are temporarily timed out.
55
+ * This function removes any peers that have been in the timed out state for too long.
56
+ * To give them a chance to reconnect.
57
+ */
58
+ cleanupExpiredTimeouts() {
59
+ // Clean up expired timeouts
60
+ const now = Date.now();
61
+ for (const [peerId, timedOutPeer] of this.timedOutPeers.entries()) {
62
+ if (now >= timedOutPeer.timeoutUntilMs) {
63
+ this.timedOutPeers.delete(peerId);
64
+ }
65
+ }
243
66
  }
244
- // Timeout period expired, remove from timed out peers
245
- this.timedOutPeers.delete(peerIdString);
246
- }
247
- if (this.peerScoring.getScoreState(peerIdString) != PeerScoreState.Healthy) {
248
- return;
249
- }
250
- const [multiaddrTcp] = await Promise.all([
251
- enr.getFullMultiaddr('tcp')
252
- ]);
253
- this.logger.trace(`Handling discovered peer ${peerId} at ${multiaddrTcp?.toString() ?? 'undefined address'}`);
254
- // stop if no tcp addr in multiaddr
255
- if (!multiaddrTcp) {
256
- this.logger.debug(`No TCP address in discovered node's multiaddr ${enr.encodeTxt()}`);
257
- return;
258
- }
259
- // check if peer is already connected
260
- const connections = this.libP2PNode.getConnections();
261
- if (connections.some((conn)=>conn.remotePeer.equals(peerId))) {
262
- this.logger.trace(`Already connected to peer ${peerId}`);
263
- return;
264
- }
265
- // check if peer is already in cache
266
- if (this.cachedPeers.has(peerIdString)) {
267
- this.logger.trace(`Peer already in cache ${peerIdString}`);
268
- return;
269
- }
270
- // create cached peer object
271
- const cachedPeer = {
272
- peerId,
273
- enr,
274
- multiaddrTcp,
275
- dialAttempts: 0,
276
- addedUnixMs: Date.now()
277
- };
278
- // Determine if we should dial immediately or not
279
- if (this.shouldDialPeer()) {
280
- void this.dialPeer(cachedPeer);
281
- } else {
282
- this.logger.trace(`Caching peer ${peerIdString}`);
283
- this.cachedPeers.set(peerIdString, cachedPeer);
284
- // Prune set of cached peers
285
- this.pruneCachedPeers();
286
- }
287
- }
288
- async dialPeer(peer) {
289
- const id = peer.peerId.toString();
290
- // Add to the address book before dialing
291
- await this.libP2PNode.peerStore.merge(peer.peerId, {
292
- multiaddrs: [
293
- peer.multiaddrTcp
294
- ]
295
- });
296
- this.logger.trace(`Dialing peer ${id}`);
297
- try {
298
- await this.libP2PNode.dial(peer.multiaddrTcp);
299
- } catch (error) {
300
- peer.dialAttempts++;
301
- if (peer.dialAttempts < MAX_DIAL_ATTEMPTS) {
302
- this.logger.trace(`Failed to dial peer ${id} (attempt ${peer.dialAttempts})`, {
303
- error: inspect(error)
304
- });
305
- this.cachedPeers.set(id, peer);
306
- } else {
307
- formatLibp2pDialError(error);
308
- this.logger.debug(`Failed to dial peer ${id} (dropping)`, {
309
- error: inspect(error)
310
- });
311
- this.cachedPeers.delete(id);
312
- // Add to timed out peers
313
- this.timedOutPeers.set(id, {
314
- peerId: id,
315
- timeoutUntilMs: Date.now() + FAILED_PEER_BAN_TIME_MS
67
+ /**
68
+ * Simply logs the type of connected peer.
69
+ * @param e - The connected peer event.
70
+ */
71
+ handleConnectedPeerEvent(e) {
72
+ const peerId = e.detail;
73
+ if (this.peerDiscoveryService.isBootstrapPeer(peerId)) {
74
+ this.logger.verbose(`Connected to bootstrap peer ${peerId.toString()}`);
75
+ }
76
+ else {
77
+ this.logger.verbose(`Connected to transaction peer ${peerId.toString()}`);
78
+ }
79
+ }
80
+ /**
81
+ * Simply logs the type of disconnected peer.
82
+ * @param e - The disconnected peer event.
83
+ */
84
+ handleDisconnectedPeerEvent(e) {
85
+ const peerId = e.detail;
86
+ if (this.peerDiscoveryService.isBootstrapPeer(peerId)) {
87
+ this.logger.verbose(`Disconnected from bootstrap peer ${peerId.toString()}`);
88
+ }
89
+ else {
90
+ this.logger.verbose(`Disconnected from transaction peer ${peerId.toString()}`);
91
+ }
92
+ }
93
+ /**
94
+ * Handles a goodbye received from a peer.
95
+ *
96
+ * Used as the reqresp handler when a peer sends us goodbye message.
97
+ * @param peerId - The peer ID.
98
+ * @param reason - The reason for the goodbye.
99
+ */
100
+ goodbyeReceived(peerId, reason) {
101
+ this.logger.debug(`Goodbye received from peer ${peerId.toString()} with reason ${prettyGoodbyeReason(reason)}`);
102
+ this.metrics.recordGoodbyeReceived(reason);
103
+ void this.disconnectPeer(peerId);
104
+ }
105
+ penalizePeer(peerId, penalty) {
106
+ this.peerScoring.penalizePeer(peerId, penalty);
107
+ }
108
+ getPeerScore(peerId) {
109
+ return this.peerScoring.getScore(peerId);
110
+ }
111
+ getPeers(includePending = false) {
112
+ const connected = this.libP2PNode
113
+ .getPeers()
114
+ .map(peer => ({ id: peer.toString(), score: this.getPeerScore(peer.toString()), status: 'connected' }));
115
+ if (!includePending) {
116
+ return connected;
117
+ }
118
+ const dialQueue = this.libP2PNode
119
+ .getDialQueue()
120
+ .filter(peer => !!peer.peerId)
121
+ .map(peer => ({
122
+ id: peer.peerId.toString(),
123
+ status: 'dialing',
124
+ dialStatus: peer.status,
125
+ addresses: peer.multiaddrs.map(m => m.toString()),
126
+ }));
127
+ const cachedPeers = Array.from(this.cachedPeers.values())
128
+ .filter(peer => !dialQueue.some(dialPeer => dialPeer.id && peer.peerId.toString() === dialPeer.id.toString()))
129
+ .filter(peer => !connected.some(connPeer => connPeer.id.toString() === peer.peerId.toString()))
130
+ .map(peer => ({
131
+ status: 'cached',
132
+ id: peer.peerId.toString(),
133
+ addresses: [peer.multiaddrTcp.toString()],
134
+ dialAttempts: peer.dialAttempts,
135
+ enr: peer.enr.encodeTxt(),
136
+ }));
137
+ return [...connected, ...dialQueue, ...cachedPeers];
138
+ }
139
+ /**
140
+ * Discovers peers.
141
+ */
142
+ discover() {
143
+ const connections = this.libP2PNode.getConnections();
144
+ const healthyConnections = this.pruneUnhealthyPeers(connections);
145
+ // Calculate how many connections we're looking to make
146
+ const peersToConnect = this.config.maxPeerCount - healthyConnections.length;
147
+ const logLevel = this.heartbeatCounter % this.displayPeerCountsPeerHeartbeat === 0 ? 'info' : 'debug';
148
+ this.logger[logLevel](`Connected to ${connections.length} peers`, {
149
+ connections: connections.length,
150
+ maxPeerCount: this.config.maxPeerCount,
151
+ cachedPeers: this.cachedPeers.size,
152
+ ...this.peerScoring.getStats(),
316
153
  });
154
+ // Exit if no peers to connect
155
+ if (peersToConnect <= 0) {
156
+ return;
157
+ }
158
+ const cachedPeersToDial = [];
159
+ const pendingDials = new Set(this.libP2PNode
160
+ .getDialQueue()
161
+ .map(pendingDial => pendingDial.peerId?.toString())
162
+ .filter(Boolean));
163
+ for (const [id, peerData] of this.cachedPeers.entries()) {
164
+ // if already dialling or connected to, remove from cache
165
+ if (pendingDials.has(id) ||
166
+ healthyConnections.some(conn => conn.remotePeer.equals(peerData.peerId)) ||
167
+ // if peer has been in cache for the max cache age, remove from cache
168
+ Date.now() - peerData.addedUnixMs > MAX_CACHED_PEER_AGE_MS) {
169
+ this.cachedPeers.delete(id);
170
+ }
171
+ else {
172
+ // cachedPeersToDial.set(id, enr);
173
+ cachedPeersToDial.push(peerData);
174
+ }
175
+ }
176
+ // reverse to dial older entries first
177
+ cachedPeersToDial.reverse();
178
+ for (const peer of cachedPeersToDial) {
179
+ // We remove from the cache before, as dialling will add it back if it fails
180
+ this.cachedPeers.delete(peer.peerId.toString());
181
+ void this.dialPeer(peer);
182
+ }
183
+ // if we need more peers, start randomNodesQuery
184
+ if (peersToConnect > 0) {
185
+ this.logger.trace(`Running random nodes query to connect to ${peersToConnect} peers`);
186
+ void this.peerDiscoveryService.runRandomNodesQuery();
187
+ }
317
188
  }
318
- }
319
- }
320
- shouldDialPeer() {
321
- const connections = this.libP2PNode.getConnections().length;
322
- if (connections >= this.config.maxPeerCount) {
323
- this.logger.trace(`Not dialing peer due to max peer count of ${this.config.maxPeerCount} reached (${connections} current connections)`);
324
- return false;
325
- }
326
- return true;
327
- }
328
- pruneCachedPeers() {
329
- let peersToDelete = this.cachedPeers.size - MAX_CACHED_PEERS;
330
- if (peersToDelete <= 0) {
331
- return;
332
- }
333
- // Remove the oldest peers
334
- for (const key of this.cachedPeers.keys()){
335
- this.cachedPeers.delete(key);
336
- this.logger.trace(`Pruning peer ${key} from cache`);
337
- peersToDelete--;
338
- if (peersToDelete <= 0) {
339
- break;
189
+ pruneUnhealthyPeers(connections) {
190
+ const connectedHealthyPeers = [];
191
+ for (const peer of connections) {
192
+ const score = this.peerScoring.getScoreState(peer.remotePeer.toString());
193
+ switch (score) {
194
+ case PeerScoreState.Banned:
195
+ void this.goodbyeAndDisconnectPeer(peer.remotePeer, GoodByeReason.BANNED);
196
+ break;
197
+ case PeerScoreState.Disconnect:
198
+ void this.goodbyeAndDisconnectPeer(peer.remotePeer, GoodByeReason.DISCONNECTED);
199
+ break;
200
+ case PeerScoreState.Healthy:
201
+ connectedHealthyPeers.push(peer);
202
+ }
203
+ }
204
+ return connectedHealthyPeers;
340
205
  }
341
- }
342
- }
343
- /**
344
- * Stops the peer manager.
345
- * Removing all event listeners.
346
- */ async stop() {
347
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
348
- this.peerDiscoveryService.off(PeerEvent.DISCOVERED, this.discoveredPeerHandler);
349
- // Send goodbyes to all peers
350
- await Promise.all(this.libP2PNode.getPeers().map((peer)=>this.goodbyeAndDisconnectPeer(peer, GoodByeReason.SHUTDOWN)));
351
- this.libP2PNode.removeEventListener(PeerEvent.CONNECTED, this.handleConnectedPeerEvent);
352
- this.libP2PNode.removeEventListener(PeerEvent.DISCONNECTED, this.handleDisconnectedPeerEvent);
353
- }
354
- }
355
- _ts_decorate([
356
- trackSpan('PeerManager.heartbeat')
357
- ], PeerManager.prototype, "heartbeat", null);
206
+ async goodbyeAndDisconnectPeer(peer, reason) {
207
+ this.logger.debug(`Disconnecting peer ${peer.toString()} with reason ${prettyGoodbyeReason(reason)}`);
208
+ this.metrics.recordGoodbyeSent(reason);
209
+ try {
210
+ await this.reqresp.sendRequestToPeer(peer, ReqRespSubProtocol.GOODBYE, Buffer.from([reason]));
211
+ }
212
+ catch (error) {
213
+ this.logger.debug(`Failed to send goodbye to peer ${peer.toString()}: ${error}`);
214
+ }
215
+ finally {
216
+ await this.disconnectPeer(peer);
217
+ }
218
+ }
219
+ async disconnectPeer(peer) {
220
+ try {
221
+ await this.libP2PNode.hangUp(peer);
222
+ }
223
+ catch (error) {
224
+ this.logger.debug(`Failed to disconnect peer ${peer.toString()}`, { error: inspect(error) });
225
+ }
226
+ }
227
+ /**
228
+ * Handles a discovered peer.
229
+ * @param enr - The discovered peer's ENR.
230
+ */
231
+ async handleDiscoveredPeer(enr) {
232
+ // Check that the peer has not already been banned
233
+ const peerId = await enr.peerId();
234
+ const peerIdString = peerId.toString();
235
+ // Check if peer is temporarily timed out
236
+ const timedOutPeer = this.timedOutPeers.get(peerIdString);
237
+ if (timedOutPeer) {
238
+ if (Date.now() < timedOutPeer.timeoutUntilMs) {
239
+ this.logger.trace(`Skipping timed out peer ${peerId}`);
240
+ return;
241
+ }
242
+ // Timeout period expired, remove from timed out peers
243
+ this.timedOutPeers.delete(peerIdString);
244
+ }
245
+ if (this.peerScoring.getScoreState(peerIdString) != PeerScoreState.Healthy) {
246
+ return;
247
+ }
248
+ const [multiaddrTcp] = await Promise.all([enr.getFullMultiaddr('tcp')]);
249
+ this.logger.trace(`Handling discovered peer ${peerId} at ${multiaddrTcp?.toString() ?? 'undefined address'}`);
250
+ // stop if no tcp addr in multiaddr
251
+ if (!multiaddrTcp) {
252
+ this.logger.debug(`No TCP address in discovered node's multiaddr ${enr.encodeTxt()}`);
253
+ return;
254
+ }
255
+ // check if peer is already connected
256
+ const connections = this.libP2PNode.getConnections();
257
+ if (connections.some((conn) => conn.remotePeer.equals(peerId))) {
258
+ this.logger.trace(`Already connected to peer ${peerId}`);
259
+ return;
260
+ }
261
+ // check if peer is already in cache
262
+ if (this.cachedPeers.has(peerIdString)) {
263
+ this.logger.trace(`Peer already in cache ${peerIdString}`);
264
+ return;
265
+ }
266
+ // create cached peer object
267
+ const cachedPeer = {
268
+ peerId,
269
+ enr,
270
+ multiaddrTcp,
271
+ dialAttempts: 0,
272
+ addedUnixMs: Date.now(),
273
+ };
274
+ // Determine if we should dial immediately or not
275
+ if (this.shouldDialPeer()) {
276
+ void this.dialPeer(cachedPeer);
277
+ }
278
+ else {
279
+ this.logger.trace(`Caching peer ${peerIdString}`);
280
+ this.cachedPeers.set(peerIdString, cachedPeer);
281
+ // Prune set of cached peers
282
+ this.pruneCachedPeers();
283
+ }
284
+ }
285
+ async dialPeer(peer) {
286
+ const id = peer.peerId.toString();
287
+ // Add to the address book before dialing
288
+ await this.libP2PNode.peerStore.merge(peer.peerId, { multiaddrs: [peer.multiaddrTcp] });
289
+ this.logger.trace(`Dialing peer ${id}`);
290
+ try {
291
+ await this.libP2PNode.dial(peer.multiaddrTcp);
292
+ }
293
+ catch (error) {
294
+ peer.dialAttempts++;
295
+ if (peer.dialAttempts < MAX_DIAL_ATTEMPTS) {
296
+ this.logger.trace(`Failed to dial peer ${id} (attempt ${peer.dialAttempts})`, { error: inspect(error) });
297
+ this.cachedPeers.set(id, peer);
298
+ }
299
+ else {
300
+ formatLibp2pDialError(error);
301
+ this.logger.debug(`Failed to dial peer ${id} (dropping)`, { error: inspect(error) });
302
+ this.cachedPeers.delete(id);
303
+ // Add to timed out peers
304
+ this.timedOutPeers.set(id, {
305
+ peerId: id,
306
+ timeoutUntilMs: Date.now() + FAILED_PEER_BAN_TIME_MS,
307
+ });
308
+ }
309
+ }
310
+ }
311
+ shouldDialPeer() {
312
+ const connections = this.libP2PNode.getConnections().length;
313
+ if (connections >= this.config.maxPeerCount) {
314
+ this.logger.trace(`Not dialing peer due to max peer count of ${this.config.maxPeerCount} reached (${connections} current connections)`);
315
+ return false;
316
+ }
317
+ return true;
318
+ }
319
+ pruneCachedPeers() {
320
+ let peersToDelete = this.cachedPeers.size - MAX_CACHED_PEERS;
321
+ if (peersToDelete <= 0) {
322
+ return;
323
+ }
324
+ // Remove the oldest peers
325
+ for (const key of this.cachedPeers.keys()) {
326
+ this.cachedPeers.delete(key);
327
+ this.logger.trace(`Pruning peer ${key} from cache`);
328
+ peersToDelete--;
329
+ if (peersToDelete <= 0) {
330
+ break;
331
+ }
332
+ }
333
+ }
334
+ /**
335
+ * Stops the peer manager.
336
+ * Removing all event listeners.
337
+ */
338
+ async stop() {
339
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
340
+ this.peerDiscoveryService.off(PeerEvent.DISCOVERED, this.discoveredPeerHandler);
341
+ // Send goodbyes to all peers
342
+ await Promise.all(this.libP2PNode.getPeers().map(peer => this.goodbyeAndDisconnectPeer(peer, GoodByeReason.SHUTDOWN)));
343
+ this.libP2PNode.removeEventListener(PeerEvent.CONNECTED, this.handleConnectedPeerEvent);
344
+ this.libP2PNode.removeEventListener(PeerEvent.DISCONNECTED, this.handleDisconnectedPeerEvent);
345
+ }
346
+ },
347
+ (() => {
348
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
349
+ _heartbeat_decorators = [trackSpan('PeerManager.heartbeat')];
350
+ __esDecorate(_a, null, _heartbeat_decorators, { kind: "method", name: "heartbeat", static: false, private: false, access: { has: obj => "heartbeat" in obj, get: obj => obj.heartbeat }, metadata: _metadata }, null, _instanceExtraInitializers);
351
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
352
+ })(),
353
+ _a;
354
+ })();
355
+ export { PeerManager };
358
356
  /**
359
357
  * copied from github.com/ChainSafe/lodestar
360
358
  * libp2p errors with extremely noisy errors here, which are deeply nested taking 30-50 lines.
@@ -383,11 +381,15 @@ _ts_decorate([
383
381
  * ```
384
382
  *
385
383
  * Tracking issue https://github.com/libp2p/js-libp2p/issues/996
386
- */ function formatLibp2pDialError(e) {
384
+ */
385
+ function formatLibp2pDialError(e) {
387
386
  const errorMessage = e.message.trim();
388
387
  const newlineIndex = errorMessage.indexOf('\n');
389
388
  e.message = newlineIndex !== -1 ? errorMessage.slice(0, newlineIndex) : errorMessage;
390
- if (e.message.includes('The operation was aborted') || e.message.includes('stream ended before 1 bytes became available') || e.message.includes('The operation was aborted')) {
389
+ if (e.message.includes('The operation was aborted') ||
390
+ e.message.includes('stream ended before 1 bytes became available') ||
391
+ e.message.includes('The operation was aborted')) {
391
392
  e.stack = undefined;
392
393
  }
393
394
  }
395
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVlcl9tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZpY2VzL3BlZXItbWFuYWdlci9wZWVyX21hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUNBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNyRCxPQUFPLEVBQXdCLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBSzFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFJL0IsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBR3JGLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDeEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ2xELE9BQU8sRUFBRSxjQUFjLEVBQW9CLE1BQU0sbUJBQW1CLENBQUM7QUFFckUsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLENBQUM7QUFDNUIsTUFBTSxnQkFBZ0IsR0FBRyxHQUFHLENBQUM7QUFDN0IsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLFlBQVk7QUFDMUQsTUFBTSx1QkFBdUIsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLG9EQUFvRDtJQWV0RixXQUFXOzs7O3NCQUFYLFdBQVc7WUFTdEIsWUFDVSxVQUF3QixFQUN4QixvQkFBMEMsRUFDMUMsTUFBaUIsRUFDekIsZUFBZ0MsRUFDeEIsU0FBUyxZQUFZLENBQUMsa0JBQWtCLENBQUMsRUFDekMsV0FBd0IsRUFDeEIsT0FBZ0I7Z0JBTmhCLGVBQVUsSUFWVCxtREFBVyxFQVVaLFVBQVUsRUFBYztnQkFDeEIseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtn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