@aztec/p2p 3.0.0-rc.5 → 4.0.0-nightly.20260107

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 (98) hide show
  1. package/dest/client/factory.d.ts +2 -2
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +2 -3
  4. package/dest/client/p2p_client.d.ts +2 -2
  5. package/dest/client/p2p_client.d.ts.map +1 -1
  6. package/dest/client/p2p_client.js +395 -21
  7. package/dest/config.d.ts +4 -7
  8. package/dest/config.d.ts.map +1 -1
  9. package/dest/config.js +6 -9
  10. package/dest/mem_pools/instrumentation.d.ts +7 -1
  11. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  12. package/dest/mem_pools/instrumentation.js +29 -2
  13. package/dest/mem_pools/interface.d.ts +3 -4
  14. package/dest/mem_pools/interface.d.ts.map +1 -1
  15. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +28 -24
  16. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  17. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +261 -323
  18. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +18 -0
  19. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +1 -0
  20. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +56 -0
  21. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +83 -0
  22. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +1 -0
  23. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +5 -0
  24. package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts +15 -0
  25. package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.d.ts.map +1 -0
  26. package/dest/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.js +88 -0
  27. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +17 -0
  28. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
  29. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +84 -0
  30. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +19 -0
  31. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
  32. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +76 -0
  33. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +26 -0
  34. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +1 -0
  35. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +84 -0
  36. package/dest/mem_pools/tx_pool/index.d.ts +1 -2
  37. package/dest/mem_pools/tx_pool/index.d.ts.map +1 -1
  38. package/dest/mem_pools/tx_pool/index.js +0 -1
  39. package/dest/mem_pools/tx_pool/priority.d.ts +5 -1
  40. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  41. package/dest/mem_pools/tx_pool/priority.js +6 -1
  42. package/dest/mem_pools/tx_pool/tx_pool.d.ts +8 -4
  43. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  44. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  45. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  46. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +25 -20
  47. package/dest/services/libp2p/libp2p_service.d.ts +4 -4
  48. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  49. package/dest/services/libp2p/libp2p_service.js +447 -64
  50. package/dest/services/peer-manager/metrics.d.ts +6 -1
  51. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  52. package/dest/services/peer-manager/metrics.js +17 -0
  53. package/dest/services/peer-manager/peer_manager.d.ts +1 -1
  54. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  55. package/dest/services/peer-manager/peer_manager.js +385 -9
  56. package/dest/services/reqresp/protocols/tx.d.ts +2 -3
  57. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  58. package/dest/services/reqresp/reqresp.js +402 -24
  59. package/dest/services/tx_provider.d.ts +2 -1
  60. package/dest/services/tx_provider.d.ts.map +1 -1
  61. package/dest/services/tx_provider.js +11 -2
  62. package/dest/services/tx_provider_instrumentation.d.ts +5 -2
  63. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
  64. package/dest/services/tx_provider_instrumentation.js +14 -1
  65. package/dest/test-helpers/reqresp-nodes.d.ts +2 -2
  66. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  67. package/dest/testbench/p2p_client_testbench_worker.js +1 -0
  68. package/package.json +14 -14
  69. package/src/client/factory.ts +5 -10
  70. package/src/client/p2p_client.ts +12 -17
  71. package/src/config.ts +8 -14
  72. package/src/mem_pools/instrumentation.ts +33 -0
  73. package/src/mem_pools/interface.ts +2 -4
  74. package/src/mem_pools/tx_pool/README.md +255 -0
  75. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +308 -368
  76. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +71 -0
  77. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +93 -0
  78. package/src/mem_pools/tx_pool/eviction/insufficient_fee_payer_balance_rule.ts +108 -0
  79. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +104 -0
  80. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +91 -0
  81. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +106 -0
  82. package/src/mem_pools/tx_pool/index.ts +0 -1
  83. package/src/mem_pools/tx_pool/priority.ts +8 -1
  84. package/src/mem_pools/tx_pool/tx_pool.ts +8 -3
  85. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +18 -13
  86. package/src/services/libp2p/libp2p_service.ts +12 -17
  87. package/src/services/peer-manager/metrics.ts +22 -0
  88. package/src/services/peer-manager/peer_manager.ts +2 -0
  89. package/src/services/reqresp/protocols/tx.ts +1 -2
  90. package/src/services/tx_provider.ts +17 -2
  91. package/src/services/tx_provider_instrumentation.ts +19 -2
  92. package/src/test-helpers/mock-pubsub.ts +1 -1
  93. package/src/test-helpers/reqresp-nodes.ts +1 -1
  94. package/src/testbench/p2p_client_testbench_worker.ts +2 -1
  95. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +0 -81
  96. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +0 -1
  97. package/dest/mem_pools/tx_pool/memory_tx_pool.js +0 -239
  98. package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -285
