@aztec/p2p 0.71.0 → 0.73.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 (153) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +2 -2
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/bootstrap/bootstrap.js +1 -1
  4. package/dest/client/factory.js +4 -4
  5. package/dest/client/p2p_client.d.ts +13 -16
  6. package/dest/client/p2p_client.d.ts.map +1 -1
  7. package/dest/client/p2p_client.js +55 -67
  8. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  9. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +11 -19
  10. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +6 -13
  11. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  12. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +74 -80
  13. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  14. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +5 -5
  15. package/dest/mem_pools/attestation_pool/mocks.d.ts +3 -2
  16. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  17. package/dest/mem_pools/attestation_pool/mocks.js +3 -3
  18. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +9 -9
  19. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  20. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +60 -54
  21. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +7 -7
  22. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  23. package/dest/mem_pools/tx_pool/memory_tx_pool.js +17 -18
  24. package/dest/mem_pools/tx_pool/tx_pool.d.ts +7 -7
  25. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  26. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  27. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +48 -47
  28. package/dest/mocks/index.d.ts +3 -3
  29. package/dest/mocks/index.d.ts.map +1 -1
  30. package/dest/mocks/index.js +19 -18
  31. package/dest/msg_validators/attestation_validator/attestation_validator.js +2 -2
  32. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +2 -2
  33. package/dest/msg_validators/tx_validator/block_header_validator.js +3 -3
  34. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  35. package/dest/msg_validators/tx_validator/data_validator.js +7 -7
  36. package/dest/msg_validators/tx_validator/double_spend_validator.js +3 -3
  37. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  38. package/dest/msg_validators/tx_validator/metadata_validator.js +9 -9
  39. package/dest/services/data_store.d.ts +4 -4
  40. package/dest/services/data_store.d.ts.map +1 -1
  41. package/dest/services/data_store.js +7 -7
  42. package/dest/services/dummy_service.d.ts +7 -0
  43. package/dest/services/dummy_service.d.ts.map +1 -1
  44. package/dest/services/dummy_service.js +10 -1
  45. package/dest/services/libp2p/libp2p_service.d.ts +19 -15
  46. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  47. package/dest/services/libp2p/libp2p_service.js +163 -134
  48. package/dest/services/peer-manager/metrics.d.ts +12 -0
  49. package/dest/services/peer-manager/metrics.d.ts.map +1 -0
  50. package/dest/services/peer-manager/metrics.js +26 -0
  51. package/dest/services/{peer_manager.d.ts → peer-manager/peer_manager.d.ts} +24 -8
  52. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -0
  53. package/dest/services/peer-manager/peer_manager.js +395 -0
  54. package/dest/services/{peer-scoring → peer-manager}/peer_scoring.d.ts +3 -0
  55. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -0
  56. package/dest/services/peer-manager/peer_scoring.js +84 -0
  57. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +45 -0
  58. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -0
  59. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +81 -0
  60. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +61 -0
  61. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -0
  62. package/dest/services/reqresp/connection-sampler/connection_sampler.js +175 -0
  63. package/dest/services/reqresp/interface.d.ts +17 -4
  64. package/dest/services/reqresp/interface.d.ts.map +1 -1
  65. package/dest/services/reqresp/interface.js +34 -11
  66. package/dest/services/reqresp/metrics.d.ts +15 -0
  67. package/dest/services/reqresp/metrics.d.ts.map +1 -0
  68. package/dest/services/reqresp/metrics.js +42 -0
  69. package/dest/services/reqresp/protocols/block.d.ts +4 -0
  70. package/dest/services/reqresp/protocols/block.d.ts.map +1 -0
  71. package/dest/services/reqresp/protocols/block.js +9 -0
  72. package/dest/services/reqresp/protocols/goodbye.d.ts +51 -0
  73. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -0
  74. package/dest/services/reqresp/protocols/goodbye.js +92 -0
  75. package/dest/services/reqresp/protocols/index.d.ts +9 -0
  76. package/dest/services/reqresp/protocols/index.d.ts.map +1 -0
  77. package/dest/services/reqresp/protocols/index.js +9 -0
  78. package/dest/services/reqresp/protocols/ping.d.ts +9 -0
  79. package/dest/services/reqresp/protocols/ping.d.ts.map +1 -0
  80. package/dest/services/reqresp/protocols/ping.js +9 -0
  81. package/dest/services/reqresp/{handlers.d.ts → protocols/status.d.ts} +1 -7
  82. package/dest/services/reqresp/protocols/status.d.ts.map +1 -0
  83. package/dest/services/reqresp/protocols/status.js +9 -0
  84. package/dest/services/reqresp/protocols/tx.d.ts +13 -0
  85. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -0
  86. package/dest/services/reqresp/protocols/tx.js +23 -0
  87. package/dest/services/reqresp/rate-limiter/index.d.ts.map +1 -0
  88. package/dest/services/reqresp/{rate_limiter → rate-limiter}/index.js +1 -1
  89. package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.d.ts +3 -3
  90. package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.d.ts.map +1 -1
  91. package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.js +4 -4
  92. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -0
  93. package/dest/services/reqresp/rate-limiter/rate_limits.js +55 -0
  94. package/dest/services/reqresp/reqresp.d.ts +33 -6
  95. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  96. package/dest/services/reqresp/reqresp.js +414 -249
  97. package/dest/services/service.d.ts +8 -0
  98. package/dest/services/service.d.ts.map +1 -1
  99. package/dest/util.d.ts +6 -2
  100. package/dest/util.d.ts.map +1 -1
  101. package/dest/util.js +2 -2
  102. package/package.json +8 -8
  103. package/src/bootstrap/bootstrap.ts +2 -2
  104. package/src/client/factory.ts +3 -3
  105. package/src/client/p2p_client.ts +68 -80
  106. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +14 -22
  107. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +100 -94
  108. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +4 -4
  109. package/src/mem_pools/attestation_pool/mocks.ts +5 -5
  110. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +84 -73
  111. package/src/mem_pools/tx_pool/memory_tx_pool.ts +26 -23
  112. package/src/mem_pools/tx_pool/tx_pool.ts +7 -7
  113. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +50 -47
  114. package/src/mocks/index.ts +19 -20
  115. package/src/msg_validators/attestation_validator/attestation_validator.ts +1 -1
  116. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +1 -1
  117. package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
  118. package/src/msg_validators/tx_validator/data_validator.ts +12 -9
  119. package/src/msg_validators/tx_validator/double_spend_validator.ts +2 -2
  120. package/src/msg_validators/tx_validator/metadata_validator.ts +8 -8
  121. package/src/services/data_store.ts +9 -9
  122. package/src/services/dummy_service.ts +13 -0
  123. package/src/services/libp2p/libp2p_service.ts +212 -163
  124. package/src/services/peer-manager/metrics.ts +41 -0
  125. package/src/services/{peer_manager.ts → peer-manager/peer_manager.ts} +73 -23
  126. package/src/services/{peer-scoring → peer-manager}/peer_scoring.ts +16 -3
  127. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +94 -0
  128. package/src/services/reqresp/connection-sampler/connection_sampler.ts +211 -0
  129. package/src/services/reqresp/interface.ts +39 -16
  130. package/src/services/reqresp/metrics.ts +57 -0
  131. package/src/services/reqresp/protocols/block.ts +15 -0
  132. package/src/services/reqresp/protocols/goodbye.ts +101 -0
  133. package/src/services/reqresp/protocols/index.ts +8 -0
  134. package/src/services/reqresp/protocols/ping.ts +8 -0
  135. package/src/services/reqresp/{handlers.ts → protocols/status.ts} +0 -9
  136. package/src/services/reqresp/protocols/tx.ts +29 -0
  137. package/src/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.ts +3 -3
  138. package/src/services/reqresp/{rate_limiter → rate-limiter}/rate_limits.ts +24 -4
  139. package/src/services/reqresp/reqresp.ts +231 -26
  140. package/src/services/service.ts +12 -0
  141. package/src/util.ts +11 -4
  142. package/dest/services/peer-scoring/peer_scoring.d.ts.map +0 -1
  143. package/dest/services/peer-scoring/peer_scoring.js +0 -75
  144. package/dest/services/peer_manager.d.ts.map +0 -1
  145. package/dest/services/peer_manager.js +0 -358
  146. package/dest/services/reqresp/handlers.d.ts.map +0 -1
  147. package/dest/services/reqresp/handlers.js +0 -17
  148. package/dest/services/reqresp/rate_limiter/index.d.ts.map +0 -1
  149. package/dest/services/reqresp/rate_limiter/rate_limits.d.ts.map +0 -1
  150. package/dest/services/reqresp/rate_limiter/rate_limits.js +0 -35
  151. /package/dest/services/reqresp/{rate_limiter → rate-limiter}/index.d.ts +0 -0
  152. /package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limits.d.ts +0 -0
  153. /package/src/services/reqresp/{rate_limiter → rate-limiter}/index.ts +0 -0
