@aztec/p2p 0.87.5 → 0.87.7

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 (80) hide show
  1. package/dest/client/interface.d.ts +8 -4
  2. package/dest/client/interface.d.ts.map +1 -1
  3. package/dest/client/p2p_client.d.ts +4 -3
  4. package/dest/client/p2p_client.d.ts.map +1 -1
  5. package/dest/client/p2p_client.js +17 -10
  6. package/dest/config.d.ts +10 -0
  7. package/dest/config.d.ts.map +1 -1
  8. package/dest/config.js +12 -2
  9. package/dest/index.d.ts +1 -0
  10. package/dest/index.d.ts.map +1 -1
  11. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +5 -6
  12. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  13. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +37 -12
  14. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +2 -2
  15. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  16. package/dest/mem_pools/tx_pool/memory_tx_pool.js +1 -3
  17. package/dest/mem_pools/tx_pool/tx_pool.d.ts +6 -1
  18. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  19. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +10 -0
  20. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -0
  21. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.js +36 -0
  22. package/dest/services/dummy_service.d.ts +1 -1
  23. package/dest/services/dummy_service.d.ts.map +1 -1
  24. package/dest/services/dummy_service.js +1 -1
  25. package/dest/services/index.d.ts +1 -0
  26. package/dest/services/index.d.ts.map +1 -1
  27. package/dest/services/index.js +1 -0
  28. package/dest/services/libp2p/instrumentation.d.ts +11 -0
  29. package/dest/services/libp2p/instrumentation.d.ts.map +1 -0
  30. package/dest/services/libp2p/instrumentation.js +29 -0
  31. package/dest/services/libp2p/libp2p_service.d.ts +8 -5
  32. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  33. package/dest/services/libp2p/libp2p_service.js +59 -12
  34. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +1 -1
  35. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
  36. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +7 -3
  37. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -1
  38. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  39. package/dest/services/reqresp/connection-sampler/connection_sampler.js +8 -3
  40. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
  41. package/dest/services/reqresp/protocols/goodbye.js +3 -1
  42. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +4 -2
  43. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  44. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -2
  45. package/dest/services/reqresp/rate-limiter/rate_limits.js +1 -1
  46. package/dest/services/reqresp/reqresp.d.ts +3 -3
  47. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  48. package/dest/services/reqresp/reqresp.js +39 -13
  49. package/dest/services/service.d.ts +3 -2
  50. package/dest/services/service.d.ts.map +1 -1
  51. package/dest/services/tx_collector.d.ts +14 -0
  52. package/dest/services/tx_collector.d.ts.map +1 -0
  53. package/dest/services/tx_collector.js +76 -0
  54. package/dest/test-helpers/reqresp-nodes.d.ts +3 -3
  55. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  56. package/dest/test-helpers/reqresp-nodes.js +4 -4
  57. package/dest/testbench/p2p_client_testbench_worker.js +1 -1
  58. package/package.json +12 -12
  59. package/src/client/interface.ts +8 -4
  60. package/src/client/p2p_client.ts +22 -10
  61. package/src/config.ts +22 -1
  62. package/src/index.ts +2 -0
  63. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +45 -18
  64. package/src/mem_pools/tx_pool/memory_tx_pool.ts +2 -4
  65. package/src/mem_pools/tx_pool/tx_pool.ts +7 -1
  66. package/src/msg_validators/msg_seen_validator/msg_seen_validator.ts +36 -0
  67. package/src/services/dummy_service.ts +3 -1
  68. package/src/services/index.ts +1 -0
  69. package/src/services/libp2p/instrumentation.ts +39 -0
  70. package/src/services/libp2p/libp2p_service.ts +79 -11
  71. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +4 -2
  72. package/src/services/reqresp/connection-sampler/connection_sampler.ts +8 -3
  73. package/src/services/reqresp/protocols/goodbye.ts +3 -1
  74. package/src/services/reqresp/rate-limiter/rate_limiter.ts +9 -3
  75. package/src/services/reqresp/rate-limiter/rate_limits.ts +1 -1
  76. package/src/services/reqresp/reqresp.ts +44 -16
  77. package/src/services/service.ts +4 -1
  78. package/src/services/tx_collector.ts +103 -0
  79. package/src/test-helpers/reqresp-nodes.ts +13 -8
  80. package/src/testbench/p2p_client_testbench_worker.ts +1 -1
@@ -5,6 +5,7 @@ function _ts_decorate(decorators, target, key, desc) {
5
5
  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;
6
6
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
7
  }