@@ -26,7 +26,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
26
26
  });
27
27
 
28
28
  it('adds txs to the pool as pending', async () => {
29
- const tx1 = await mockTx();
29
+ const tx1 = await mockTx(1);
30
30
 
31
31
  await pool.addTxs([tx1]);
32
32
  const poolTx = await pool.getTxByHash(tx1.getTxHash());
@@ -37,9 +37,9 @@ export function describeTxPool(getTxPool: () => TxPool) {
37
37
  });
38
38
 
39
39
  it('emits txs-added event with new txs', async () => {
40
- const tx1 = await mockTx(); // existing and pending
41
- const tx2 = await mockTx(); // mined but not known
42
- const tx3 = await mockTx(); // brand new
40
+ const tx1 = await mockTx(1); // existing and pending
41
+ const tx2 = await mockTx(2); // mined but not known
42
+ const tx3 = await mockTx(3); // brand new
43
43
 
44
44
  await pool.addTxs([tx1]);
45
45
  await pool.markAsMined([tx2.getTxHash()], minedBlockHeader);
@@ -52,10 +52,11 @@ export function describeTxPool(getTxPool: () => TxPool) {
52
52
  await pool.addTxs([tx1, tx2, tx3]);
53
53
  expect(txsFromEvent).toBeDefined();
54
54
  expect(txsFromEvent).toHaveLength(2);
55
- expect(txsFromEvent).toEqual(expect.arrayContaining([tx2, tx3]));
55
+ const eventHashes = txsFromEvent!.map(tx => tx.getTxHash());
56
+ expect(eventHashes).toEqual(expect.arrayContaining([tx2.getTxHash(), tx3.getTxHash()]));
56
57
  });
57
58
 
58
- it('permanently deletes pending txs and soft-deletes mined txs', async () => {
59
+ it('removes txs from the pool', async () => {
59
60
  const pendingTx = await mockTx(1);
60
61
  const minedTx = await mockTx(2);
61
62
 
@@ -83,7 +84,8 @@ export function describeTxPool(getTxPool: () => TxPool) {
83
84
  await pool.addTxs([tx1, tx2]);
84
85
  await pool.markAsMined([tx1.getTxHash()], minedBlockHeader);
85
86
 
86
- await expect(pool.getTxByHash(tx1.getTxHash())).resolves.toEqual(tx1);
87
+ const retrievedTx = await pool.getTxByHash(tx1.getTxHash());
88
+ expect(retrievedTx?.getTxHash()).toEqual(tx1.getTxHash());
87
89
  await expect(pool.getTxStatus(tx1.getTxHash())).resolves.toEqual('mined');
88
90
  await expect(pool.getMinedTxHashes()).resolves.toEqual([[tx1.getTxHash(), 1]]);
89
91
  await expect(pool.getPendingTxHashes()).resolves.toEqual([tx2.getTxHash()]);
@@ -97,7 +99,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
97
99
  await pool.addTxs([tx1, tx2]);
98
100
  await pool.markAsMined([tx1.getTxHash()], minedBlockHeader);
99
101
 
100
- await pool.markMinedAsPending([tx1.getTxHash()]);
102
+ await pool.markMinedAsPending([tx1.getTxHash()], BlockNumber(1));
101
103
  await expect(pool.getMinedTxHashes()).resolves.toEqual([]);
102
104
  const pending = await pool.getPendingTxHashes();
103
105
  expect(pending).toHaveLength(2);
@@ -121,7 +123,7 @@ export function describeTxPool(getTxPool: () => TxPool) {
121
123
  );
122
124
 
123
125
  // reorg: both txs should now become available again
124
- await pool.markMinedAsPending([tx1.getTxHash(), someTxHashThatThisPeerDidNotSee]);
126
+ await pool.markMinedAsPending([tx1.getTxHash(), someTxHashThatThisPeerDidNotSee], BlockNumber(1));
125
127
  await expect(pool.getMinedTxHashes()).resolves.toEqual([]);
126
128
  await expect(pool.getPendingTxHashes()).resolves.toEqual([tx1.getTxHash()]); // tx2 is not in the pool
127
129
  await expect(pool.getPendingTxCount()).resolves.toEqual(1);
@@ -136,7 +138,8 @@ export function describeTxPool(getTxPool: () => TxPool) {
136
138
 
137
139
  const poolTxs = await pool.getAllTxs();
138
140
  expect(poolTxs).toHaveLength(3);
139
- expect(poolTxs).toEqual(expect.arrayContaining([tx1, tx2, tx3]));
141
+ const poolHashes = poolTxs.map(tx => tx.getTxHash());
142
+ expect(poolHashes).toEqual(expect.arrayContaining([tx1.getTxHash(), tx2.getTxHash(), tx3.getTxHash()]));
140
143
  await expect(pool.getPendingTxCount()).resolves.toEqual(3);
141
144
  });
142
145
 
@@ -163,17 +166,19 @@ export function describeTxPool(getTxPool: () => TxPool) {
163
166
 
164
167
  const requestedTxs = await pool.getTxsByHash([tx1.getTxHash(), tx3.getTxHash()]);
165
168
  expect(requestedTxs).toHaveLength(2);
166
- expect(requestedTxs).toEqual(expect.arrayContaining([tx1, tx3]));
169
+ const requestedHashes = requestedTxs.map(tx => tx!.getTxHash());
170
+ expect(requestedHashes).toEqual(expect.arrayContaining([tx1.getTxHash(), tx3.getTxHash()]));
167
171
  });
168
172
 
169
173
  it('returns a large number of transactions by their hash', async () => {
170
- const numTxs = 1000;
174
+ const numTxs = 1_000;
171
175
  const txs = await Promise.all(Array.from({ length: numTxs }, (_, i) => mockTx(i)));
172
176
  const hashes = txs.map(tx => tx.getTxHash());
173
177
  await pool.addTxs(txs);
174
178
  const requestedTxs = await pool.getTxsByHash(hashes);
175
179
  expect(requestedTxs).toHaveLength(numTxs);
176
- expect(requestedTxs).toEqual(expect.arrayContaining(txs));
180
+ const requestedHashes = requestedTxs.map(tx => tx!.getTxHash());
181
+ expect(requestedHashes).toEqual(expect.arrayContaining(hashes));
177
182
  });
178
183
 
179
184
  it('returns whether or not txs exist', async () => {
@@ -153,7 +153,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
153
153
  private peerDiscoveryService: PeerDiscoveryService,
154
154
  private reqresp: ReqRespInterface,
155
155
  private peerManager: PeerManagerInterface,
156
- protected mempools: MemPools<T>,
156
+ protected mempools: MemPools,
157
157
  private archiver: L2BlockSource & ContractDataSource,
158
158
  private epochCache: EpochCacheInterface,
159
159
  private proofVerifier: ClientProtocolCircuitVerifier,
@@ -185,7 +185,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
185
185
 
186
186
  // Use FishermanAttestationValidator in fisherman mode to validate attestation payloads against proposals
187
187
  this.attestationValidator = config.fishermanMode
188
- ? new FishermanAttestationValidator(epochCache, mempools.attestationPool!, telemetry)
188
+ ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
189
189
  : new AttestationValidator(epochCache);
190
190
  this.blockProposalValidator = new BlockProposalValidator(epochCache, { txsPermitted: !config.disableTransactions });
191
191
 
@@ -215,7 +215,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
215
215
  config: P2PConfig,
216
216
  peerId: PeerId,
217
217
  deps: {
218
- mempools: MemPools<T>;
218
+ mempools: MemPools;
219
219
  l2BlockSource: L2BlockSource & ContractDataSource;
220
220
  epochCache: EpochCacheInterface;
221
221
  proofVerifier: ClientProtocolCircuitVerifier;
@@ -486,8 +486,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
486
486
  [ReqRespSubProtocol.BLOCK]: blockHandler.bind(this),
487
487
  };
488
488
 
489
- // Only handle block transactions request if attestation pool is available to the client
490
- if (this.mempools.attestationPool && !this.config.disableTransactions) {
489
+ if (!this.config.disableTransactions) {
491
490
  const blockTxsHandler = reqRespBlockTxsHandler(this.mempools.attestationPool, this.mempools.txPool);
492
491
  requestResponseHandlers[ReqRespSubProtocol.BLOCK_TXS] = blockTxsHandler.bind(this);
493
492
  }
@@ -809,7 +808,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
809
808
  private async processAttestationFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
810
809
  const validationFunc: () => Promise<ReceivedMessageValidationResult<BlockAttestation>> = async () => {
811
810
  const attestation = BlockAttestation.fromBuffer(payloadData);
812
- const pool = this.mempools.attestationPool!;
811
+ const pool = this.mempools.attestationPool;
813
812
  const isValid = await this.validateAttestation(source, attestation);
814
813
  const exists = isValid && (await pool.hasAttestation(attestation));
815
814
 
@@ -866,7 +865,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
866
865
  },
867
866
  );
868
867
 
869
- await this.mempools.attestationPool!.addAttestations([attestation]);
868
+ await this.mempools.attestationPool.addAttestations([attestation]);
870
869
  }
871
870
 
872
871
  private async processBlockFromPeer(payloadData: Buffer, msgId: string, source: PeerId): Promise<void> {
@@ -875,10 +874,8 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
875
874
  const isValid = await this.validateBlockProposal(source, block);
876
875
  const pool = this.mempools.attestationPool;
877
876
 
878
- // Note that we dont have an attestation pool if we're a prover node, but we still
879
- // subscribe to block proposal topics in order to prevent their txs from being cleared.
880
- const exists = isValid && (await pool?.hasBlockProposal(block));
881
- const canAdd = isValid && (await pool?.canAddProposal(block));
877
+ const exists = isValid && (await pool.hasBlockProposal(block));
878
+ const canAdd = isValid && (await pool.canAddProposal(block));
882
879
 
883
880
  this.logger.trace(`Validate propagated block proposal`, {
884
881
  isValid,
@@ -934,14 +931,12 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
934
931
  archive: block.archive.toString(),
935
932
  source: sender.toString(),
936
933
  });
937
- const attestationsForPreviousSlot = await this.mempools.attestationPool?.getAttestationsForSlot(previousSlot);
938
- if (attestationsForPreviousSlot !== undefined) {
939
- this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
940
- }
934
+ const attestationsForPreviousSlot = await this.mempools.attestationPool.getAttestationsForSlot(previousSlot);
935
+ this.logger.verbose(`Received ${attestationsForPreviousSlot.length} attestations for slot ${previousSlot}`);
941
936
 
942
937
  // Attempt to add proposal, then mark the txs in this proposal as non-evictable
943
938
  try {
944
- await this.mempools.attestationPool?.addBlockProposal(block);
939
+ await this.mempools.attestationPool.addBlockProposal(block);
945
940
  } catch (err: unknown) {
946
941
  // Drop proposals if we hit per-slot cap in the attestation pool; rethrow unknown errors
947
942
  if (err instanceof ProposalSlotCapExceededError) {
@@ -1047,7 +1042,7 @@ export class LibP2PService<T extends P2PClientType = P2PClientType.Full> extends
1047
1042
  }
1048
1043
 
1049
1044
  // Given proposal (should have locally), ensure returned txs are valid subset and match request indices
1050
- const proposal = await this.mempools.attestationPool?.getBlockProposal(request.blockHash.toString());
1045
+ const proposal = await this.mempools.attestationPool.getBlockProposal(request.blockHash.toString());
1051
1046
  if (proposal) {
1052
1047
  // Build intersected indices
1053
1048
  const intersectIdx = request.txIndices.getTrueIndices().filter(i => response.txIndices.isSet(i));
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  Attributes,
3
3
  type Gauge,
4
+ type Histogram,
4
5
  Metrics,
5
6
  type TelemetryClient,
6
7
  type Tracer,
@@ -9,6 +10,8 @@ import {
9
10
  getTelemetryClient,
10
11
  } from '@aztec/telemetry-client';
11
12
 
13
+ import type { PeerId } from '@libp2p/interface';
14
+
12
15
  import { type GoodByeReason, prettyGoodbyeReason } from '../reqresp/protocols/index.js';
13
16
 
14
17
  export class PeerManagerMetrics {
@@ -16,6 +19,9 @@ export class PeerManagerMetrics {
16
19
  private receivedGoodbyes: UpDownCounter;
17
20
  private peerCount: Gauge;
18
21
  private lowScoreDisconnects: UpDownCounter;
22
+ private peerConnectionDuration: Histogram;
23
+
24
+ private peerConnectedAt: Map<string, number> = new Map<string, number>();
19
25
 
20
26
  public readonly tracer: Tracer;
21
27
 
@@ -46,6 +52,11 @@ export class PeerManagerMetrics {
46
52
  unit: 'peers',
47
53
  valueType: ValueType.INT,
48
54
  });
55
+ this.peerConnectionDuration = meter.createHistogram(Metrics.PEER_MANAGER_PEER_CONNECTION_DURATION, {
56
+ description: 'Time duration between peer connection and disconnection',
57
+ unit: 'ms',
58
+ valueType: ValueType.INT,
59
+ });
49
60
  }
50
61
 
51
62
  public recordGoodbyeSent(reason: GoodByeReason) {
@@ -63,4 +74,15 @@ export class PeerManagerMetrics {
63
74
  public recordLowScoreDisconnect(scoreState: 'Banned' | 'Disconnect') {
64
75
  this.lowScoreDisconnects.add(1, { [Attributes.P2P_PEER_SCORE_STATE]: scoreState });
65
76
  }
77
+
78
+ public peerConnected(id: PeerId) {
79
+ this.peerConnectedAt.set(id.toString(), Date.now());
80
+ }
81
+
82
+ public peerDisconnected(id: PeerId) {
83
+ const connectedAt = this.peerConnectedAt.get(id.toString());
84
+ if (connectedAt) {
85
+ this.peerConnectionDuration.record(Date.now() - connectedAt);
86
+ }
87
+ }
66
88
  }
@@ -278,6 +278,7 @@ export class PeerManager implements PeerManagerInterface {
278
278
  private handleConnectedPeerEvent(e: CustomEvent<PeerId>) {
279
279
  const peerId = e.detail;
280
280
  this.logger.verbose(`Connected to peer ${peerId.toString()}`);
281
+ this.metrics.peerConnected(peerId);
281
282
  if (this.config.p2pDisableStatusHandshake) {
282
283
  return;
283
284
  }
@@ -303,6 +304,7 @@ export class PeerManager implements PeerManagerInterface {
303
304
  */
304
305
  private handleDisconnectedPeerEvent(e: CustomEvent<PeerId>) {
305
306
  const peerId = e.detail;
307
+ this.metrics.peerDisconnected(peerId);
306
308
  this.logger.verbose(`Disconnected from peer ${peerId.toString()}`);
307
309
  const validatorAddress = this.authenticatedPeerIdToValidatorAddress.get(peerId.toString());
308
310
  if (validatorAddress !== undefined) {
@@ -1,5 +1,4 @@
1
1
  import { chunk } from '@aztec/foundation/collection';
2
- import type { P2PClientType } from '@aztec/stdlib/p2p';
3
2
  import { TxArray, TxHash, TxHashArray } from '@aztec/stdlib/tx';
4
3
 
5
4
  import type { PeerId } from '@libp2p/interface';
@@ -16,7 +15,7 @@ import { ReqRespStatus, ReqRespStatusError } from '../status.js';
16
15
  * @param mempools - the mempools
17
16
  * @returns the Tx request handler
18
17
  */
19
- export function reqRespTxHandler<T extends P2PClientType>(mempools: MemPools<T>): ReqRespSubProtocolHandler {
18
+ export function reqRespTxHandler(mempools: MemPools): ReqRespSubProtocolHandler {
20
19
  /**
21
20
  * Handler for tx requests
22
21
  * @param msg - the tx request message
@@ -137,6 +137,7 @@ export class TxProvider implements ITxProvider {
137
137
  );
138
138
 
139
139
  if (missingTxHashes.size === 0) {
140
+ this.instrumentation.incTxsFromP2P(0, txHashes.length);
140
141
  return { txsFromMempool };
141
142
  }
142
143
 
@@ -155,24 +156,26 @@ export class TxProvider implements ITxProvider {
155
156
 
156
157
  if (missingTxHashes.size === 0) {
157
158
  await this.processProposalTxs(txsFromProposal);
159
+ this.instrumentation.incTxsFromP2P(0, txHashes.length);
158
160
  return { txsFromMempool, txsFromProposal };
159
161
  }
160
162
 
161
163
  // Start tx collection from the network if needed, while we validate the txs taken from the proposal in parallel
162
164
  const [txsFromNetwork] = await Promise.all([
163
- this.txCollection.collectFastFor(request, [...missingTxHashes], opts),
165
+ this.collectFromP2P(request, [...missingTxHashes], opts),
164
166
  this.processProposalTxs(txsFromProposal),
165
167
  ] as const);
166
168
 
167
169
  if (txsFromNetwork.length > 0) {
168
170
  txsFromNetwork.forEach(tx => missingTxHashes.delete(tx.txHash.toString()));
169
- this.instrumentation.incTxsFromP2P(txsFromNetwork.length);
170
171
  this.log.debug(
171
172
  `Retrieved ${txsFromNetwork.length} txs from network for block proposal (${missingTxHashes.size} pending)`,
172
173
  { ...blockInfo, missingTxHashes: [...missingTxHashes] },
173
174
  );
174
175
  }
175
176
 
177
+ this.instrumentation.incTxsFromP2P(txsFromNetwork.length, txHashes.length);
178
+
176
179
  if (missingTxHashes.size === 0) {
177
180
  return { txsFromNetwork, txsFromMempool, txsFromProposal };
178
181
  }
@@ -200,6 +203,18 @@ export class TxProvider implements ITxProvider {
200
203
  };
201
204
  }
202
205
 
206
+ private async collectFromP2P(
207
+ input: FastCollectionRequestInput,
208
+ txHashes: TxHash[] | string[],
209
+ opts: { deadline: Date; pinnedPeer?: PeerId },
210
+ ): Promise<Tx[]> {
211
+ const requestedAt = Date.now();
212
+ const result = await this.txCollection.collectFastFor(input, txHashes, opts);
213
+ const requestProcessedAt = Date.now();
214
+ this.instrumentation.recordTxsRequestDelay(requestProcessedAt - requestedAt);
215
+ return result;
216
+ }
217
+
203
218
  private extractFromProposal(proposal: BlockProposal | undefined, missingTxHashes: string[]): Tx[] {
204
219
  if (!proposal) {
205
220
  return [];
@@ -1,4 +1,4 @@
1
- import { Metrics, type TelemetryClient, type UpDownCounter } from '@aztec/telemetry-client';
1
+ import { type Histogram, Metrics, type TelemetryClient, type UpDownCounter } from '@aztec/telemetry-client';
2
2
 
3
3
  export class TxProviderInstrumentation {
4
4
  private txFromProposalCount: UpDownCounter;
@@ -6,6 +6,9 @@ export class TxProviderInstrumentation {
6
6
  private txFromP2PCount: UpDownCounter;
7
7
  private missingTxsCount: UpDownCounter;
8
8
 
9
+ private fractionOfTxsRequestedFromP2P: Histogram;
10
+ private txsRequestDelay: Histogram;
11
+
9
12
  constructor(client: TelemetryClient, name: string) {
10
13
  const meter = client.getMeter(name);
11
14
 
@@ -24,6 +27,15 @@ export class TxProviderInstrumentation {
24
27
  this.missingTxsCount = meter.createUpDownCounter(Metrics.TX_PROVIDER_MISSING_TXS_COUNT, {
25
28
  description: 'The number of txs not found anywhere',
26
29
  });
30
+
31
+ this.fractionOfTxsRequestedFromP2P = meter.createHistogram(Metrics.TX_PROVIDER_P2P_TXS_REQUESTED_FRACTION, {
32
+ description: 'The fraction of transaction requested from peers',
33
+ });
34
+
35
+ this.txsRequestDelay = meter.createHistogram(Metrics.TX_PROVIDER_P2P_TXS_REQUEST_DELAY, {
36
+ unit: 'ms',
37
+ description: 'The time it took to request missing transactions from p2p',
38
+ });
27
39
  }
28
40
 
29
41
  incTxsFromProposals(count: number) {
@@ -34,8 +46,13 @@ export class TxProviderInstrumentation {
34
46
  this.txFromMempoolCount.add(count);
35
47
  }
36
48
 
37
- incTxsFromP2P(count: number) {
49
+ incTxsFromP2P(count: number, total: number) {
38
50
  this.txFromP2PCount.add(count);
51
+ this.fractionOfTxsRequestedFromP2P.record(count / total);
52
+ }
53
+
54
+ recordTxsRequestDelay(delay: number) {
55
+ this.txsRequestDelay.record(delay);
39
56
  }
40
57
 
41
58
  incMissingTxs(count: number) {
@@ -39,7 +39,7 @@ export function getMockPubSubP2PServiceFactory<T extends P2PClientType>(
39
39
  peerId: PeerId,
40
40
  deps: {
41
41
  packageVersion: string;
42
- mempools: MemPools<T>;
42
+ mempools: MemPools;
43
43
  l2BlockSource: L2BlockSource & ContractDataSource;
44
44
  epochCache: EpochCacheInterface;
45
45
  proofVerifier: ClientProtocolCircuitVerifier;
@@ -112,7 +112,7 @@ export async function createTestLibP2PService<T extends P2PClientType>(
112
112
  archiver: L2BlockSource & ContractDataSource,
113
113
  worldStateSynchronizer: WorldStateSynchronizer,
114
114
  epochCache: EpochCache,
115
- mempools: MemPools<T>,
115
+ mempools: MemPools,
116
116
  telemetry: TelemetryClient,
117
117
  port: number = 0,
118
118
  peerId?: PeerId,
@@ -56,6 +56,7 @@ function mockTxPool(): TxPool {
56
56
  hasTx: () => Promise.resolve(false),
57
57
  updateConfig: () => {},
58
58
  markTxsAsNonEvictable: () => Promise.resolve(),
59
+ clearNonEvictableTxs: () => Promise.resolve(),
59
60
  cleanupDeletedMinedTxs: () => Promise.resolve(0),
60
61
  };
61
62
  return Object.assign(new EventEmitter(), pool);
@@ -126,7 +127,7 @@ class TestLibP2PService<T extends P2PClientType = P2PClientType.Full> extends Li
126
127
  peerDiscoveryService: PeerDiscoveryService,
127
128
  reqresp: ReqResp,
128
129
  peerManager: PeerManager,
129
- mempools: MemPools<T>,
130
+ mempools: MemPools,
130
131
  archiver: L2BlockSource & ContractDataSource,
131
132
  epochCache: EpochCacheInterface,
132
133
  proofVerifier: ClientProtocolCircuitVerifier,
@@ -1,81 +0,0 @@
1
- import { BlockNumber } from '@aztec/foundation/branded-types';
2
- import type { TypedEventEmitter } from '@aztec/foundation/types';
3
- import { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
4
- import { type TelemetryClient } from '@aztec/telemetry-client';
5
- import type { TxPool, TxPoolEvents, TxPoolOptions } from './tx_pool.js';
6
- declare const InMemoryTxPool_base: new () => TypedEventEmitter<TxPoolEvents>;
7
- /**
8
- * In-memory implementation of the Transaction Pool.
9
- */
10
- export declare class InMemoryTxPool extends InMemoryTxPool_base implements TxPool {
11
- private log;
12
- /**
13
- * Our tx pool, stored as a Map in-memory, with K: tx hash and V: the transaction.
14
- */
15
- private txs;
16
- private minedTxs;
17
- private pendingTxs;
18
- private deletedMinedTxHashes;
19
- private blockToDeletedMinedTxHash;
20
- private metrics;
21
- /**
22
- * Class constructor for in-memory TxPool. Initiates our transaction pool as a JS Map.
23
- * @param log - A logger.
24
- */
25
- constructor(telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
26
- private countTx;
27
- isEmpty(): Promise<boolean>;
28
- markAsMined(txHashes: TxHash[], blockHeader: BlockHeader): Promise<void>;
29
- markMinedAsPending(txHashes: TxHash[]): Promise<void>;
30
- getPendingTxHashes(): Promise<TxHash[]>;
31
- getMinedTxHashes(): Promise<[TxHash, BlockNumber][]>;
32
- getPendingTxCount(): Promise<number>;
33
- getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | 'deleted' | undefined>;
34
- /**
35
- * Checks if a transaction exists in the pool and returns it.
36
- * @param txHash - The generated tx hash.
37
- * @returns The transaction, if found, 'undefined' otherwise.
38
- */
39
- getTxByHash(txHash: TxHash): Promise<Tx | undefined>;
40
- getTxsByHash(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
41
- hasTxs(txHashes: TxHash[]): Promise<boolean[]>;
42
- hasTx(txHash: TxHash): Promise<boolean>;
43
- getArchivedTxByHash(): Promise<Tx | undefined>;
44
- /**
45
- * Adds a list of transactions to the pool. Duplicates are ignored.
46
- * @param txs - An array of txs to be added to the pool.
47
- * @returns Empty promise.
48
- */
49
- addTxs(txs: Tx[], opts?: {
50
- source?: string;
51
- }): Promise<number>;
52
- /**
53
- * Deletes transactions from the pool. Tx hashes that are not present are ignored.
54
- * Mined transactions are soft-deleted with a timestamp, pending transactions are permanently deleted.
55
- * @param txHashes - An array of tx hashes to be deleted from the tx pool.
56
- * @returns Empty promise.
57
- */
58
- deleteTxs(txHashes: TxHash[], opts?: {
59
- permanently?: boolean;
60
- }): Promise<void>;
61
- /**
62
- * Gets all the transactions stored in the pool.
63
- * @returns Array of tx objects in the order they were added to the pool.
64
- */
65
- getAllTxs(): Promise<Tx[]>;
66
- /**
67
- * Gets the hashes of all transactions currently in the tx pool.
68
- * @returns An array of transaction hashes found in the tx pool.
69
- */
70
- getAllTxHashes(): Promise<TxHash[]>;
71
- updateConfig(_config: TxPoolOptions): void;
72
- markTxsAsNonEvictable(_: TxHash[]): Promise<void>;
73
- /**
74
- * Permanently deletes deleted mined transactions from blocks up to and including the specified block number.
75
- * @param blockNumber - Block number threshold. Deleted mined txs from this block or earlier will be permanently deleted.
76
- * @returns The number of transactions permanently deleted.
77
- */
78
- cleanupDeletedMinedTxs(blockNumber: BlockNumber): Promise<number>;
79
- }
80
- export {};
81
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5X3R4X3Bvb2wuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tZW1fcG9vbHMvdHhfcG9vbC9tZW1vcnlfdHhfcG9vbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFOUQsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUVqRSxPQUFPLEVBQUUsV0FBVyxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMzRCxPQUFPLEVBQUUsS0FBSyxlQUFlLEVBQXNCLE1BQU0seUJBQXlCLENBQUM7QUFNbkYsT0FBTyxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7O0FBRXhFOztHQUVHO0FBQ0gscUJBQWEsY0FBZSxTQUFRLG1CQUE0RCxZQUFXLE1BQU07SUFtQjdHLE9BQU8sQ0FBQyxHQUFHO0lBbEJiOztPQUVHO0lBQ0gsT0FBTyxDQUFDLEdBQUcsQ0FBa0I7SUFDN0IsT0FBTyxDQUFDLFFBQVEsQ0FBMkI7SUFDM0MsT0FBTyxDQUFDLFVBQVUsQ0FBYztJQUNoQyxPQUFPLENBQUMsb0JBQW9CLENBQTJCO0lBRXZELE9BQU8sQ0FBQyx5QkFBeUIsQ0FBZ0M7SUFFakUsT0FBTyxDQUFDLE9BQU8sQ0FBMEI7SUFFekM7OztPQUdHO0lBQ0gsWUFDRSxTQUFTLEdBQUUsZUFBc0MsRUFDekMsR0FBRyx5Q0FBOEIsRUFTMUM7SUFFRCxPQUFPLENBQUMsT0FBTyxDQU9iO0lBRUssT0FBTyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FFakM7SUFFTSxXQUFXLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxFQUFFLFdBQVcsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQW9COUU7SUFFTSxrQkFBa0IsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQWdCM0Q7SUFFWSxrQkFBa0IsSUFBSSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FXbkQ7SUFFTSxnQkFBZ0IsSUFBSSxPQUFPLENBQUMsQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUkxRDtJQUVNLGlCQUFpQixJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FHMUM7SUFFTSxXQUFXLENBQUMsTUFBTSxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsU0FBUyxHQUFHLE9BQU8sR0FBRyxTQUFTLEdBQUcsU0FBUyxDQUFDLENBYXZGO0lBRUQ7Ozs7T0FJRztJQUNJLFdBQVcsQ0FBQyxNQUFNLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxFQUFFLEdBQUcsU0FBUyxDQUFDLENBRzFEO0lBRUQsWUFBWSxDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsQ0FBQyxFQUFFLEdBQUcsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUU1RDtJQUNELE1BQU0sQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBRTdDO0lBRUssS0FBSyxDQUFDLE1BQU0sRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUc1QztJQUVNLG1CQUFtQixJQUFJLE9BQU8sQ0FBQyxFQUFFLEdBQUcsU0FBUyxDQUFDLENBRXBEO0lBRUQ7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxHQUFHLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxHQUFFO1FBQUUsTUFBTSxDQUFDLEVBQUUsTUFBTSxDQUFBO0tBQU8sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLENBd0J4RTtJQUVEOzs7OztPQUtHO0lBQ0ksU0FBUyxDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRTtRQUFFLFdBQVcsQ0FBQyxFQUFFLE9BQU8sQ0FBQTtLQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQTJCcEY7SUFFRDs7O09BR0c7SUFDSSxTQUFTLElBQUksT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBRWhDO0lBRUQ7OztPQUdHO0lBQ0ksY0FBYyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUV6QztJQUVELFlBQVksQ0FBQyxPQUFPLEVBQUUsYUFBYSxHQUFHLElBQUksQ0FBRztJQUU3QyxxQkFBcUIsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUVoRDtJQUVEOzs7O09BSUc7SUFDSSxzQkFBc0IsQ0FBQyxXQUFXLEVBQUUsV0FBVyxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0EwQnZFO0NBQ0YifQ==
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory_tx_pool.d.ts","sourceRoot":"","sources":["../../../src/mem_pools/tx_pool/memory_tx_pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAMnF,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;;AAExE;;GAEG;AACH,qBAAa,cAAe,SAAQ,mBAA4D,YAAW,MAAM;IAmB7G,OAAO,CAAC,GAAG;IAlBb;;OAEG;IACH,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,oBAAoB,CAA2B;IAEvD,OAAO,CAAC,yBAAyB,CAAgC;IAEjE,OAAO,CAAC,OAAO,CAA0B;IAEzC;;;OAGG;IACH,YACE,SAAS,GAAE,eAAsC,EACzC,GAAG,yCAA8B,EAS1C;IAED,OAAO,CAAC,OAAO,CAOb;IAEK,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAEjC;IAEM,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB9E;IAEM,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB3D;IAEY,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAWnD;IAEM,gBAAgB,IAAI,OAAO,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC,CAI1D;IAEM,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAG1C;IAEM,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC,CAavF;IAED;;;;OAIG;IACI,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC,CAG1D;IAED,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAE5D;IACD,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAE7C;IAEK,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG5C;IAEM,mBAAmB,IAAI,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC,CAEpD;IAED;;;;OAIG;IACI,MAAM,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBxE;IAED;;;;;OAKG;IACI,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BpF;IAED;;;OAGG;IACI,SAAS,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAEhC;IAED;;;OAGG;IACI,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAEzC;IAED,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAG;IAE7C,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhD;IAED;;;;OAIG;IACI,sBAAsB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BvE;CACF"}