@@ -12,7 +12,7 @@ import {
12
12
  type RawGossipMessage,
13
13
  TopicTypeMap,
14
14
  Tx,
15
- TxHash,
15
+ type TxHash,
16
16
  type TxValidationResult,
17
17
  type WorldStateSynchronizer,
18
18
  getTopicTypeForClientType,
@@ -23,7 +23,7 @@ import { type EpochCache } from '@aztec/epoch-cache';
23
23
  import { createLogger } from '@aztec/foundation/log';
24
24
  import { SerialQueue } from '@aztec/foundation/queue';
25
25
  import { RunningPromise } from '@aztec/foundation/running-promise';
26
- import type { AztecKVStore } from '@aztec/kv-store';
26
+ import type { AztecAsyncKVStore } from '@aztec/kv-store';
27
27
  import { Attributes, OtelMetricsAdapter, type TelemetryClient, WithTracer, trackSpan } from '@aztec/telemetry-client';
28
28
 
29
29
  import { type ENR } from '@chainsafe/enr';
@@ -38,6 +38,7 @@ import { noise } from '@chainsafe/libp2p-noise';
38
38
  import { yamux } from '@chainsafe/libp2p-yamux';
39
39
  import { identify } from '@libp2p/identify';
40
40
  import { type Message, type PeerId, TopicValidatorResult } from '@libp2p/interface';
41
+ import { type ConnectionManager } from '@libp2p/interface-internal';
41
42
  import '@libp2p/kad-dht';
42
43
  import { mplex } from '@libp2p/mplex';
43
44
  import { tcp } from '@libp2p/tcp';
@@ -56,18 +57,11 @@ import {
56
57
  import { type PubSubLibp2p, convertToMultiaddr } from '../../util.js';
57
58
  import { AztecDatastore } from '../data_store.js';
58
59
  import { SnappyTransform, fastMsgIdFn, getMsgIdFn, msgIdToStrFn } from '../encoding.js';
59
- import { PeerManager } from '../peer_manager.js';
60
- import { pingHandler, statusHandler } from '../reqresp/handlers.js';
61
- import {
62
- DEFAULT_SUB_PROTOCOL_HANDLERS,
63
- DEFAULT_SUB_PROTOCOL_VALIDATORS,
64
- PING_PROTOCOL,
65
- type ReqRespSubProtocol,
66
- type ReqRespSubProtocolHandlers,
67
- STATUS_PROTOCOL,
68
- type SubProtocolMap,
69
- TX_REQ_PROTOCOL,
70
- } from '../reqresp/interface.js';
60
+ import { PeerManager } from '../peer-manager/peer_manager.js';
61
+ import { PeerScoring } from '../peer-manager/peer_scoring.js';
62
+ import { DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, type SubProtocolMap } from '../reqresp/interface.js';
63
+ import { reqGoodbyeHandler } from '../reqresp/protocols/goodbye.js';
64
+ import { pingHandler, reqRespBlockHandler, reqRespTxHandler, statusHandler } from '../reqresp/protocols/index.js';
71
65
  import { ReqResp } from '../reqresp/reqresp.js';
72
66
  import type { P2PService, PeerDiscoveryService } from '../service.js';
73
67
  import { GossipSubEvent } from '../types.js';
@@ -117,121 +111,44 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
117
111
  private peerDiscoveryService: PeerDiscoveryService,
118
112
  private mempools: MemPools<T>,
119
113
  private l2BlockSource: L2BlockSource,
120
- private epochCache: EpochCache,
114
+ epochCache: EpochCache,
121
115
  private proofVerifier: ClientProtocolCircuitVerifier,
122
116
  private worldStateSynchronizer: WorldStateSynchronizer,
123
- private telemetry: TelemetryClient,
124
- private requestResponseHandlers: ReqRespSubProtocolHandlers = DEFAULT_SUB_PROTOCOL_HANDLERS,
117
+ telemetry: TelemetryClient,
125
118
  private logger = createLogger('p2p:libp2p_service'),
126
119
  ) {
127
120
  super(telemetry, 'LibP2PService');
128
121
 
129
- this.peerManager = new PeerManager(node, peerDiscoveryService, config, telemetry, logger);
122
+ const peerScoring = new PeerScoring(config);
123
+ this.reqresp = new ReqResp(config, node, peerScoring);
124
+
125
+ this.peerManager = new PeerManager(
126
+ node,
127
+ peerDiscoveryService,
128
+ config,
129
+ telemetry,
130
+ logger,
131
+ peerScoring,
132
+ this.reqresp,
133
+ );
134
+
135
+ // Update gossipsub score params
130
136
  this.node.services.pubsub.score.params.appSpecificScore = (peerId: string) => {
131
137
  return this.peerManager.getPeerScore(peerId);
132
138
  };
133
139
  this.node.services.pubsub.score.params.appSpecificWeight = 10;
134
- this.reqresp = new ReqResp(config, node, this.peerManager);
135
140
 
136
141
  this.attestationValidator = new AttestationValidator(epochCache);
137
142
  this.blockProposalValidator = new BlockProposalValidator(epochCache);
138
143
  this.epochProofQuoteValidator = new EpochProofQuoteValidator(epochCache);
139
144
 
140
- this.blockReceivedCallback = (block: BlockProposal): Promise<BlockAttestation | undefined> => {
141
- this.logger.verbose(
142
- `[WARNING] handler not yet registered: Block received callback not set. Received block ${block.p2pMessageIdentifier()} from peer.`,
145
+ this.blockReceivedCallback = async (block: BlockProposal): Promise<BlockAttestation | undefined> => {
146
+ this.logger.warn(
147
+ `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber.toNumber()} from peer.`,
148
+ { p2pMessageIdentifier: await block.p2pMessageIdentifier() },
143
149
  );
144
- return Promise.resolve(undefined);
145
- };
146
- }
147
-
148
- /**
149
- * Starts the LibP2P service.
150
- * @returns An empty promise.
151
- */
152
- public async start() {
153
- // Check if service is already started
154
- if (this.node.status === 'started') {
155
- throw new Error('P2P service already started');
156
- }
157
-
158
- // Get listen & announce addresses for logging
159
- const { tcpListenAddress, tcpAnnounceAddress } = this.config;
160
- if (!tcpAnnounceAddress) {
161
- throw new Error('Announce address not provided.');
162
- }
163
- const announceTcpMultiaddr = convertToMultiaddr(tcpAnnounceAddress, 'tcp');
164
-
165
- // Start job queue, peer discovery service and libp2p node
166
- this.jobQueue.start();
167
- await this.peerDiscoveryService.start();
168
- await this.node.start();
169
-
170
- // Subscribe to standard GossipSub topics by default
171
- for (const topic of getTopicTypeForClientType(this.clientType)) {
172
- this.subscribeToTopic(TopicTypeMap[topic].p2pTopic);
173
- }
174
-
175
- // Add p2p topic validators
176
- // As they are stored within a kv pair, there is no need to register them conditionally
177
- // based on the client type
178
- const topicValidators = {
179
- [Tx.p2pTopic]: this.validatePropagatedTxFromMessage.bind(this),
180
- [BlockAttestation.p2pTopic]: this.validatePropagatedAttestationFromMessage.bind(this),
181
- [BlockProposal.p2pTopic]: this.validatePropagatedBlockFromMessage.bind(this),
182
- [EpochProofQuote.p2pTopic]: this.validatePropagatedEpochProofQuoteFromMessage.bind(this),
183
- };
184
- for (const [topic, validator] of Object.entries(topicValidators)) {
185
- this.node.services.pubsub.topicValidators.set(topic, validator);
186
- }
187
-
188
- // add GossipSub listener
189
- this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.handleGossipSubEvent.bind(this));
190
-
191
- // Start running promise for peer discovery
192
- this.discoveryRunningPromise = new RunningPromise(
193
- () => this.peerManager.heartbeat(),
194
- this.logger,
195
- this.config.peerCheckIntervalMS,
196
- );
197
- this.discoveryRunningPromise.start();
198
-
199
- // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
200
- const reqrespSubProtocolValidators = {
201
- ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
202
- [TX_REQ_PROTOCOL]: this.validateRequestedTx.bind(this),
150
+ return undefined;
203
151
  };
204
- await this.reqresp.start(this.requestResponseHandlers, reqrespSubProtocolValidators);
205
- this.logger.info(`Started P2P service`, {
206
- listen: tcpListenAddress,
207
- announce: announceTcpMultiaddr,
208
- peerId: this.node.peerId.toString(),
209
- });
210
- }
211
-
212
- /**
213
- * Stops the LibP2P service.
214
- * @returns An empty promise.
215
- */
216
- public async stop() {
217
- // Remove gossip sub listener
218
- this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.handleGossipSubEvent.bind(this));
219
-
220
- // Stop peer manager
221
- this.logger.debug('Stopping peer manager...');
222
- this.peerManager.stop();
223
-
224
- this.logger.debug('Stopping job queue...');
225
- await this.jobQueue.end();
226
- this.logger.debug('Stopping running promise...');
227
- await this.discoveryRunningPromise?.stop();
228
- this.logger.debug('Stopping peer discovery service...');
229
- await this.peerDiscoveryService.stop();
230
- this.logger.debug('Request response service stopped...');
231
- await this.reqresp.stop();
232
- this.logger.debug('Stopping LibP2P...');
233
- await this.stopLibP2P();
234
- this.logger.info('LibP2P service stopped');
235
152
  }
236
153
 
237
154
  /**
@@ -250,7 +167,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
250
167
  epochCache: EpochCache,
251
168
  proofVerifier: ClientProtocolCircuitVerifier,
252
169
  worldStateSynchronizer: WorldStateSynchronizer,
253
- store: AztecKVStore,
170
+ store: AztecAsyncKVStore,
254
171
  telemetry: TelemetryClient,
255
172
  ) {
256
173
  const { tcpListenAddress, tcpAnnounceAddress, minPeerCount, maxPeerCount } = config;
@@ -333,28 +250,12 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
333
250
  },
334
251
  }),
335
252
  }) as (components: GossipSubComponents) => GossipSub,
253
+ components: (components: { connectionManager: ConnectionManager }) => ({
254
+ connectionManager: components.connectionManager,
255
+ }),
336
256
  },
337
257
  });
338
258
 
339
- // Create request response protocol handlers
340
- /**
341
- * Handler for tx requests
342
- * @param msg - the tx request message
343
- * @returns the tx response message
344
- */
345
- const txHandler = (msg: Buffer): Promise<Buffer> => {
346
- const txHash = TxHash.fromBuffer(msg);
347
- const foundTx = mempools.txPool.getTxByHash(txHash);
348
- const buf = foundTx ? foundTx.toBuffer() : Buffer.alloc(0);
349
- return Promise.resolve(buf);
350
- };
351
-
352
- const requestResponseHandlers = {
353
- [PING_PROTOCOL]: pingHandler,
354
- [STATUS_PROTOCOL]: statusHandler,
355
- [TX_REQ_PROTOCOL]: txHandler,
356
- };
357
-
358
259
  return new LibP2PService(
359
260
  clientType,
360
261
  config,
@@ -366,19 +267,123 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
366
267
  proofVerifier,
367
268
  worldStateSynchronizer,
368
269
  telemetry,
369
- requestResponseHandlers,
370
270
  );
371
271
  }
