@aztec/p2p 0.71.0 → 0.72.1

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 (107) hide show
  1. package/dest/client/p2p_client.d.ts.map +1 -1
  2. package/dest/client/p2p_client.js +6 -6
  3. package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -1
  4. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  5. package/dest/mem_pools/attestation_pool/mocks.js +1 -1
  6. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  7. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +2 -2
  8. package/dest/mocks/index.d.ts +3 -3
  9. package/dest/mocks/index.d.ts.map +1 -1
  10. package/dest/mocks/index.js +19 -18
  11. package/dest/services/dummy_service.d.ts +7 -0
  12. package/dest/services/dummy_service.d.ts.map +1 -1
  13. package/dest/services/dummy_service.js +10 -1
  14. package/dest/services/libp2p/libp2p_service.d.ts +17 -13
  15. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  16. package/dest/services/libp2p/libp2p_service.js +109 -101
  17. package/dest/services/peer-manager/metrics.d.ts +12 -0
  18. package/dest/services/peer-manager/metrics.d.ts.map +1 -0
  19. package/dest/services/peer-manager/metrics.js +26 -0
  20. package/dest/services/{peer_manager.d.ts → peer-manager/peer_manager.d.ts} +23 -8
  21. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -0
  22. package/dest/services/peer-manager/peer_manager.js +392 -0
  23. package/dest/services/{peer-scoring → peer-manager}/peer_scoring.d.ts +3 -0
  24. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -0
  25. package/dest/services/peer-manager/peer_scoring.js +84 -0
  26. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +45 -0
  27. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -0
  28. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +81 -0
  29. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +61 -0
  30. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -0
  31. package/dest/services/reqresp/connection-sampler/connection_sampler.js +175 -0
  32. package/dest/services/reqresp/interface.d.ts +17 -4
  33. package/dest/services/reqresp/interface.d.ts.map +1 -1
  34. package/dest/services/reqresp/interface.js +34 -11
  35. package/dest/services/reqresp/metrics.d.ts +15 -0
  36. package/dest/services/reqresp/metrics.d.ts.map +1 -0
  37. package/dest/services/reqresp/metrics.js +42 -0
  38. package/dest/services/reqresp/protocols/block.d.ts +4 -0
  39. package/dest/services/reqresp/protocols/block.d.ts.map +1 -0
  40. package/dest/services/reqresp/protocols/block.js +9 -0
  41. package/dest/services/reqresp/protocols/goodbye.d.ts +51 -0
  42. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -0
  43. package/dest/services/reqresp/protocols/goodbye.js +92 -0
  44. package/dest/services/reqresp/protocols/index.d.ts +9 -0
  45. package/dest/services/reqresp/protocols/index.d.ts.map +1 -0
  46. package/dest/services/reqresp/protocols/index.js +9 -0
  47. package/dest/services/reqresp/protocols/ping.d.ts +9 -0
  48. package/dest/services/reqresp/protocols/ping.d.ts.map +1 -0
  49. package/dest/services/reqresp/protocols/ping.js +9 -0
  50. package/dest/services/reqresp/{handlers.d.ts → protocols/status.d.ts} +1 -7
  51. package/dest/services/reqresp/protocols/status.d.ts.map +1 -0
  52. package/dest/services/reqresp/protocols/status.js +9 -0
  53. package/dest/services/reqresp/protocols/tx.d.ts +13 -0
  54. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -0
  55. package/dest/services/reqresp/protocols/tx.js +23 -0
  56. package/dest/services/reqresp/rate-limiter/index.d.ts.map +1 -0
  57. package/dest/services/reqresp/{rate_limiter → rate-limiter}/index.js +1 -1
  58. package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.d.ts +3 -3
  59. package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.d.ts.map +1 -1
  60. package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.js +4 -4
  61. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -0
  62. package/dest/services/reqresp/rate-limiter/rate_limits.js +55 -0
  63. package/dest/services/reqresp/reqresp.d.ts +33 -6
  64. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  65. package/dest/services/reqresp/reqresp.js +414 -249
  66. package/dest/services/service.d.ts +8 -0
  67. package/dest/services/service.d.ts.map +1 -1
  68. package/dest/util.d.ts +4 -0
  69. package/dest/util.d.ts.map +1 -1
  70. package/dest/util.js +1 -1
  71. package/package.json +8 -8
  72. package/src/client/p2p_client.ts +5 -5
  73. package/src/mem_pools/attestation_pool/mocks.ts +2 -2
  74. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -1
  75. package/src/mocks/index.ts +19 -20
  76. package/src/services/dummy_service.ts +13 -0
  77. package/src/services/libp2p/libp2p_service.ts +143 -128
  78. package/src/services/peer-manager/metrics.ts +41 -0
  79. package/src/services/{peer_manager.ts → peer-manager/peer_manager.ts} +67 -22
  80. package/src/services/{peer-scoring → peer-manager}/peer_scoring.ts +16 -3
  81. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +94 -0
  82. package/src/services/reqresp/connection-sampler/connection_sampler.ts +211 -0
  83. package/src/services/reqresp/interface.ts +39 -16
  84. package/src/services/reqresp/metrics.ts +57 -0
  85. package/src/services/reqresp/protocols/block.ts +15 -0
  86. package/src/services/reqresp/protocols/goodbye.ts +101 -0
  87. package/src/services/reqresp/protocols/index.ts +8 -0
  88. package/src/services/reqresp/protocols/ping.ts +8 -0
  89. package/src/services/reqresp/{handlers.ts → protocols/status.ts} +0 -9
  90. package/src/services/reqresp/protocols/tx.ts +29 -0
  91. package/src/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.ts +3 -3
  92. package/src/services/reqresp/{rate_limiter → rate-limiter}/rate_limits.ts +24 -4
  93. package/src/services/reqresp/reqresp.ts +224 -25
  94. package/src/services/service.ts +12 -0
  95. package/src/util.ts +4 -0
  96. package/dest/services/peer-scoring/peer_scoring.d.ts.map +0 -1
  97. package/dest/services/peer-scoring/peer_scoring.js +0 -75
  98. package/dest/services/peer_manager.d.ts.map +0 -1
  99. package/dest/services/peer_manager.js +0 -358
  100. package/dest/services/reqresp/handlers.d.ts.map +0 -1
  101. package/dest/services/reqresp/handlers.js +0 -17
  102. package/dest/services/reqresp/rate_limiter/index.d.ts.map +0 -1
  103. package/dest/services/reqresp/rate_limiter/rate_limits.d.ts.map +0 -1
  104. package/dest/services/reqresp/rate_limiter/rate_limits.js +0 -35
  105. /package/dest/services/reqresp/{rate_limiter → rate-limiter}/index.d.ts +0 -0
  106. /package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limits.d.ts +0 -0
  107. /package/src/services/reqresp/{rate_limiter → rate-limiter}/index.ts +0 -0