8
+ import { compactArray } from '@aztec/foundation/collection';
8
9
  import { createLogger } from '@aztec/foundation/log';
9
10
  import { executeTimeout } from '@aztec/foundation/timer';
10
11
  import { PeerErrorSeverity } from '@aztec/stdlib/p2p';
@@ -44,7 +45,7 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
44
45
  rateLimiter;
45
46
  snappyTransform;
46
47
  metrics;
47
- constructor(config, libp2p, peerScoring, telemetryClient = getTelemetryClient()){
48
+ constructor(config, libp2p, peerScoring, rateLimits = {}, telemetryClient = getTelemetryClient()){
48
49
  this.libp2p = libp2p;
49
50
  this.peerScoring = peerScoring;
50
51
  this.subProtocolHandlers = DEFAULT_SUB_PROTOCOL_HANDLERS;
@@ -52,7 +53,7 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
52
53
  this.logger = createLogger('p2p:reqresp');
53
54
  this.overallRequestTimeoutMs = config.overallRequestTimeoutMs;
54
55
  this.individualRequestTimeoutMs = config.individualRequestTimeoutMs;
55
- this.rateLimiter = new RequestResponseRateLimiter(peerScoring);
56
+ this.rateLimiter = new RequestResponseRateLimiter(peerScoring, rateLimits);
56
57
  // Connection sampler is used to sample our connected peers
57
58
  this.connectionSampler = new ConnectionSampler(libp2p);
58
59
  this.snappyTransform = new SnappyTransform();
@@ -185,7 +186,7 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
185
186
  * @returns
186
187
  *
187
188
  * @throws {CollectiveReqRespTimeoutError} - If the request batch exceeds the specified timeout (`timeoutMs`).
188
- */ async sendBatchRequest(subProtocol, requests, timeoutMs = 10000, maxPeers = Math.max(10, Math.ceil(requests.length / 3)), maxRetryAttempts = 3) {
189
+ */ async sendBatchRequest(subProtocol, requests, pinnedPeer, timeoutMs = 10000, maxPeers = Math.max(10, Math.ceil(requests.length / 3)), maxRetryAttempts = 3) {
189
190
  const responseValidator = this.subProtocolValidators[subProtocol];
190
191
  const responses = new Array(requests.length);
191
192
  const requestBuffers = requests.map((req)=>req.toBuffer());
@@ -193,9 +194,11 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
193
194
  // Track which requests still need to be processed
194
195
  const pendingRequestIndices = new Set(requestBuffers.map((_, i)=>i));
195
196
  // Create batch sampler with the total number of requests and max peers
196
- const batchSampler = new BatchConnectionSampler(this.connectionSampler, requests.length, maxPeers);
197
- if (batchSampler.activePeerCount === 0) {
198
- this.logger.debug('No active peers to send requests to');
197
+ const batchSampler = new BatchConnectionSampler(this.connectionSampler, requests.length, maxPeers, compactArray([
198
+ pinnedPeer
199
+ ]));
200
+ if (batchSampler.activePeerCount === 0 && !pinnedPeer) {
201
+ this.logger.warn('No active peers to send requests to');
199
202
  return [];
200
203
  }
201
204
  // This is where it gets fun
@@ -222,6 +225,15 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
222
225
  }
223
226
  requestBatches.get(peerAsString).indices.push(requestIndex);
224
227
  }
228
+ // If there is a pinned peer, we will always send every request to that peer
229
+ // We use the default limits for the subprotocol to avoid hitting the rate limiter
230
+ if (pinnedPeer) {
231
+ const limit = this.rateLimiter.getRateLimits(subProtocol).peerLimit.quotaCount;
232
+ requestBatches.set(pinnedPeer.toString(), {
233
+ peerId: pinnedPeer,
234
+ indices: Array.from(pendingRequestIndices.values()).slice(0, limit)
235
+ });
236
+ }
225
237
  // Make parallel requests for each peer's batch
226
238
  // A batch entry will look something like this:
227
239
  // PeerId0: [0, 1, 2, 3]
@@ -233,6 +245,7 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
233
245
  // Requests all going to the same peer are sent synchronously
234
246
  const peerResults = [];
235
247
  for (const index of indices){
248
+ this.logger.trace(`Sending request ${index} to peer ${peerAsString}`);
236
249
  const response = await this.sendRequestToPeer(peer, subProtocol, requestBuffers[index]);
237
250
  // Check the status of the response buffer
238
251
  if (response.status !== ReqRespStatus.SUCCESS) {
@@ -468,8 +481,9 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
468
481
  const msg = Buffer.from(chunkList.subarray());
469
482
  const response = await handler(connection.remotePeer, msg);
470
483
  if (protocol === ReqRespSubProtocol.GOODBYE) {
484
+ // NOTE: The stream was already closed by Goodbye handler
485
+ // peerManager.goodbyeReceived(peerId, reason); will call libp2p.hangUp closing all active streams and connections
471
486
  // Don't respond
472
- await stream.close();
473
487
  return;
474
488
  }
475
489
  // Send success code first, then the response
@@ -488,13 +502,25 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
488
502
  if (e instanceof ReqRespStatusError) {
489
503
  errorStatus = e.status;
490
504
  }
491
- const sendErrorChunk = this.sendErrorChunk(errorStatus);
492
- // Return and yield the response chunk
493
- await pipe(stream, async function*(_source) {
494
- yield* sendErrorChunk;
495
- }, stream);
505
+ if (stream.status === 'open') {
506
+ const sendErrorChunk = this.sendErrorChunk(errorStatus);
507
+ // Return and yield the response chunk
508
+ await pipe(stream, async function*(_source) {
509
+ yield* sendErrorChunk;
510
+ }, stream);
511
+ } else {
512
+ this.logger.debug('Stream already closed, not sending error response', {
513
+ protocol,
514
+ err: e,
515
+ errorStatus
516
+ });
517
+ }
496
518
  } finally{
497
- await stream.close();
519
+ //NOTE: All other status codes indicate closed stream.
520
+ //Either graceful close (closed/closing) or forced close (aborted/reset)
521
+ if (stream.status === 'open') {
522
+ await stream.close();
523
+ }
498
524
  }
499
525
  }
500
526
  async *sendErrorChunk(error) {
@@ -9,6 +9,7 @@ export declare enum PeerDiscoveryState {
9
9
  RUNNING = "running",
10
10
  STOPPED = "stopped"
11
11
  }
12
+ export type P2PBlockReceivedCallback = (block: BlockProposal, sender: PeerId) => Promise<BlockAttestation | undefined>;
12
13
  /**
13
14
  * The interface for a P2P service implementation.
14
15
  */
@@ -43,8 +44,8 @@ export interface P2PService {
43
44
  * @param requests - The requests to send to the peers
44
45
  * @returns The responses to the requests
45
46
  */
46
- sendBatchRequest<Protocol extends ReqRespSubProtocol>(protocol: Protocol, requests: InstanceType<SubProtocolMap[Protocol]['request']>[], timeoutMs?: number, maxPeers?: number, maxRetryAttempts?: number): Promise<(InstanceType<SubProtocolMap[Protocol]['response']> | undefined)[]>;
47
- registerBlockReceivedCallback(callback: (block: BlockProposal) => Promise<BlockAttestation | undefined>): void;
47
+ sendBatchRequest<Protocol extends ReqRespSubProtocol>(protocol: Protocol, requests: InstanceType<SubProtocolMap[Protocol]['request']>[], pinnedPeerId?: PeerId, timeoutMs?: number, maxPeers?: number, maxRetryAttempts?: number): Promise<(InstanceType<SubProtocolMap[Protocol]['response']> | undefined)[]>;
48
+ registerBlockReceivedCallback(callback: P2PBlockReceivedCallback): void;
48
49
  getEnr(): ENR | undefined;
49
50
  getPeers(includePending?: boolean): PeerInfo[];
50
51
  validate(txs: Tx[]): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/services/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/services/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type Logger } from '@aztec/foundation/log';
2
+ import type { BlockProposal } from '@aztec/stdlib/p2p';
3
+ import type { Tx, TxHash } from '@aztec/stdlib/tx';
4
+ import type { P2PClient } from '../client/p2p_client.js';
5
+ export declare class TxCollector {
6
+ private p2pClient;
7
+ private log;
8
+ constructor(p2pClient: Pick<P2PClient, 'getTxsByHashFromPool' | 'hasTxsInPool' | 'getTxsByHash' | 'validate' | 'requestTxsByHash'>, log?: Logger);
9
+ collectForBlockProposal(proposal: BlockProposal, peerWhoSentTheProposal: any): Promise<{
10
+ txs: Tx[];
11
+ missing?: TxHash[];
12
+ }>;
13
+ }
14
+ //# sourceMappingURL=tx_collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tx_collector.d.ts","sourceRoot":"","sources":["../../src/services/tx_collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,qBAAa,WAAW;IAEpB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,GAAG;gBAJH,SAAS,EAAE,IAAI,CACrB,SAAS,EACT,sBAAsB,GAAG,cAAc,GAAG,cAAc,GAAG,UAAU,GAAG,kBAAkB,CAC3F,EACO,GAAG,GAAE,MAAyC;IAGlD,uBAAuB,CAC3B,QAAQ,EAAE,aAAa,EACvB,sBAAsB,EAAE,GAAG,GAC1B,OAAO,CAAC;QAAE,GAAG,EAAE,EAAE,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAmF9C"}
@@ -0,0 +1,76 @@
1
+ import { compactArray } from '@aztec/foundation/collection';
2
+ import { createLogger } from '@aztec/foundation/log';
3
+ export class TxCollector {
4
+ p2pClient;
5
+ log;
6
+ constructor(p2pClient, log = createLogger('p2p:tx-collector')){
7
+ this.p2pClient = p2pClient;
8
+ this.log = log;
9
+ }
10
+ async collectForBlockProposal(proposal, peerWhoSentTheProposal) {
11
+ if (proposal.payload.txHashes.length === 0) {
12
+ this.log.verbose(`Received block proposal with no transactions, skipping transaction availability check`);
13
+ return {
14
+ txs: []
15
+ };
16
+ }
17
+ // Is this a new style proposal?
18
+ if (proposal.txs && proposal.txs.length > 0 && proposal.txs.length === proposal.payload.txHashes.length) {
19
+ // Yes, any txs that we already have we should use
20
+ this.log.info(`Using new style proposal with ${proposal.txs.length} transactions`);
21
+ // Request from the pool based on the signed hashes in the payload
22
+ const hashesFromPayload = proposal.payload.txHashes;
23
+ const txsToUse = await this.p2pClient.getTxsByHashFromPool(hashesFromPayload);
24
+ const missingTxs = txsToUse.filter((tx)=>tx === undefined).length;
25
+ if (missingTxs > 0) {
26
+ this.log.verbose(`Missing ${missingTxs}/${hashesFromPayload.length} transactions in the tx pool, will attempt to take from the proposal`);
27
+ }
28
+ let usedFromProposal = 0;
29
+ // Fill any holes with txs in the proposal, provided their hash matches the hash in the payload
30
+ for(let i = 0; i < txsToUse.length; i++){
31
+ if (txsToUse[i] === undefined) {
32
+ // We don't have the transaction, take from the proposal, provided the hash is the same
33
+ const hashOfTxInProposal = await proposal.txs[i].getTxHash();
34
+ if (hashOfTxInProposal.equals(hashesFromPayload[i])) {
35
+ // Hash is equal, we can use the tx from the proposal
36
+ txsToUse[i] = proposal.txs[i];
37
+ usedFromProposal++;
38
+ } else {
39
+ this.log.warn(`Unable to take tx: ${hashOfTxInProposal.toString()} from the proposal, it does not match payload hash: ${hashesFromPayload[i].toString()}`);
40
+ }
41
+ }
42
+ }
43
+ // See if we still have any holes, if there are then we were not successful and will try the old method
44
+ if (txsToUse.some((tx)=>tx === undefined)) {
45
+ this.log.warn(`Failed to use transactions from proposal. Falling back to old proposal logic`);
46
+ } else {
47
+ this.log.info(`Successfully used ${usedFromProposal}/${hashesFromPayload.length} transactions from the proposal`);
48
+ await this.p2pClient.validate(txsToUse);
49
+ return {
50
+ txs: txsToUse
51
+ };
52
+ }
53
+ }
54
+ this.log.info(`Using old style proposal with ${proposal.payload.txHashes.length} transactions`);
55
+ // Old style proposal, we will perform a request by hash from pool
56
+ // This will request from network any txs that are missing
57
+ const txHashes = proposal.payload.txHashes;
58
+ // This part is just for logging that we are requesting from the network
59
+ const availability = await this.p2pClient.hasTxsInPool(txHashes);
60
+ const notAvailable = availability.filter((availability)=>availability === false);
61
+ if (notAvailable.length) {
62
+ this.log.verbose(`Missing ${notAvailable.length} transactions in the tx pool, will need to request from the network`);
63
+ }
64
+ // This will request from the network any txs that are missing
65
+ // NOTE: this could still return missing txs so we need to (1) be careful to handle undefined and (2) keep the txs in the correct order for re-execution
66
+ const maybeRetrievedTxs = await this.p2pClient.getTxsByHash(txHashes, peerWhoSentTheProposal);
67
+ const missingTxs = compactArray(maybeRetrievedTxs.map((tx, index)=>tx === undefined ? txHashes[index] : undefined));
68
+ // if we found all txs, this is a noop. If we didn't find all txs then validate the ones we did find and tell the validator to skip attestations because missingTxs.length > 0
69
+ const retrievedTxs = compactArray(maybeRetrievedTxs);
70
+ await this.p2pClient.validate(retrievedTxs);
71
+ return {
72
+ txs: retrievedTxs,
73
+ missing: missingTxs
74
+ };
75
+ }
76
+ }
@@ -14,7 +14,7 @@ import type { BootnodeConfig } from '../config.js';
14
14
  import type { MemPools } from '../mem_pools/interface.js';
15
15
  import { LibP2PService } from '../services/libp2p/libp2p_service.js';
16
16
  import type { PeerScoring } from '../services/peer-manager/peer_scoring.js';
17
- import { type ReqRespSubProtocolHandlers, type ReqRespSubProtocolValidators } from '../services/reqresp/interface.js';
17
+ import { type ReqRespSubProtocolHandlers, type ReqRespSubProtocolRateLimits, type ReqRespSubProtocolValidators } from '../services/reqresp/interface.js';
18
18
  import { ReqResp } from '../services/reqresp/reqresp.js';
19
19
  /**
20
20
  * Creates a libp2p node, pre configured.
@@ -43,10 +43,10 @@ export declare const MOCK_SUB_PROTOCOL_VALIDATORS: ReqRespSubProtocolValidators;
43
43
  * @param numberOfNodes - the number of nodes to create
44
44
  * @returns An array of the created nodes
45
45
  */
46
- export declare const createNodes: (peerScoring: PeerScoring, numberOfNodes: number) => Promise<ReqRespNode[]>;
46
+ export declare const createNodes: (peerScoring: PeerScoring, numberOfNodes: number, rateLimits?: Partial<ReqRespSubProtocolRateLimits>) => Promise<ReqRespNode[]>;
47
47
  export declare const startNodes: (nodes: ReqRespNode[], subProtocolHandlers?: ReqRespSubProtocolHandlers, subProtocolValidators?: ReqRespSubProtocolValidators) => Promise<void>;
48
48
  export declare const stopNodes: (nodes: ReqRespNode[]) => Promise<void>;
49
- export declare const createReqResp: (peerScoring: PeerScoring) => Promise<ReqRespNode>;
49
+ export declare const createReqResp: (peerScoring: PeerScoring, rateLimits?: Partial<ReqRespSubProtocolRateLimits>) => Promise<ReqRespNode>;
50
50
  export declare const connectToPeers: (nodes: ReqRespNode[]) => Promise<void>;
51
51
  export declare class AlwaysTrueCircuitVerifier implements ClientProtocolCircuitVerifier {
52
52
  verifyProof(_tx: Tx): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"reqresp-nodes.d.ts","sourceRoot":"","sources":["../../src/test-helpers/reqresp-nodes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reqresp-nodes.d.ts","sourceRoot":"","sources":["../../src/test-helpers/reqresp-nodes.ts"],"names":[],"mappings":"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"}
@@ -112,8 +112,8 @@ export const MOCK_SUB_PROTOCOL_VALIDATORS = {
112
112
  /**
113
113
  * @param numberOfNodes - the number of nodes to create
114
114
  * @returns An array of the created nodes
115
- */ export const createNodes = (peerScoring, numberOfNodes)=>{
116
- return timesParallel(numberOfNodes, ()=>createReqResp(peerScoring));
115
+ */ export const createNodes = (peerScoring, numberOfNodes, rateLimits = {})=>{
116
+ return timesParallel(numberOfNodes, ()=>createReqResp(peerScoring, rateLimits));
117
117
  };
118
118
  export const startNodes = async (nodes, subProtocolHandlers = MOCK_SUB_PROTOCOL_HANDLERS, subProtocolValidators = MOCK_SUB_PROTOCOL_VALIDATORS)=>{
119
119
  for (const node of nodes){
@@ -128,13 +128,13 @@ export const stopNodes = async (nodes)=>{
128
128
  await Promise.all(stopPromises);
129
129
  };
130
130
  // Create a req resp node, exposing the underlying p2p node
131
- export const createReqResp = async (peerScoring)=>{
131
+ export const createReqResp = async (peerScoring, rateLimits = {})=>{
132
132
  const p2p = await createLibp2pNode();
133
133
  const config = {
134
134
  overallRequestTimeoutMs: 4000,
135
135
  individualRequestTimeoutMs: 2000
136
136
  };
137
- const req = new ReqResp(config, p2p, peerScoring);
137
+ const req = new ReqResp(config, p2p, peerScoring, rateLimits);
138
138
  return {
139
139
  p2p,
140
140
  req
@@ -33,7 +33,7 @@ function mockTxPool() {
33
33
  getTxStatus: ()=>Promise.resolve(TxStatus.PENDING),
34
34
  getTxsByHash: ()=>Promise.resolve([]),
35
35
  hasTxs: ()=>Promise.resolve([]),
36
- setMaxTxPoolSize: ()=>Promise.resolve(),
36
+ updateConfig: ()=>{},
37
37
  markTxsAsNonEvictable: ()=>Promise.resolve()
38
38
  };
39
39
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/p2p",
3
- "version": "0.87.5",
3
+ "version": "0.87.7",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -63,16 +63,16 @@
63
63
  ]
64
64
  },
65
65
  "dependencies": {
66
- "@aztec/constants": "0.87.5",
67
- "@aztec/epoch-cache": "0.87.5",
68
- "@aztec/foundation": "0.87.5",
69
- "@aztec/kv-store": "0.87.5",
70
- "@aztec/noir-contracts.js": "0.87.5",
71
- "@aztec/noir-protocol-circuits-types": "0.87.5",
72
- "@aztec/protocol-contracts": "0.87.5",
73
- "@aztec/simulator": "0.87.5",
74
- "@aztec/stdlib": "0.87.5",
75
- "@aztec/telemetry-client": "0.87.5",
66
+ "@aztec/constants": "0.87.7",
67
+ "@aztec/epoch-cache": "0.87.7",
68
+ "@aztec/foundation": "0.87.7",
69
+ "@aztec/kv-store": "0.87.7",
70
+ "@aztec/noir-contracts.js": "0.87.7",
71
+ "@aztec/noir-protocol-circuits-types": "0.87.7",
72
+ "@aztec/protocol-contracts": "0.87.7",
73
+ "@aztec/simulator": "0.87.7",
74
+ "@aztec/stdlib": "0.87.7",
75
+ "@aztec/telemetry-client": "0.87.7",
76
76
  "@chainsafe/discv5": "9.0.0",
77
77
  "@chainsafe/enr": "3.0.0",
78
78
  "@chainsafe/libp2p-gossipsub": "13.0.0",
@@ -101,7 +101,7 @@
101
101
  "xxhash-wasm": "^1.1.0"
102
102
  },
103
103
  "devDependencies": {
104
- "@aztec/archiver": "0.87.5",
104
+ "@aztec/archiver": "0.87.7",
105
105
  "@jest/globals": "^29.5.0",
106
106
  "@types/jest": "^29.5.0",
107
107
  "@types/node": "^22.15.17",
@@ -1,11 +1,13 @@
1
1
  import type { L2BlockId } from '@aztec/stdlib/block';
2
2
  import type { P2PApi } from '@aztec/stdlib/interfaces/server';
3
- import { BlockAttestation, type BlockProposal, type P2PClientType } from '@aztec/stdlib/p2p';
3
+ import type { BlockProposal, P2PClientType } from '@aztec/stdlib/p2p';
4
4
  import type { Tx, TxHash } from '@aztec/stdlib/tx';
5
5
 
6
6
  import type { ENR } from '@chainsafe/enr';
7
+ import type { PeerId } from '@libp2p/interface';
7
8
 
8
9
  import type { P2PConfig } from '../config.js';
10
+ import type { P2PBlockReceivedCallback } from '../services/service.js';
9
11
 
10
12
  /**
11
13
  * Enum defining the possible states of the p2p client.
@@ -50,14 +52,15 @@ export type P2P<T extends P2PClientType = P2PClientType.Full> = P2PApi<T> & {
50
52
  */
51
53
  // REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
52
54
  // ^ This pattern is not my favorite (md)
53
- registerBlockProposalHandler(handler: (block: BlockProposal) => Promise<BlockAttestation | undefined>): void;
55
+ registerBlockProposalHandler(callback: P2PBlockReceivedCallback): void;
54
56
 
55
57
  /**
56
58
  * Request a list of transactions from another peer by their tx hashes.
57
59
  * @param txHashes - Hashes of the txs to query.
60
+ * @param pinnedPeerId - An optional peer id that will be used to request the tx from (in addition to other random peers).
58
61
  * @returns A list of transactions or undefined if the transactions are not found.
59
62
  */
60
- requestTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
63
+ requestTxsByHash(txHashes: TxHash[], pinnedPeerId: PeerId): Promise<(Tx | undefined)[]>;
61
64
 
62
65
  /**
63
66
  * Request a transaction from another peer by its tx hash.
@@ -115,9 +118,10 @@ export type P2P<T extends P2PClientType = P2PClientType.Full> = P2PApi<T> & {
115
118
  /**
116
119
  * Returns transactions in the transaction pool by hash, requesting from the network if not found.
117
120
  * @param txHashes - Hashes of tx to return.
121
+ * @param pinnedPeerId - An optional peer id that will be used to request the tx from (in addition to other random peers).
118
122
  * @returns An array of tx or undefined.
119
123
  */
120
- getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
124
+ getTxsByHash(txHashes: TxHash[], pinnedPeerId: PeerId | undefined): Promise<(Tx | undefined)[]>;
121
125
 
122
126
  /**
123
127
  * Returns an archived transaction from the transaction pool by its hash.
@@ -24,6 +24,7 @@ import {
24
24
  } from '@aztec/telemetry-client';
25
25
 
26
26
  import type { ENR } from '@chainsafe/enr';
27
+ import type { PeerId } from '@libp2p/interface';
27
28
 
28
29
  import { type P2PConfig, getP2PDefaultConfig } from '../config.js';
29
30
  import type { AttestationPool } from '../mem_pools/attestation_pool/attestation_pool.js';
@@ -31,6 +32,7 @@ import type { MemPools } from '../mem_pools/interface.js';
31
32
  import type { TxPool } from '../mem_pools/tx_pool/index.js';
32
33
  import { ReqRespSubProtocol } from '../services/reqresp/interface.js';
33
34
  import type { P2PService } from '../services/service.js';
35
+ import { TxCollector } from '../services/tx_collector.js';
34
36
  import { type P2P, P2PClientState, type P2PSyncState } from './interface.js';
35
37
 
36
38
  /**
@@ -87,6 +89,15 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
87
89
  this.txPool = mempools.txPool;
88
90
  this.attestationPool = mempools.attestationPool!;
89
91
 
92
+ // Default to collecting all txs when we see a valid proposal
93
+ // This can be overridden by the validator client to attest, and it will call collectForBlockProposal on its own
94
+ const txCollector = new TxCollector(this, this.log);
95
+ this.registerBlockProposalHandler(async (block, sender) => {
96
+ this.log.debug(`Received block proposal from ${sender.toString()}`);
97
+ await txCollector.collectForBlockProposal(block, sender);
98
+ return undefined;
99
+ });
100
+
90
101
  // REFACTOR: Try replacing these with an L2TipsStore
91
102
  this.synchedBlockHashes = store.openMap('p2p_pool_block_hashes');
92
103
  this.synchedLatestBlockNumber = store.openSingleton('p2p_pool_last_l2_block');
@@ -111,11 +122,9 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
111
122
  return this.synchedBlockHashes.getAsync(number);
112
123
  }
113
124
 
114
- public async updateP2PConfig(config: Partial<P2PConfig>): Promise<void> {
115
- if (typeof config.maxTxPoolSize === 'number' && this.config.maxTxPoolSize !== config.maxTxPoolSize) {
116
- await this.txPool.setMaxTxPoolSize(config.maxTxPoolSize);
117
- this.config.maxTxPoolSize = config.maxTxPoolSize;
118
- }
125
+ public updateP2PConfig(config: Partial<P2PConfig>): Promise<void> {
126
+ this.txPool.updateConfig(config);
127
+ return Promise.resolve();
119
128
  }
120
129
 
121
130
  public async getL2Tips(): Promise<L2Tips> {
@@ -328,7 +337,9 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
328
337
 
329
338
  // REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
330
339
  // ^ This pattern is not my favorite (md)
331
- public registerBlockProposalHandler(handler: (block: BlockProposal) => Promise<BlockAttestation | undefined>): void {
340
+ public registerBlockProposalHandler(
341
+ handler: (block: BlockProposal, sender: any) => Promise<BlockAttestation | undefined>,
342
+ ): void {
332
343
  this.p2pService.registerBlockReceivedCallback(handler);
333
344
  }
334
345
 
@@ -357,7 +368,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
357
368
  /**
358
369
  * Uses the batched Request Response protocol to request a set of transactions from the network.
359
370
  */
360
- public async requestTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
371
+ public async requestTxsByHash(txHashes: TxHash[], pinnedPeerId: PeerId | undefined): Promise<(Tx | undefined)[]> {
361
372
  const timeoutMs = 8000; // Longer timeout for now
362
373
  const maxPeers = Math.min(Math.ceil(txHashes.length / 3), 10);
363
374
  const maxRetryAttempts = 10; // Keep retrying within the timeout
@@ -365,6 +376,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
365
376
  const txs = await this.p2pService.sendBatchRequest(
366
377
  ReqRespSubProtocol.TX,
367
378
  txHashes,
379
+ pinnedPeerId,
368
380
  timeoutMs,
369
381
  maxPeers,
370
382
  maxRetryAttempts,
@@ -462,7 +474,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
462
474
  * @param txHashes - Hashes of the transactions to look for.
463
475
  * @returns The txs found, or undefined if not found in the order requested.
464
476
  */
465
- async getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
477
+ async getTxsByHash(txHashes: TxHash[], pinnedPeerId: PeerId | undefined): Promise<(Tx | undefined)[]> {
466
478
  const txs = await Promise.all(txHashes.map(txHash => this.txPool.getTxByHash(txHash)));
467
479
  const missingTxHashes = txs
468
480
  .map((tx, index) => [tx, index] as const)
@@ -473,7 +485,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
473
485
  return txs as Tx[];
474
486
  }
475
487
 
476
- const missingTxs = await this.requestTxsByHash(missingTxHashes);
488
+ const missingTxs = await this.requestTxsByHash(missingTxHashes, pinnedPeerId);
477
489
  const fetchedMissingTxs = missingTxs.filter((tx): tx is Tx => !!tx);
478
490
 
479
491
  // TODO: optimize
@@ -678,7 +690,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
678
690
  `Requesting ${missingTxHashes.length} missing txs from peers for ${unprovenBlocks.length} unproven mined blocks`,
679
691
  { missingTxHashes, unprovenBlockNumbers: unprovenBlocks.map(block => block.number) },
680
692
  );
681
- await this.requestTxsByHash(missingTxHashes);
693
+ await this.requestTxsByHash(missingTxHashes, undefined);
682
694
  }
683
695
  } catch (err) {
684
696
  this.log.error(`Error requesting missing txs from unproven blocks`, err, {
package/src/config.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  type ConfigMappingsType,
3
3
  booleanConfigHelper,
4
+ floatConfigHelper,
4
5
  getConfigFromMappings,
5
6
  getDefaultConfig,
6
7
  numberConfigHelper,
@@ -196,6 +197,16 @@ export interface P2PConfig extends P2PReqRespConfig, ChainConfig {
196
197
  * The maximum cumulative tx size (in bytes) of pending txs before evicting lower priority txs.
197
198
  */
198
199
  maxTxPoolSize: number;
200
+
201
+ /**
202
+ * If the pool is full, it will still accept a few more txs until it reached maxTxPoolOverspillFactor * maxTxPoolSize. Then it will evict
203
+ */
204
+ txPoolOverflowFactor: number;
205
+
206
+ /**
207
+ * The node's seen message ID cache size
208
+ */
209
+ seenMessageCacheSize: number;
199
210
  }
200
211
 
201
212
  export const DEFAULT_P2P_PORT = 40400;
@@ -308,7 +319,7 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
308
319
  gossipsubFloodPublish: {
309
320
  env: 'P2P_GOSSIPSUB_FLOOD_PUBLISH',
310
321
  description: 'Whether to flood publish messages. - For testing purposes only',
311
- ...booleanConfigHelper(true),
322
+ ...booleanConfigHelper(false),
312
323
  },
313
324
  gossipsubMcacheLength: {
314
325
  env: 'P2P_GOSSIPSUB_MCACHE_LENGTH',
@@ -393,6 +404,16 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
393
404
  description: 'The maximum cumulative tx size of pending txs (in bytes) before evicting lower priority txs.',
394
405
  ...numberConfigHelper(100_000_000), // 100MB
395
406
  },
407
+ txPoolOverflowFactor: {
408
+ env: 'P2P_TX_POOL_OVERFLOW_FACTOR',
409
+ description: 'How much the tx pool can overflow before it starts evicting txs. Must be greater than 1',
410
+ ...floatConfigHelper(1.1), // 10% overflow
411
+ },
412
+ seenMessageCacheSize: {
413
+ env: 'P2P_SEEN_MSG_CACHE_SIZE',
414
+ description: 'The number of messages to keep in the seen message cache',
415
+ ...numberConfigHelper(100_000), // 100K
416
+ },
396
417
  ...p2pReqRespConfigMappings,
397
418
  ...chainConfigMappings,
398
419
  };
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export type { PeerId } from '@libp2p/interface';
2
+
1
3
  export * from './bootstrap/bootstrap.js';
2
4
  export * from './client/index.js';
3
5
  export * from './enr/index.js';