372
272
 
273
+ /**
274
+ * Starts the LibP2P service.
275
+ * @returns An empty promise.
276
+ */
277
+ public async start() {
278
+ // Check if service is already started
279
+ if (this.node.status === 'started') {
280
+ throw new Error('P2P service already started');
281
+ }
282
+
283
+ // Get listen & announce addresses for logging
284
+ const { tcpListenAddress, tcpAnnounceAddress } = this.config;
285
+ if (!tcpAnnounceAddress) {
286
+ throw new Error('Announce address not provided.');
287
+ }
288
+ const announceTcpMultiaddr = convertToMultiaddr(tcpAnnounceAddress, 'tcp');
289
+
290
+ // Start job queue, peer discovery service and libp2p node
291
+ this.jobQueue.start();
292
+ await this.peerDiscoveryService.start();
293
+ await this.node.start();
294
+
295
+ // Subscribe to standard GossipSub topics by default
296
+ for (const topic of getTopicTypeForClientType(this.clientType)) {
297
+ this.subscribeToTopic(TopicTypeMap[topic].p2pTopic);
298
+ }
299
+
300
+ // Create request response protocol handlers
301
+ const txHandler = reqRespTxHandler(this.mempools);
302
+ const goodbyeHandler = reqGoodbyeHandler(this.peerManager);
303
+ const blockHandler = reqRespBlockHandler(this.l2BlockSource);
304
+
305
+ const requestResponseHandlers = {
306
+ [ReqRespSubProtocol.PING]: pingHandler,
307
+ [ReqRespSubProtocol.STATUS]: statusHandler,
308
+ [ReqRespSubProtocol.TX]: txHandler.bind(this),
309
+ [ReqRespSubProtocol.GOODBYE]: goodbyeHandler.bind(this),
310
+ [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
311
+ };
312
+
313
+ // Add p2p topic validators
314
+ // As they are stored within a kv pair, there is no need to register them conditionally
315
+ // based on the client type
316
+ const topicValidators = {
317
+ [Tx.p2pTopic]: this.validatePropagatedTxFromMessage.bind(this),
318
+ [BlockAttestation.p2pTopic]: this.validatePropagatedAttestationFromMessage.bind(this),
319
+ [BlockProposal.p2pTopic]: this.validatePropagatedBlockFromMessage.bind(this),
320
+ [EpochProofQuote.p2pTopic]: this.validatePropagatedEpochProofQuoteFromMessage.bind(this),
321
+ };
322
+ for (const [topic, validator] of Object.entries(topicValidators)) {
323
+ this.node.services.pubsub.topicValidators.set(topic, validator);
324
+ }
325
+
326
+ // add GossipSub listener
327
+ this.node.services.pubsub.addEventListener(GossipSubEvent.MESSAGE, this.handleGossipSubEvent.bind(this));
328
+
329
+ // Start running promise for peer discovery
330
+ this.discoveryRunningPromise = new RunningPromise(
331
+ () => this.peerManager.heartbeat(),
332
+ this.logger,
333
+ this.config.peerCheckIntervalMS,
334
+ );
335
+ this.discoveryRunningPromise.start();
336
+
337
+ // Define the sub protocol validators - This is done within this start() method to gain a callback to the existing validateTx function
338
+ const reqrespSubProtocolValidators = {
339
+ ...DEFAULT_SUB_PROTOCOL_VALIDATORS,
340
+ // TODO(#11336): A request validator for blocks
341
+ [ReqRespSubProtocol.TX]: this.validateRequestedTx.bind(this),
342
+ };
343
+ await this.reqresp.start(requestResponseHandlers, reqrespSubProtocolValidators);
344
+ this.logger.info(`Started P2P service`, {
345
+ listen: tcpListenAddress,
346
+ announce: announceTcpMultiaddr,
347
+ peerId: this.node.peerId.toString(),
348
+ });
349
+ }
350
+
351
+ /**
352
+ * Stops the LibP2P service.
353
+ * @returns An empty promise.
354
+ */
355
+ public async stop() {
356
+ // Remove gossip sub listener
357
+ this.node.services.pubsub.removeEventListener(GossipSubEvent.MESSAGE, this.handleGossipSubEvent.bind(this));
358
+
359
+ // Stop peer manager
360
+ this.logger.debug('Stopping peer manager...');
361
+ await this.peerManager.stop();
362
+
363
+ this.logger.debug('Stopping job queue...');
364
+ await this.jobQueue.end();
365
+ this.logger.debug('Stopping running promise...');
366
+ await this.discoveryRunningPromise?.stop();
367
+ this.logger.debug('Stopping peer discovery service...');
368
+ await this.peerDiscoveryService.stop();
369
+ this.logger.debug('Request response service stopped...');
370
+ await this.reqresp.stop();
371
+ this.logger.debug('Stopping LibP2P...');
372
+ await this.stopLibP2P();
373
+ this.logger.info('LibP2P service stopped');
374
+ }
375
+
373
376
  public getPeers(includePending?: boolean): PeerInfo[] {
374
377
  return this.peerManager.getPeers(includePending);
375
378
  }
376
379
 
377
- private async handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
380
+ private handleGossipSubEvent(e: CustomEvent<GossipsubMessage>) {
378
381
  const { msg } = e.detail;
379
382
  this.logger.trace(`Received PUBSUB message.`);
380
383
 
381
- await this.jobQueue.put(() => this.handleNewGossipMessage(msg));
384
+ void this.jobQueue
385
+ .put(() => this.handleNewGossipMessage(msg))
386
+ .catch(err => this.logger.error(`Error processing gossip message`, err));
382
387
  }
383
388
 
384
389
  /**
@@ -398,6 +403,19 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
398
403
  return this.reqresp.sendRequest(protocol, request);
399
404
  }
400
405
 
406
+ /**
407
+ * Send a batch of requests to peers, and return the responses
408
+ * @param protocol - The request response protocol to use
409
+ * @param requests - The requests to send to the peers
410
+ * @returns The responses to the requests
411
+ */
412
+ sendBatchRequest<SubProtocol extends ReqRespSubProtocol>(
413
+ protocol: SubProtocol,
414
+ requests: InstanceType<SubProtocolMap[SubProtocol]['request']>[],
415
+ ): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[] | undefined> {
416
+ return this.reqresp.sendBatchRequest(protocol, requests);
417
+ }
418
+
401
419
  /**
402
420
  * Get the ENR of the node
403
421
  * @returns The ENR of the node
@@ -457,7 +475,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
457
475
  }
458
476
  if (message.topic == EpochProofQuote.p2pTopic) {
459
477
  const epochProofQuote = EpochProofQuote.fromBuffer(Buffer.from(message.data));
460
- this.processEpochProofQuoteFromPeer(epochProofQuote);
478
+ await this.processEpochProofQuoteFromPeer(epochProofQuote);
461
479
  }
462
480
 
463
481
  return;
@@ -468,14 +486,22 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
468
486
  *
469
487
  * @param attestation - The attestation to process.
470
488
  */
471
- @trackSpan('Libp2pService.processAttestationFromPeer', attestation => ({
489
+ @trackSpan('Libp2pService.processAttestationFromPeer', async attestation => ({
472
490
  [Attributes.BLOCK_NUMBER]: attestation.payload.header.globalVariables.blockNumber.toNumber(),
473
491
  [Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toNumber(),
474
492
  [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
475
- [Attributes.P2P_ID]: attestation.p2pMessageIdentifier().toString(),
493
+ [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
476
494
  }))
477
495
  private async processAttestationFromPeer(attestation: BlockAttestation): Promise<void> {
478
- this.logger.debug(`Received attestation ${attestation.p2pMessageIdentifier()} from external peer.`);
496
+ this.logger.debug(
497
+ `Received attestation for block ${attestation.blockNumber.toNumber()} slot ${attestation.slotNumber.toNumber()} from external peer.`,
498
+ {
499
+ p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
500
+ slot: attestation.slotNumber.toNumber(),
501
+ archive: attestation.archive.toString(),
502
+ block: attestation.blockNumber.toNumber(),
503
+ },
504
+ );
479
505
  await this.mempools.attestationPool!.addAttestations([attestation]);
480
506
  }
481
507
 
@@ -486,21 +512,37 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
486
512
  * @param block - The block to process.
487
513
  */
488
514
  // REVIEW: callback pattern https://github.com/AztecProtocol/aztec-packages/issues/7963
489
- @trackSpan('Libp2pService.processBlockFromPeer', block => ({
490
- [Attributes.BLOCK_NUMBER]: block.payload.header.globalVariables.blockNumber.toNumber(),
491
- [Attributes.SLOT_NUMBER]: block.payload.header.globalVariables.slotNumber.toNumber(),
515
+ @trackSpan('Libp2pService.processBlockFromPeer', async block => ({
516
+ [Attributes.BLOCK_NUMBER]: block.blockNumber.toNumber(),
517
+ [Attributes.SLOT_NUMBER]: block.slotNumber.toNumber(),
492
518
  [Attributes.BLOCK_ARCHIVE]: block.archive.toString(),
493
- [Attributes.P2P_ID]: block.p2pMessageIdentifier().toString(),
519
+ [Attributes.P2P_ID]: await block.p2pMessageIdentifier().then(i => i.toString()),
494
520
  }))
495
521
  private async processBlockFromPeer(block: BlockProposal): Promise<void> {
496
- this.logger.verbose(`Received block ${block.p2pMessageIdentifier()} from external peer.`);
522
+ this.logger.verbose(
523
+ `Received block ${block.blockNumber.toNumber()} for slot ${block.slotNumber.toNumber()} from external peer.`,
524
+ {
525
+ p2pMessageIdentifier: await block.p2pMessageIdentifier(),
526
+ slot: block.slotNumber.toNumber(),
527
+ archive: block.archive.toString(),
528
+ block: block.blockNumber.toNumber(),
529
+ },
530
+ );
497
531
  const attestation = await this.blockReceivedCallback(block);
498
532
 
499
533
  // TODO: fix up this pattern - the abstraction is not nice
500
534
  // The attestation can be undefined if no handler is registered / the validator deems the block invalid
501
535
  if (attestation != undefined) {
502
- this.logger.verbose(`Broadcasting attestation ${attestation.p2pMessageIdentifier()}`);
503
- this.broadcastAttestation(attestation);
536
+ this.logger.verbose(
537
+ `Broadcasting attestation for block ${attestation.blockNumber.toNumber()} slot ${attestation.slotNumber.toNumber()}`,
538
+ {
539
+ p2pMessageIdentifier: await attestation.p2pMessageIdentifier(),
540
+ slot: attestation.slotNumber.toNumber(),
541
+ archive: attestation.archive.toString(),
542
+ block: attestation.blockNumber.toNumber(),
543
+ },
544
+ );
545
+ await this.broadcastAttestation(attestation);
504
546
  }
505
547
  }
506
548
 
@@ -508,18 +550,24 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
508
550
  * Broadcast an attestation to all peers.
509
551
  * @param attestation - The attestation to broadcast.
510
552
  */
511
- @trackSpan('Libp2pService.broadcastAttestation', attestation => ({
553
+ @trackSpan('Libp2pService.broadcastAttestation', async attestation => ({
512
554
  [Attributes.BLOCK_NUMBER]: attestation.payload.header.globalVariables.blockNumber.toNumber(),
513
555
  [Attributes.SLOT_NUMBER]: attestation.payload.header.globalVariables.slotNumber.toNumber(),
514
556
  [Attributes.BLOCK_ARCHIVE]: attestation.archive.toString(),
515
- [Attributes.P2P_ID]: attestation.p2pMessageIdentifier().toString(),
557
+ [Attributes.P2P_ID]: await attestation.p2pMessageIdentifier().then(i => i.toString()),
516
558
  }))
517
- private broadcastAttestation(attestation: BlockAttestation): void {
518
- this.propagate(attestation);
559
+ private async broadcastAttestation(attestation: BlockAttestation) {
560
+ await this.propagate(attestation);
519
561
  }
520
562
 
521
- private processEpochProofQuoteFromPeer(epochProofQuote: EpochProofQuote): void {
522
- this.logger.verbose(`Received epoch proof quote ${epochProofQuote.p2pMessageIdentifier()} from external peer.`);
563
+ private async processEpochProofQuoteFromPeer(epochProofQuote: EpochProofQuote) {
564
+ const epoch = epochProofQuote.payload.epochToProve;
565
+ const prover = epochProofQuote.payload.prover.toString();
566
+ const p2pMessageIdentifier = await epochProofQuote.p2pMessageIdentifier();
567
+ this.logger.verbose(
568
+ `Received epoch proof quote ${p2pMessageIdentifier} by prover ${prover} for epoch ${epoch} from external peer.`,
569
+ { quote: epochProofQuote.toInspect(), p2pMessageIdentifier },
570
+ );
523
571
  this.mempools.epochProofQuotePool.addQuote(epochProofQuote);
524
572
  }
525
573
 
@@ -527,8 +575,9 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
527
575
  * Propagates provided message to peers.
528
576
  * @param message - The message to propagate.
529
577
  */
530
- public propagate<T extends Gossipable>(message: T): void {
531
- this.logger.trace(`[${message.p2pMessageIdentifier()}] queued`);
578
+ public async propagate<T extends Gossipable>(message: T) {
579
+ const p2pMessageIdentifier = await message.p2pMessageIdentifier();
580
+ this.logger.trace(`Message ${p2pMessageIdentifier} queued`, { p2pMessageIdentifier });
532
581
  void this.jobQueue.put(async () => {
533
582
  await this.sendToPeers(message);
534
583
  });
@@ -548,7 +597,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
548
597
  * In order to perform this check, the tx proof must be verified.
549
598
  *
550
599
  * Note: This function is called from within `ReqResp.sendRequest` as part of the
551
- * TX_REQ_PROTOCOL subprotocol validation.
600
+ * ReqRespSubProtocol.TX subprotocol validation.
552
601
  *
553
602
  * @param requestedTxHash - The hash of the tx that was requested.
554
603
  * @param responseTx - The tx that was received as a response to the request.
@@ -563,7 +612,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
563
612
  const validProof = await proofValidator.validateTx(responseTx);
564
613
 
565
614
  // If the node returns the wrong data, we penalize it
566
- if (!requestedTxHash.equals(responseTx.getTxHash())) {
615
+ if (!requestedTxHash.equals(await responseTx.getTxHash())) {
567
616
  // Returning the wrong data is a low tolerance error
568
617
  this.peerManager.penalizePeer(peerId, PeerErrorSeverity.MidToleranceError);
569
618
  return false;
@@ -591,7 +640,7 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
591
640
  const tx = Tx.fromBuffer(Buffer.from(msg.data));
592
641
  const isValid = await this.validatePropagatedTx(tx, propagationSource);
593
642
  this.logger.trace(`validatePropagatedTx: ${isValid}`, {
594
- [Attributes.TX_HASH]: tx.getTxHash().toString(),
643
+ [Attributes.TX_HASH]: (await tx.getTxHash()).toString(),
595
644
  [Attributes.P2P_ID]: propagationSource.toString(),
596
645
  });
597
646
  return isValid ? TopicValidatorResult.Accept : TopicValidatorResult.Reject;
@@ -654,8 +703,8 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
654
703
  return isValid ? TopicValidatorResult.Accept : TopicValidatorResult.Reject;
655
704
  }
656
705
 
657
- @trackSpan('Libp2pService.validatePropagatedTx', tx => ({
658
- [Attributes.TX_HASH]: tx.getTxHash().toString(),
706
+ @trackSpan('Libp2pService.validatePropagatedTx', async tx => ({
707
+ [Attributes.TX_HASH]: (await tx.getTxHash()).toString(),
659
708
  }))
660
709
  private async validatePropagatedTx(tx: Tx, peerId: PeerId): Promise<boolean> {
661
710
  const blockNumber = (await this.l2BlockSource.getBlockNumber()) + 1;
@@ -851,17 +900,17 @@ export class LibP2PService<T extends P2PClientType> extends WithTracer implement
851
900
  private async sendToPeers<T extends Gossipable>(message: T) {
852
901
  const parent = message.constructor as typeof Gossipable;
853
902
 
854
- const identifier = message.p2pMessageIdentifier().toString();
855
- this.logger.trace(`Sending message ${identifier}`);
903
+ const identifier = await message.p2pMessageIdentifier().then(i => i.toString());
904
+ this.logger.trace(`Sending message ${identifier}`, { p2pMessageIdentifier: identifier });
856
905
 
857
906
  const recipientsNum = await this.publishToTopic(parent.p2pTopic, message.toBuffer());
858
- this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`);
907
+ this.logger.debug(`Sent message ${identifier} to ${recipientsNum} peers`, { p2pMessageIdentifier: identifier });
859
908
  }
860
909
 
861
910
  // Libp2p seems to hang sometimes if new peers are initiating connections.
862
911
  private async stopLibP2P() {
863
912
  const TIMEOUT_MS = 5000; // 5 seconds timeout
864
- const timeout = new Promise((resolve, reject) => {
913
+ const timeout = new Promise((_resolve, reject) => {
865
914
  setTimeout(() => reject(new Error('Timeout during libp2p.stop()')), TIMEOUT_MS);
866
915
  });
867
916
  try {
@@ -0,0 +1,41 @@
1
+ import {
2
+ Attributes,
3
+ Metrics,
4
+ type TelemetryClient,
5
+ type Tracer,
6
+ type UpDownCounter,
7
+ ValueType,
8
+ } from '@aztec/telemetry-client';
9
+
10
+ import { type GoodByeReason, prettyGoodbyeReason } from '../reqresp/protocols/index.js';
11
+
12
+ export class PeerManagerMetrics {
13
+ private sentGoodbyes: UpDownCounter;
14
+ private receivedGoodbyes: UpDownCounter;
15
+
16
+ public readonly tracer: Tracer;
17
+
18
+ constructor(public readonly telemetryClient: TelemetryClient, name = 'PeerManager') {
19
+ this.tracer = telemetryClient.getTracer(name);
20
+
21
+ const meter = telemetryClient.getMeter(name);
22
+ this.sentGoodbyes = meter.createUpDownCounter(Metrics.PEER_MANAGER_GOODBYES_SENT, {
23
+ description: 'Number of goodbyes sent to peers',
24
+ unit: 'peers',
25
+ valueType: ValueType.INT,
26
+ });
27
+ this.receivedGoodbyes = meter.createUpDownCounter(Metrics.PEER_MANAGER_GOODBYES_RECEIVED, {
28
+ description: 'Number of goodbyes received from peers',
29
+ unit: 'peers',
30
+ valueType: ValueType.INT,
31
+ });
32
+ }
33
+
34
+ public recordGoodbyeSent(reason: GoodByeReason) {
35
+ this.sentGoodbyes.add(1, { [Attributes.P2P_GOODBYE_REASON]: prettyGoodbyeReason(reason) });
36
+ }
37
+
38
+ public recordGoodbyeReceived(reason: GoodByeReason) {
39
+ this.receivedGoodbyes.add(1, { [Attributes.P2P_GOODBYE_REASON]: prettyGoodbyeReason(reason) });
40
+ }
41
+ }