@@ -0,0 +1,392 @@
1
+ import { __esDecorate, __runInitializers } from "tslib";
2
+ import { createLogger } from '@aztec/foundation/log';
3
+ import { trackSpan } from '@aztec/telemetry-client';
4
+ import { inspect } from 'util';
5
+ import { ReqRespSubProtocol } from '../reqresp/interface.js';
6
+ import { GoodByeReason, prettyGoodbyeReason } from '../reqresp/protocols/goodbye.js';
7
+ import { PeerEvent } from '../types.js';
8
+ import { PeerManagerMetrics } from './metrics.js';
9
+ import { PeerScoreState } from './peer_scoring.js';
10
+ const MAX_DIAL_ATTEMPTS = 3;
11
+ const MAX_CACHED_PEERS = 100;
12
+ const MAX_CACHED_PEER_AGE_MS = 5 * 60 * 1000; // 5 minutes
13
+ const FAILED_PEER_BAN_TIME_MS = 5 * 60 * 1000; // 5 minutes timeout after failing MAX_DIAL_ATTEMPTS
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.peerDiscoveryService.on(PeerEvent.DISCOVERED, this.handleDiscoveredPeer.bind(this));
37
+ // Display peer counts every 60 seconds
38
+ this.displayPeerCountsPeerHeartbeat = Math.floor(60000 / this.config.peerCheckIntervalMS);
39
+ }
40
+ get tracer() {
41
+ return this.metrics.tracer;
42
+ }
43
+ heartbeat() {
44
+ this.heartbeatCounter++;
45
+ this.peerScoring.decayAllScores();
46
+ this.cleanupExpiredTimeouts();
47
+ this.discover();
48
+ }
49
+ /**
50
+ * Cleans up expired timeouts.
51
+ *
52
+ * When peers fail to dial after a number of retries, they are temporarily timed out.
53
+ * This function removes any peers that have been in the timed out state for too long.
54
+ * To give them a chance to reconnect.
55
+ */
56
+ cleanupExpiredTimeouts() {
57
+ // Clean up expired timeouts
58
+ const now = Date.now();
59
+ for (const [peerId, timedOutPeer] of this.timedOutPeers.entries()) {
60
+ if (now >= timedOutPeer.timeoutUntilMs) {
61
+ this.timedOutPeers.delete(peerId);
62
+ }
63
+ }
64
+ }
65
+ /**
66
+ * Simply logs the type of connected peer.
67
+ * @param e - The connected peer event.
68
+ */
69
+ handleConnectedPeerEvent(e) {
70
+ const peerId = e.detail;
71
+ if (this.peerDiscoveryService.isBootstrapPeer(peerId)) {
72
+ this.logger.verbose(`Connected to bootstrap peer ${peerId.toString()}`);
73
+ }
74
+ else {
75
+ this.logger.verbose(`Connected to transaction peer ${peerId.toString()}`);
76
+ }
77
+ }
78
+ /**
79
+ * Simply logs the type of disconnected peer.
80
+ * @param e - The disconnected peer event.
81
+ */
82
+ handleDisconnectedPeerEvent(e) {
83
+ const peerId = e.detail;
84
+ if (this.peerDiscoveryService.isBootstrapPeer(peerId)) {
85
+ this.logger.verbose(`Disconnected from bootstrap peer ${peerId.toString()}`);
86
+ }
87
+ else {
88
+ this.logger.verbose(`Disconnected from transaction peer ${peerId.toString()}`);
89
+ }
90
+ }
91
+ /**
92
+ * Handles a goodbye received from a peer.
93
+ *
94
+ * Used as the reqresp handler when a peer sends us goodbye message.
95
+ * @param peerId - The peer ID.
96
+ * @param reason - The reason for the goodbye.
97
+ */
98
+ goodbyeReceived(peerId, reason) {
99
+ this.logger.debug(`Goodbye received from peer ${peerId.toString()} with reason ${prettyGoodbyeReason(reason)}`);
100
+ this.metrics.recordGoodbyeReceived(reason);
101
+ void this.disconnectPeer(peerId);
102
+ }
103
+ penalizePeer(peerId, penalty) {
104
+ this.peerScoring.penalizePeer(peerId, penalty);
105
+ }
106
+ getPeerScore(peerId) {
107
+ return this.peerScoring.getScore(peerId);
108
+ }
109
+ getPeers(includePending = false) {
110
+ const connected = this.libP2PNode
111
+ .getPeers()
112
+ .map(peer => ({ id: peer.toString(), score: this.getPeerScore(peer.toString()), status: 'connected' }));
113
+ if (!includePending) {
114
+ return connected;
115
+ }
116
+ const dialQueue = this.libP2PNode
117
+ .getDialQueue()
118
+ .filter(peer => !!peer.peerId)
119
+ .map(peer => ({
120
+ id: peer.peerId.toString(),
121
+ status: 'dialing',
122
+ dialStatus: peer.status,
123
+ addresses: peer.multiaddrs.map(m => m.toString()),
124
+ }));
125
+ const cachedPeers = Array.from(this.cachedPeers.values())
126
+ .filter(peer => !dialQueue.some(dialPeer => dialPeer.id && peer.peerId.toString() === dialPeer.id.toString()))
127
+ .filter(peer => !connected.some(connPeer => connPeer.id.toString() === peer.peerId.toString()))
128
+ .map(peer => ({
129
+ status: 'cached',
130
+ id: peer.peerId.toString(),
131
+ addresses: [peer.multiaddrTcp.toString()],
132
+ dialAttempts: peer.dialAttempts,
133
+ enr: peer.enr.encodeTxt(),
134
+ }));
135
+ return [...connected, ...dialQueue, ...cachedPeers];
136
+ }
137
+ /**
138
+ * Discovers peers.
139
+ */
140
+ discover() {
141
+ const connections = this.libP2PNode.getConnections();
142
+ const healthyConnections = this.pruneUnhealthyPeers(connections);
143
+ // Calculate how many connections we're looking to make
144
+ const peersToConnect = this.config.maxPeerCount - healthyConnections.length;
145
+ const logLevel = this.heartbeatCounter % this.displayPeerCountsPeerHeartbeat === 0 ? 'info' : 'debug';
146
+ this.logger[logLevel](`Connected to ${connections.length} peers`, {
147
+ connections: connections.length,
148
+ maxPeerCount: this.config.maxPeerCount,
149
+ cachedPeers: this.cachedPeers.size,
150
+ ...this.peerScoring.getStats(),
151
+ });
152
+ // Exit if no peers to connect
153
+ if (peersToConnect <= 0) {
154
+ return;
155
+ }
156
+ const cachedPeersToDial = [];
157
+ const pendingDials = new Set(this.libP2PNode
158
+ .getDialQueue()
159
+ .map(pendingDial => pendingDial.peerId?.toString())
160
+ .filter(Boolean));
161
+ for (const [id, peerData] of this.cachedPeers.entries()) {
162
+ // if already dialling or connected to, remove from cache
163
+ if (pendingDials.has(id) ||
164
+ healthyConnections.some(conn => conn.remotePeer.equals(peerData.peerId)) ||
165
+ // if peer has been in cache for the max cache age, remove from cache
166
+ Date.now() - peerData.addedUnixMs > MAX_CACHED_PEER_AGE_MS) {
167
+ this.cachedPeers.delete(id);
168
+ }
169
+ else {
170
+ // cachedPeersToDial.set(id, enr);
171
+ cachedPeersToDial.push(peerData);
172
+ }
173
+ }
174
+ // reverse to dial older entries first
175
+ cachedPeersToDial.reverse();
176
+ for (const peer of cachedPeersToDial) {
177
+ // We remove from the cache before, as dialling will add it back if it fails
178
+ this.cachedPeers.delete(peer.peerId.toString());
179
+ void this.dialPeer(peer);
180
+ }
181
+ // if we need more peers, start randomNodesQuery
182
+ if (peersToConnect > 0) {
183
+ this.logger.trace(`Running random nodes query to connect to ${peersToConnect} peers`);
184
+ void this.peerDiscoveryService.runRandomNodesQuery();
185
+ }
186
+ }
187
+ pruneUnhealthyPeers(connections) {
188
+ const connectedHealthyPeers = [];
189
+ for (const peer of connections) {
190
+ const score = this.peerScoring.getScoreState(peer.remotePeer.toString());
191
+ switch (score) {
192
+ case PeerScoreState.Banned:
193
+ void this.goodbyeAndDisconnectPeer(peer.remotePeer, GoodByeReason.BANNED);
194
+ break;
195
+ case PeerScoreState.Disconnect:
196
+ void this.goodbyeAndDisconnectPeer(peer.remotePeer, GoodByeReason.DISCONNECTED);
197
+ break;
198
+ case PeerScoreState.Healthy:
199
+ connectedHealthyPeers.push(peer);
200
+ }
201
+ }
202
+ return connectedHealthyPeers;
203
+ }
204
+ async goodbyeAndDisconnectPeer(peer, reason) {
205
+ this.logger.debug(`Disconnecting peer ${peer.toString()} with reason ${prettyGoodbyeReason(reason)}`);
206
+ this.metrics.recordGoodbyeSent(reason);
207
+ try {
208
+ await this.reqresp.sendRequestToPeer(peer, ReqRespSubProtocol.GOODBYE, Buffer.from([reason]));
209
+ }
210
+ catch (error) {
211
+ this.logger.debug(`Failed to send goodbye to peer ${peer.toString()}: ${error}`);
212
+ }
213
+ finally {
214
+ await this.disconnectPeer(peer);
215
+ }
216
+ }
217
+ async disconnectPeer(peer) {
218
+ try {
219
+ await this.libP2PNode.hangUp(peer);
220
+ }
221
+ catch (error) {
222
+ this.logger.debug(`Failed to disconnect peer ${peer.toString()}`, { error: inspect(error) });
223
+ }
224
+ }
225
+ /**
226
+ * Handles a discovered peer.
227
+ * @param enr - The discovered peer's ENR.
228
+ */
229
+ async handleDiscoveredPeer(enr) {
230
+ // Check that the peer has not already been banned
231
+ const peerId = await enr.peerId();
232
+ const peerIdString = peerId.toString();
233
+ // Check if peer is temporarily timed out
234
+ const timedOutPeer = this.timedOutPeers.get(peerIdString);
235
+ if (timedOutPeer) {
236
+ if (Date.now() < timedOutPeer.timeoutUntilMs) {
237
+ this.logger.trace(`Skipping timed out peer ${peerId}`);
238
+ return;
239
+ }
240
+ // Timeout period expired, remove from timed out peers
241
+ this.timedOutPeers.delete(peerIdString);
242
+ }
243
+ if (this.peerScoring.getScoreState(peerIdString) != PeerScoreState.Healthy) {
244
+ return;
245
+ }
246
+ const [multiaddrTcp] = await Promise.all([enr.getFullMultiaddr('tcp')]);
247
+ this.logger.trace(`Handling discovered peer ${peerId} at ${multiaddrTcp?.toString() ?? 'undefined address'}`);
248
+ // stop if no tcp addr in multiaddr
249
+ if (!multiaddrTcp) {
250
+ this.logger.debug(`No TCP address in discovered node's multiaddr ${enr.encodeTxt()}`);
251
+ return;
252
+ }
253
+ // check if peer is already connected
254
+ const connections = this.libP2PNode.getConnections();
255
+ if (connections.some((conn) => conn.remotePeer.equals(peerId))) {
256
+ this.logger.trace(`Already connected to peer ${peerId}`);
257
+ return;
258
+ }
259
+ // check if peer is already in cache
260
+ if (this.cachedPeers.has(peerIdString)) {
261
+ this.logger.trace(`Peer already in cache ${peerIdString}`);
262
+ return;
263
+ }
264
+ // create cached peer object
265
+ const cachedPeer = {
266
+ peerId,
267
+ enr,
268
+ multiaddrTcp,
269
+ dialAttempts: 0,
270
+ addedUnixMs: Date.now(),
271
+ };
272
+ // Determine if we should dial immediately or not
273
+ if (this.shouldDialPeer()) {
274
+ void this.dialPeer(cachedPeer);
275
+ }
276
+ else {
277
+ this.logger.trace(`Caching peer ${peerIdString}`);
278
+ this.cachedPeers.set(peerIdString, cachedPeer);
279
+ // Prune set of cached peers
280
+ this.pruneCachedPeers();
281
+ }
282
+ }
283
+ async dialPeer(peer) {
284
+ const id = peer.peerId.toString();
285
+ // Add to the address book before dialing
286
+ await this.libP2PNode.peerStore.merge(peer.peerId, { multiaddrs: [peer.multiaddrTcp] });
287
+ this.logger.trace(`Dialing peer ${id}`);
288
+ try {
289
+ await this.libP2PNode.dial(peer.multiaddrTcp);
290
+ }
291
+ catch (error) {
292
+ peer.dialAttempts++;
293
+ if (peer.dialAttempts < MAX_DIAL_ATTEMPTS) {
294
+ this.logger.trace(`Failed to dial peer ${id} (attempt ${peer.dialAttempts})`, { error: inspect(error) });
295
+ this.cachedPeers.set(id, peer);
296
+ }
297
+ else {
298
+ formatLibp2pDialError(error);
299
+ this.logger.debug(`Failed to dial peer ${id} (dropping)`, { error: inspect(error) });
300
+ this.cachedPeers.delete(id);
301
+ // Add to timed out peers
302
+ this.timedOutPeers.set(id, {
303
+ peerId: id,
304
+ timeoutUntilMs: Date.now() + FAILED_PEER_BAN_TIME_MS,
305
+ });
306
+ }
307
+ }
308
+ }
309
+ shouldDialPeer() {
310
+ const connections = this.libP2PNode.getConnections().length;
311
+ if (connections >= this.config.maxPeerCount) {
312
+ this.logger.trace(`Not dialing peer due to max peer count of ${this.config.maxPeerCount} reached (${connections} current connections)`);
313
+ return false;
314
+ }
315
+ return true;
316
+ }
317
+ pruneCachedPeers() {
318
+ let peersToDelete = this.cachedPeers.size - MAX_CACHED_PEERS;
319
+ if (peersToDelete <= 0) {
320
+ return;
321
+ }
322
+ // Remove the oldest peers
323
+ for (const key of this.cachedPeers.keys()) {
324
+ this.cachedPeers.delete(key);
325
+ this.logger.trace(`Pruning peer ${key} from cache`);
326
+ peersToDelete--;
327
+ if (peersToDelete <= 0) {
328
+ break;
329
+ }
330
+ }
331
+ }
332
+ /**
333
+ * Stops the peer manager.
334
+ * Removing all event listeners.
335
+ */
336
+ async stop() {
337
+ this.peerDiscoveryService.off(PeerEvent.DISCOVERED, this.handleDiscoveredPeer);
338
+ // Send goodbyes to all peers
339
+ await Promise.all(this.libP2PNode.getPeers().map(peer => this.goodbyeAndDisconnectPeer(peer, GoodByeReason.SHUTDOWN)));
340
+ this.libP2PNode.removeEventListener(PeerEvent.CONNECTED, this.handleConnectedPeerEvent);
341
+ this.libP2PNode.removeEventListener(PeerEvent.DISCONNECTED, this.handleDisconnectedPeerEvent);
342
+ }
343
+ },
344
+ (() => {
345
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
346
+ _heartbeat_decorators = [trackSpan('PeerManager.heartbeat')];
347
+ __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);
348
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
349
+ })(),
350
+ _a;
351
+ })();
352
+ export { PeerManager };
353
+ /**
354
+ * copied from github.com/ChainSafe/lodestar
355
+ * libp2p errors with extremely noisy errors here, which are deeply nested taking 30-50 lines.
356
+ * Some known errors:
357
+ * ```
358
+ * Error: The operation was aborted
359
+ * Error: stream ended before 1 bytes became available
360
+ * Error: Error occurred during XX handshake: Error occurred while verifying signed payload: Peer ID doesn't match libp2p public key
361
+ * ```
362
+ *
363
+ * Also the error's message is not properly formatted, where the error message is indented and includes the full stack
364
+ * ```
365
+ * {
366
+ * emessage: '\n' +
367
+ * ' Error: stream ended before 1 bytes became available\n' +
368
+ * ' at /home/lion/Code/eth2.0/lodestar/node_modules/it-reader/index.js:37:9\n' +
369
+ * ' at runMicrotasks (<anonymous>)\n' +
370
+ * ' at decoder (/home/lion/Code/eth2.0/lodestar/node_modules/it-length-prefixed/src/decode.js:113:22)\n' +
371
+ * ' at first (/home/lion/Code/eth2.0/lodestar/node_modules/it-first/index.js:11:20)\n' +
372
+ * ' at Object.exports.read (/home/lion/Code/eth2.0/lodestar/node_modules/multistream-select/src/multistream.js:31:15)\n' +
373
+ * ' at module.exports (/home/lion/Code/eth2.0/lodestar/node_modules/multistream-select/src/select.js:21:19)\n' +
374
+ * ' at Upgrader._encryptOutbound (/home/lion/Code/eth2.0/lodestar/node_modules/libp2p/src/upgrader.js:397:36)\n' +
375
+ * ' at Upgrader.upgradeOutbound (/home/lion/Code/eth2.0/lodestar/node_modules/libp2p/src/upgrader.js:176:11)\n' +
376
+ * ' at ClassIsWrapper.dial (/home/lion/Code/eth2.0/lodestar/node_modules/libp2p-tcp/src/index.js:49:18)'
377
+ * }
378
+ * ```
379
+ *
380
+ * Tracking issue https://github.com/libp2p/js-libp2p/issues/996
381
+ */
382
+ function formatLibp2pDialError(e) {
383
+ const errorMessage = e.message.trim();
384
+ const newlineIndex = errorMessage.indexOf('\n');
385
+ e.message = newlineIndex !== -1 ? errorMessage.slice(0, newlineIndex) : errorMessage;
386
+ if (e.message.includes('The operation was aborted') ||
387
+ e.message.includes('stream ended before 1 bytes became available') ||
388
+ e.message.includes('The operation was aborted')) {
389
+ e.stack = undefined;
390
+ }
391
+ }
392
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVlcl9tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZpY2VzL3BlZXItbWFuYWdlci9wZWVyX21hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUNBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNyRCxPQUFPLEVBQXdCLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBSzFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFJL0IsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBR3JGLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDeEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ2xELE9BQU8sRUFBRSxjQUFjLEVBQW9CLE1BQU0sbUJBQW1CLENBQUM7QUFFckUsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLENBQUM7QUFDNUIsTUFBTSxnQkFBZ0IsR0FBRyxHQUFHLENBQUM7QUFDN0IsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLFlBQVk7QUFDMUQsTUFBTSx1QkFBdUIsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLG9EQUFvRDtJQWV0RixXQUFXOzs7O3NCQUFYLFdBQVc7WUFRdEIsWUFDVSxVQUF3QixFQUN4QixvQkFBMEMsRUFDMUMsTUFBaUIsRUFDekIsZUFBZ0MsRUFDeEIsU0FBUyxZQUFZLENBQUMsa0JBQWtCLENBQUMsRUFDekMsV0FBd0IsRUFDeEIsT0FBZ0I7Z0JBTmhCLGVBQVUsSUFUVCxtREFBVyxFQVNaLFVBQVUsRUFBYztnQkFDeEIseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtn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
@@ -1,4 +1,5 @@
1
1
  import { PeerErrorSeverity } from '@aztec/circuit-types';
2
+ import { type PeerId } from '@libp2p/interface';
2
3
  import { type P2PConfig } from '../../config.js';
3
4
  export declare enum PeerScoreState {
4
5
  Banned = 0,
@@ -6,6 +7,7 @@ export declare enum PeerScoreState {
6
7
  Healthy = 2
7
8
  }
8
9
  export declare class PeerScoring {
10
+ private logger;
9
11
  private scores;
10
12
  private lastUpdateTime;
11
13
  private decayInterval;
@@ -14,6 +16,7 @@ export declare class PeerScoring {
14
16
  [key in PeerErrorSeverity]: number;
15
17
  };
16
18
  constructor(config: P2PConfig);
19
+ penalizePeer(peerId: PeerId, penalty: PeerErrorSeverity): number;
17
20
  updateScore(peerId: string, scoreDelta: number): number;
18
21
  decayAllScores(): void;
19
22
  getScore(peerId: string): number;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peer_scoring.d.ts","sourceRoot":"","sources":["../../../src/services/peer-manager/peer_scoring.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAIzD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAQjD,oBAAY,cAAc;IACxB,MAAM,IAAA;IACN,UAAU,IAAA;IACV,OAAO,IAAA;CACR;AAMD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAoC;IAClD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,WAAW,CAAO;IAC1B,aAAa,EAAE;SAAG,GAAG,IAAI,iBAAiB,GAAG,MAAM;KAAE,CAAC;gBAE1C,MAAM,EAAE,SAAS;IAYtB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB;IAQ9D,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAmBvD,cAAc,IAAI,IAAI;IActB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIzB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc;IAYpD,QAAQ,IAAI;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE;CAGpC"}
@@ -0,0 +1,84 @@
1
+ import { PeerErrorSeverity } from '@aztec/circuit-types';
2
+ import { median } from '@aztec/foundation/collection';
3
+ import { createLogger } from '@aztec/foundation/log';
4
+ const DefaultPeerPenalties = {
5
+ [PeerErrorSeverity.LowToleranceError]: 50,
6
+ [PeerErrorSeverity.MidToleranceError]: 10,
7
+ [PeerErrorSeverity.HighToleranceError]: 2,
8
+ };
9
+ export var PeerScoreState;
10
+ (function (PeerScoreState) {
11
+ PeerScoreState[PeerScoreState["Banned"] = 0] = "Banned";
12
+ PeerScoreState[PeerScoreState["Disconnect"] = 1] = "Disconnect";
13
+ PeerScoreState[PeerScoreState["Healthy"] = 2] = "Healthy";
14
+ })(PeerScoreState || (PeerScoreState = {}));
15
+ // TODO: move into config / constants
16
+ const MIN_SCORE_BEFORE_BAN = -100;
17
+ const MIN_SCORE_BEFORE_DISCONNECT = -50;
18
+ export class PeerScoring {
19
+ constructor(config) {
20
+ this.logger = createLogger('p2p:peer-scoring');
21
+ this.scores = new Map();
22
+ this.lastUpdateTime = new Map();
23
+ this.decayInterval = 1000 * 60; // 1 minute
24
+ this.decayFactor = 0.9;
25
+ const orderedValues = config.peerPenaltyValues?.sort((a, b) => a - b);
26
+ this.peerPenalties = {
27
+ [PeerErrorSeverity.HighToleranceError]: orderedValues?.[0] ?? DefaultPeerPenalties[PeerErrorSeverity.HighToleranceError],
28
+ [PeerErrorSeverity.MidToleranceError]: orderedValues?.[1] ?? DefaultPeerPenalties[PeerErrorSeverity.MidToleranceError],
29
+ [PeerErrorSeverity.LowToleranceError]: orderedValues?.[2] ?? DefaultPeerPenalties[PeerErrorSeverity.LowToleranceError],
30
+ };
31
+ }
32
+ penalizePeer(peerId, penalty) {
33
+ const id = peerId.toString();
34
+ const penaltyValue = this.peerPenalties[penalty];
35
+ const newScore = this.updateScore(id, -penaltyValue);
36
+ this.logger.verbose(`Penalizing peer ${id} with ${penalty} (new score is ${newScore})`);
37
+ return newScore;
38
+ }
39
+ updateScore(peerId, scoreDelta) {
40
+ const currentTime = Date.now();
41
+ const lastUpdate = this.lastUpdateTime.get(peerId) || currentTime;
42
+ const timePassed = currentTime - lastUpdate;
43
+ const decayPeriods = Math.floor(timePassed / this.decayInterval);
44
+ let currentScore = this.scores.get(peerId) || 0;
45
+ // Apply decay
46
+ currentScore *= Math.pow(this.decayFactor, decayPeriods);
47
+ // Apply new score delta
48
+ currentScore += scoreDelta;
49
+ this.scores.set(peerId, currentScore);
50
+ this.lastUpdateTime.set(peerId, currentTime);
51
+ return currentScore;
52
+ }
53
+ decayAllScores() {
54
+ const currentTime = Date.now();
55
+ for (const [peerId, lastUpdate] of this.lastUpdateTime.entries()) {
56
+ const timePassed = currentTime - lastUpdate;
57
+ const decayPeriods = Math.floor(timePassed / this.decayInterval);
58
+ if (decayPeriods > 0) {
59
+ let score = this.scores.get(peerId) || 0;
60
+ score *= Math.pow(this.decayFactor, decayPeriods);
61
+ this.scores.set(peerId, score);
62
+ this.lastUpdateTime.set(peerId, currentTime);
63
+ }
64
+ }
65
+ }
66
+ getScore(peerId) {
67
+ return this.scores.get(peerId) || 0;
68
+ }
69
+ getScoreState(peerId) {
70
+ // TODO(#11329): permanently store banned peers?
71
+ const score = this.getScore(peerId);
72
+ if (score < MIN_SCORE_BEFORE_BAN) {
73
+ return PeerScoreState.Banned;
74
+ }
75
+ if (score < MIN_SCORE_BEFORE_DISCONNECT) {
76
+ return PeerScoreState.Disconnect;
77
+ }
78
+ return PeerScoreState.Healthy;
79
+ }
80
+ getStats() {
81
+ return { medianScore: median(Array.from(this.scores.values())) ?? 0 };
82
+ }
83
+ }
84
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVlcl9zY29yaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZpY2VzL3BlZXItbWFuYWdlci9wZWVyX3Njb3JpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDekQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3RELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQU1yRCxNQUFNLG9CQUFvQixHQUFHO0lBQzNCLENBQUMsaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsRUFBRSxFQUFFO0lBQ3pDLENBQUMsaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsRUFBRSxFQUFFO0lBQ3pDLENBQUMsaUJBQWlCLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDO0NBQzFDLENBQUM7QUFFRixNQUFNLENBQU4sSUFBWSxjQUlYO0FBSkQsV0FBWSxjQUFjO0lBQ3hCLHVEQUFNLENBQUE7SUFDTiwrREFBVSxDQUFBO0lBQ1YseURBQU8sQ0FBQTtBQUNULENBQUMsRUFKVyxjQUFjLEtBQWQsY0FBYyxRQUl6QjtBQUVELHFDQUFxQztBQUNyQyxNQUFNLG9CQUFvQixHQUFHLENBQUMsR0FBRyxDQUFDO0FBQ2xDLE1BQU0sMkJBQTJCLEdBQUcsQ0FBQyxFQUFFLENBQUM7QUFFeEMsTUFBTSxPQUFPLFdBQVc7SUFRdEIsWUFBWSxNQUFpQjtRQVByQixXQUFNLEdBQUcsWUFBWSxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDMUMsV0FBTSxHQUF3QixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3hDLG1CQUFjLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDaEQsa0JBQWEsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUMsV0FBVztRQUN0QyxnQkFBVyxHQUFHLEdBQUcsQ0FBQztRQUl4QixNQUFNLGFBQWEs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
@@ -0,0 +1,45 @@
1
+ import { type PeerId } from '@libp2p/interface';
2
+ import { type ConnectionSampler } from './connection_sampler.js';
3
+ /**
4
+ * Manages batches of peers for parallel request processing.
5
+ * Tracks active peers and provides deterministic peer assignment for requests.
6
+ *
7
+ * Example with 3 peers and 10 requests:
8
+ *
9
+ * Peers: [P1] [P2] [P3]
10
+ * ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
11
+ * Requests: 0,1,2,9 | 3,4,5 | 6,7,8
12
+ *
13
+ * Each peer handles a bucket of consecutive requests.
14
+ * If a peer fails, it is replaced while maintaining the same bucket.
15
+ */
16
+ export declare class BatchConnectionSampler {
17
+ private readonly connectionSampler;
18
+ private readonly logger;
19
+ private readonly batch;
20
+ private readonly requestsPerPeer;
21
+ constructor(connectionSampler: ConnectionSampler, batchSize: number, maxPeers: number);
22
+ /**
23
+ * Gets the peer responsible for handling a specific request index
24
+ *
25
+ * @param index - The request index
26
+ * @returns The peer assigned to handle this request
27
+ */
28
+ getPeerForRequest(index: number): PeerId | undefined;
29
+ /**
30
+ * Removes a peer and replaces it with a new one, maintaining the same position
31
+ * in the batch array to keep request distribution consistent
32
+ *
33
+ * @param peerId - The peer to remove and replace
34
+ */
35
+ removePeerAndReplace(peerId: PeerId): void;
36
+ /**
37
+ * Gets the number of active peers
38
+ */
39
+ get activePeerCount(): number;
40
+ /**
41
+ * Gets the number of requests each peer is assigned to handle
42
+ */
43
+ get requestsPerBucket(): number;
44
+ }
45
+ //# sourceMappingURL=batch_connection_sampler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch_connection_sampler.d.ts","sourceRoot":"","sources":["../../../../src/services/reqresp/connection-sampler/batch_connection_sampler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;;;;;;;;;;GAYG;AACH,qBAAa,sBAAsB;IAKrB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAJ9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwD;IAC/E,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;gBAEZ,iBAAiB,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAetG;;;;;OAKG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAUpD;;;;;OAKG;IACH,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAmB1C;;OAEG;IACH,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED;;OAEG;IACH,IAAI,iBAAiB,IAAI,MAAM,CAE9B;CACF"}