@aztec/p2p 0.0.1-commit.88e6f9396 → 0.0.1-commit.8c0b8ff

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 (161) 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 +5 -5
  4. package/dest/client/p2p_client.d.ts +1 -1
  5. package/dest/client/p2p_client.d.ts.map +1 -1
  6. package/dest/client/p2p_client.js +4 -6
  7. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +5 -6
  8. package/dest/config.d.ts +6 -6
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +6 -6
  11. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +4 -4
  12. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  13. package/dest/mem_pools/attestation_pool/attestation_pool.js +4 -8
  14. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -6
  15. package/dest/mem_pools/instrumentation.d.ts +2 -4
  16. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  17. package/dest/mem_pools/instrumentation.js +14 -16
  18. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +5 -7
  19. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  20. package/dest/mem_pools/tx_pool_v2/interfaces.js +0 -1
  21. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +6 -5
  22. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  23. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
  24. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  25. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +43 -26
  26. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +1 -1
  27. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  28. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +0 -3
  29. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -2
  30. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  31. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +1 -18
  32. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -1
  33. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  34. package/dest/msg_validators/attestation_validator/attestation_validator.js +4 -5
  35. package/dest/msg_validators/clock_tolerance.d.ts +1 -1
  36. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  37. package/dest/msg_validators/clock_tolerance.js +3 -4
  38. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +1 -1
  39. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  40. package/dest/msg_validators/proposal_validator/proposal_validator.js +5 -5
  41. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  42. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  43. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  44. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  45. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  46. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  47. package/dest/msg_validators/tx_validator/factory.d.ts +1 -1
  48. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  49. package/dest/msg_validators/tx_validator/factory.js +8 -2
  50. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  51. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  52. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  53. package/dest/msg_validators/tx_validator/phases_validator.js +1 -1
  54. package/dest/services/libp2p/libp2p_service.d.ts +9 -2
  55. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  56. package/dest/services/libp2p/libp2p_service.js +25 -22
  57. package/dest/services/peer-manager/metrics.d.ts +1 -3
  58. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  59. package/dest/services/peer-manager/metrics.js +0 -6
  60. package/dest/services/peer-manager/peer_manager.d.ts +1 -1
  61. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  62. package/dest/services/peer-manager/peer_manager.js +3 -6
  63. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +8 -11
  64. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  65. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +101 -79
  66. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +2 -3
  67. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  68. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +4 -5
  69. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  70. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +7 -13
  71. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +11 -19
  72. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  73. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +15 -52
  74. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  75. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  76. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  77. package/dest/services/reqresp/reqresp.d.ts +1 -1
  78. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  79. package/dest/services/reqresp/reqresp.js +3 -4
  80. package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -1
  81. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  82. package/dest/services/tx_collection/fast_tx_collection.js +73 -57
  83. package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
  84. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  85. package/dest/services/tx_collection/file_store_tx_source.js +39 -29
  86. package/dest/services/tx_collection/missing_txs_tracker.d.ts +32 -0
  87. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +1 -0
  88. package/dest/services/tx_collection/missing_txs_tracker.js +27 -0
  89. package/dest/services/tx_collection/proposal_tx_collector.d.ts +7 -6
  90. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  91. package/dest/services/tx_collection/proposal_tx_collector.js +4 -4
  92. package/dest/services/tx_collection/slow_tx_collection.js +1 -1
  93. package/dest/services/tx_collection/tx_collection.d.ts +6 -3
  94. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  95. package/dest/services/tx_collection/tx_source.d.ts +6 -5
  96. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  97. package/dest/services/tx_collection/tx_source.js +9 -7
  98. package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
  99. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  100. package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
  101. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  102. package/dest/test-helpers/testbench-utils.d.ts +1 -1
  103. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  104. package/dest/test-helpers/testbench-utils.js +2 -20
  105. package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
  106. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  107. package/dest/testbench/p2p_client_testbench_worker.js +5 -6
  108. package/dest/testbench/worker_client_manager.d.ts +1 -1
  109. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  110. package/dest/testbench/worker_client_manager.js +1 -2
  111. package/dest/util.d.ts +1 -1
  112. package/package.json +14 -14
  113. package/src/client/factory.ts +8 -4
  114. package/src/client/p2p_client.ts +4 -6
  115. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +8 -7
  116. package/src/config.ts +10 -10
  117. package/src/mem_pools/attestation_pool/attestation_pool.ts +7 -8
  118. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
  119. package/src/mem_pools/instrumentation.ts +13 -17
  120. package/src/mem_pools/tx_pool_v2/interfaces.ts +4 -7
  121. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +4 -4
  122. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +43 -29
  123. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +0 -3
  124. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +1 -19
  125. package/src/msg_validators/attestation_validator/README.md +1 -1
  126. package/src/msg_validators/attestation_validator/attestation_validator.ts +4 -5
  127. package/src/msg_validators/clock_tolerance.ts +3 -4
  128. package/src/msg_validators/proposal_validator/README.md +3 -3
  129. package/src/msg_validators/proposal_validator/proposal_validator.ts +5 -6
  130. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  131. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  132. package/src/msg_validators/tx_validator/factory.ts +7 -0
  133. package/src/msg_validators/tx_validator/metadata_validator.ts +4 -12
  134. package/src/msg_validators/tx_validator/phases_validator.ts +1 -1
  135. package/src/services/libp2p/libp2p_service.ts +28 -18
  136. package/src/services/peer-manager/metrics.ts +0 -7
  137. package/src/services/peer-manager/peer_manager.ts +3 -7
  138. package/src/services/reqresp/batch-tx-requester/README.md +7 -46
  139. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +111 -75
  140. package/src/services/reqresp/batch-tx-requester/interface.ts +1 -2
  141. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +6 -13
  142. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +24 -68
  143. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  144. package/src/services/reqresp/reqresp.ts +3 -5
  145. package/src/services/tx_collection/fast_tx_collection.ts +83 -57
  146. package/src/services/tx_collection/file_store_tx_source.ts +43 -31
  147. package/src/services/tx_collection/missing_txs_tracker.ts +52 -0
  148. package/src/services/tx_collection/proposal_tx_collector.ts +13 -8
  149. package/src/services/tx_collection/slow_tx_collection.ts +1 -1
  150. package/src/services/tx_collection/tx_collection.ts +5 -3
  151. package/src/services/tx_collection/tx_source.ts +8 -7
  152. package/src/test-helpers/make-test-p2p-clients.ts +1 -1
  153. package/src/test-helpers/reqresp-nodes.ts +1 -1
  154. package/src/test-helpers/testbench-utils.ts +3 -28
  155. package/src/testbench/p2p_client_testbench_worker.ts +9 -7
  156. package/src/testbench/worker_client_manager.ts +1 -2
  157. package/src/util.ts +1 -1
  158. package/dest/services/tx_collection/request_tracker.d.ts +0 -53
  159. package/dest/services/tx_collection/request_tracker.d.ts.map +0 -1
  160. package/dest/services/tx_collection/request_tracker.js +0 -84
  161. package/src/services/tx_collection/request_tracker.ts +0 -127
@@ -0,0 +1,52 @@
1
+ import { TxHash } from '@aztec/stdlib/tx';
2
+ import type { Tx } from '@aztec/stdlib/tx';
3
+
4
+ /**
5
+ * Tracks which transactions are still missing and need to be fetched.
6
+ * Allows external code to mark transactions as fetched, enabling coordination
7
+ * between multiple fetching mechanisms (e.g., BatchTxRequester and Rpc Node requests).
8
+ */
9
+ export interface IMissingTxsTracker {
10
+ /** Returns the set of transaction hashes that are still missing. */
11
+ get missingTxHashes(): Set<string>;
12
+ /** Size of this.missingTxHashes */
13
+ get numberOfMissingTxs(): number;
14
+ /** Are all requested txs are fetched */
15
+ allFetched(): boolean;
16
+ /** Checks that transaction is still missing */
17
+ isMissing(txHash: string): boolean;
18
+ /** Marks a transaction as fetched. Returns true if it was previously missing. */
19
+ markFetched(tx: Tx): boolean;
20
+ /** Get list of collected txs */
21
+ get collectedTxs(): Tx[];
22
+ }
23
+
24
+ export class MissingTxsTracker implements IMissingTxsTracker {
25
+ public readonly collectedTxs: Tx[] = [];
26
+
27
+ private constructor(public readonly missingTxHashes: Set<string>) {}
28
+
29
+ public static fromArray(hashes: TxHash[] | string[]) {
30
+ return new MissingTxsTracker(new Set(hashes.map(hash => hash.toString())));
31
+ }
32
+
33
+ markFetched(tx: Tx): boolean {
34
+ if (this.missingTxHashes.delete(tx.txHash.toString())) {
35
+ this.collectedTxs.push(tx);
36
+ return true;
37
+ }
38
+ return false;
39
+ }
40
+
41
+ get numberOfMissingTxs(): number {
42
+ return this.missingTxHashes.size;
43
+ }
44
+
45
+ allFetched(): boolean {
46
+ return this.numberOfMissingTxs === 0;
47
+ }
48
+
49
+ isMissing(txHash: string): boolean {
50
+ return this.missingTxHashes.has(txHash.toString());
51
+ }
52
+ }
@@ -9,7 +9,7 @@ import type { BatchTxRequesterConfig } from '../reqresp/batch-tx-requester/confi
9
9
  import type { BatchTxRequesterLibP2PService } from '../reqresp/batch-tx-requester/interface.js';
10
10
  import type { IBatchRequestTxValidator } from '../reqresp/batch-tx-requester/tx_validator.js';
11
11
  import { type BlockTxsSource, ReqRespSubProtocol, chunkTxHashesRequest } from '../reqresp/index.js';
12
- import type { IRequestTracker } from './request_tracker.js';
12
+ import type { IMissingTxsTracker } from './missing_txs_tracker.js';
13
13
 
14
14
  /**
15
15
  * Strategy interface for collecting missing transactions for a block or proposal.
@@ -18,15 +18,17 @@ import type { IRequestTracker } from './request_tracker.js';
18
18
  export interface MissingTxsCollector {
19
19
  /**
20
20
  * Collect missing transactions for a block or proposal.
21
- * @param requestTracker - The missing transactions tracker
21
+ * @param missingTxsTracker - The missing transactions tracker
22
22
  * @param blockTxsSource - The block or proposal containing the transactions
23
23
  * @param pinnedPeer - Optional peer expected to have the transactions
24
+ * @param timeoutMs - Timeout in milliseconds
24
25
  * @returns The collected transactions
25
26
  */
26
27
  collectTxs(
27
- requestTracker: IRequestTracker,
28
+ missingTxsTracker: IMissingTxsTracker,
28
29
  blockTxsSource: BlockTxsSource,
29
30
  pinnedPeer: PeerId | undefined,
31
+ timeoutMs: number,
30
32
  ): Promise<Tx[]>;
31
33
  }
32
34
 
@@ -44,9 +46,10 @@ export class BatchTxRequesterCollector implements MissingTxsCollector {
44
46
  ) {}
45
47
 
46
48
  async collectTxs(
47
- requestTracker: IRequestTracker,
49
+ missingTxsTracker: IMissingTxsTracker,
48
50
  blockTxsSource: BlockTxsSource,
49
51
  pinnedPeer: PeerId | undefined,
52
+ timeoutMs: number,
50
53
  ): Promise<Tx[]> {
51
54
  const {
52
55
  batchTxRequesterSmartParallelWorkerCount: smartParallelWorkerCount,
@@ -56,9 +59,10 @@ export class BatchTxRequesterCollector implements MissingTxsCollector {
56
59
  } = this.batchTxRequesterConfig ?? {};
57
60
 
58
61
  const batchRequester = new BatchTxRequester(
59
- requestTracker,
62
+ missingTxsTracker,
60
63
  blockTxsSource,
61
64
  pinnedPeer,
65
+ timeoutMs,
62
66
  this.p2pService,
63
67
  this.log,
64
68
  this.dateProvider,
@@ -90,15 +94,16 @@ export class SendBatchRequestCollector implements MissingTxsCollector {
90
94
  ) {}
91
95
 
92
96
  async collectTxs(
93
- requestTracker: IRequestTracker,
97
+ missingTxsTracker: IMissingTxsTracker,
94
98
  _blockTxsSource: BlockTxsSource,
95
99
  pinnedPeer: PeerId | undefined,
100
+ timeoutMs: number,
96
101
  ): Promise<Tx[]> {
97
102
  const txs = await this.p2pService.reqResp.sendBatchRequest<ReqRespSubProtocol.TX>(
98
103
  ReqRespSubProtocol.TX,
99
- chunkTxHashesRequest(Array.from(requestTracker.missingTxHashes).map(TxHash.fromString)),
104
+ chunkTxHashesRequest(Array.from(missingTxsTracker.missingTxHashes).map(TxHash.fromString)),
100
105
  pinnedPeer,
101
- requestTracker.timeoutMs,
106
+ timeoutMs,
102
107
  this.maxPeers,
103
108
  this.maxRetryAttempts,
104
109
  );
@@ -196,7 +196,7 @@ export class SlowTxCollection {
196
196
  // from mined unproven blocks it has seen in the past.
197
197
  const fastRequests = this.fastCollection.getFastCollectionRequests();
198
198
  const fastCollectionTxs: Set<string> = new Set(
199
- fastRequests.values().flatMap(r => Array.from(r.requestTracker.missingTxHashes)),
199
+ fastRequests.values().flatMap(r => Array.from(r.missingTxTracker.missingTxHashes)),
200
200
  );
201
201
 
202
202
  // Return all missing txs that are not in fastCollectionTxs and are ready for reqresp if requested
@@ -1,7 +1,7 @@
1
1
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
2
  import { compactArray } from '@aztec/foundation/collection';
3
3
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
- import { RunningPromise } from '@aztec/foundation/promise';
4
+ import { type PromiseWithResolvers, RunningPromise } from '@aztec/foundation/promise';
5
5
  import { sleep } from '@aztec/foundation/sleep';
6
6
  import { DateProvider } from '@aztec/foundation/timer';
7
7
  import type { L2Block, L2BlockInfo } from '@aztec/stdlib/block';
@@ -19,7 +19,7 @@ import type { TxCollectionConfig } from './config.js';
19
19
  import { FastTxCollection } from './fast_tx_collection.js';
20
20
  import { FileStoreTxCollection } from './file_store_tx_collection.js';
21
21
  import type { FileStoreTxSource } from './file_store_tx_source.js';
22
- import type { IRequestTracker } from './request_tracker.js';
22
+ import type { IMissingTxsTracker } from './missing_txs_tracker.js';
23
23
  import { SlowTxCollection, getProofDeadlineForSlot } from './slow_tx_collection.js';
24
24
  import { type TxAddContext, TxCollectionSink } from './tx_collection_sink.js';
25
25
  import type { TxSource } from './tx_source.js';
@@ -33,8 +33,10 @@ export type FastCollectionRequestInput =
33
33
  | { type: 'proposal'; blockProposal: BlockProposal; blockNumber: BlockNumber };
34
34
 
35
35
  export type FastCollectionRequest = FastCollectionRequestInput & {
36
- requestTracker: IRequestTracker;
36
+ missingTxTracker: IMissingTxsTracker;
37
+ deadline: Date;
37
38
  blockInfo: L2BlockInfo;
39
+ promise: PromiseWithResolvers<void>;
38
40
  };
39
41
 
40
42
  /**
@@ -2,7 +2,7 @@ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
2
2
  import { protocolContractsHash } from '@aztec/protocol-contracts';
3
3
  import type { ChainConfig } from '@aztec/stdlib/config';
4
4
  import { type AztecNode, createAztecNodeClient } from '@aztec/stdlib/interfaces/client';
5
- import type { Tx, TxHash } from '@aztec/stdlib/tx';
5
+ import type { Tx, TxHash, TxValidator } from '@aztec/stdlib/tx';
6
6
  import { type ComponentsVersions, getComponentsVersionsFromConfig } from '@aztec/stdlib/versioning';
7
7
  import { makeTracedFetch } from '@aztec/telemetry-client';
8
8
 
@@ -16,12 +16,13 @@ export interface TxSource {
16
16
  export class NodeRpcTxSource implements TxSource {
17
17
  constructor(
18
18
  private readonly client: Pick<AztecNode, 'getTxsByHash'>,
19
+ private readonly txValidator: TxValidator,
19
20
  private readonly info: string,
20
21
  ) {}
21
22
 
22
- public static fromUrl(nodeUrl: string, versions: ComponentsVersions): NodeRpcTxSource {
23
+ public static fromUrl(nodeUrl: string, txValidator: TxValidator, versions: ComponentsVersions): NodeRpcTxSource {
23
24
  const client = createAztecNodeClient(nodeUrl, versions, makeTracedFetch([1, 2, 3], false));
24
- return new NodeRpcTxSource(client, nodeUrl);
25
+ return new NodeRpcTxSource(client, txValidator, nodeUrl);
25
26
  }
26
27
 
27
28
  public getInfo() {
@@ -38,8 +39,8 @@ export class NodeRpcTxSource implements TxSource {
38
39
  const invalidTxHashes: string[] = [];
39
40
  await Promise.all(
40
41
  txs.map(async tx => {
41
- const isValid = await tx.validateTxHash();
42
- if (isValid) {
42
+ const validation = await this.txValidator.validateTx(tx);
43
+ if (validation.result === 'valid') {
43
44
  validTxs.push(tx);
44
45
  } else {
45
46
  invalidTxHashes.push(tx.getTxHash().toString());
@@ -50,7 +51,7 @@ export class NodeRpcTxSource implements TxSource {
50
51
  }
51
52
  }
52
53
 
53
- export function createNodeRpcTxSources(urls: string[], chainConfig: ChainConfig) {
54
+ export function createNodeRpcTxSources(urls: string[], txValidator: TxValidator, chainConfig: ChainConfig) {
54
55
  const versions = getComponentsVersionsFromConfig(chainConfig, protocolContractsHash, getVKTreeRoot());
55
- return urls.map(url => NodeRpcTxSource.fromUrl(url, versions));
56
+ return urls.map(url => NodeRpcTxSource.fromUrl(url, txValidator, versions));
56
57
  }
@@ -4,9 +4,9 @@ import { SecretValue } from '@aztec/foundation/config';
4
4
  import { type Logger, createLogger } from '@aztec/foundation/log';
5
5
  import { retryUntil } from '@aztec/foundation/retry';
6
6
  import { sleep } from '@aztec/foundation/sleep';
7
+ import type { DataStoreConfig } from '@aztec/kv-store/config';
7
8
  import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
8
9
  import type { WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
9
- import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
10
10
 
11
11
  import { createP2PClient } from '../client/index.js';
12
12
  import type { P2PClient } from '../client/p2p_client.js';
@@ -2,6 +2,7 @@ import type { EpochCache } from '@aztec/epoch-cache';
2
2
  import { timesParallel } from '@aztec/foundation/collection';
3
3
  import { SecretValue } from '@aztec/foundation/config';
4
4
  import { createLogger } from '@aztec/foundation/log';
5
+ import type { DataStoreConfig } from '@aztec/kv-store/config';
5
6
  import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
6
7
  import type { L2BlockSource } from '@aztec/stdlib/block';
7
8
  import { type ChainConfig, emptyChainConfig } from '@aztec/stdlib/config';
@@ -11,7 +12,6 @@ import type {
11
12
  IVCProofVerificationResult,
12
13
  WorldStateSynchronizer,
13
14
  } from '@aztec/stdlib/interfaces/server';
14
- import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
15
15
  import type { Tx } from '@aztec/stdlib/tx';
16
16
  import { compressComponentVersions } from '@aztec/stdlib/versioning';
17
17
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
@@ -273,41 +273,17 @@ export class InMemoryAttestationPool {
273
273
  * Creates a mock EpochCache for testing.
274
274
  */
275
275
  export function createMockEpochCache(): EpochCacheInterface {
276
- const cache: EpochCacheInterface = {
276
+ return {
277
277
  getCommittee: () => Promise.resolve({ committee: [], seed: 1n, epoch: EpochNumber.ZERO, isEscapeHatchOpen: false }),
278
278
  getProposerIndexEncoding: () => '0x' as `0x${string}`,
279
- getSlotNow: () => SlotNumber.ZERO,
280
- getTargetSlot: () => SlotNumber.ZERO,
281
- getEpochNow: () => EpochNumber.ZERO,
282
- getTargetEpoch: () => EpochNumber.ZERO,
283
- getEpochAndSlotNow: () => ({
284
- epoch: EpochNumber.ZERO,
285
- slot: SlotNumber.ZERO,
286
- ts: 0n,
287
- nowMs: 0n,
288
- }),
289
- isProposerPipeliningEnabled: () => false,
279
+ getEpochAndSlotNow: () => ({ epoch: EpochNumber.ZERO, slot: SlotNumber.ZERO, ts: 0n, nowMs: 0n }),
290
280
  computeProposerIndex: () => 0n,
291
281
  getCurrentAndNextSlot: () => ({ currentSlot: SlotNumber.ZERO, nextSlot: SlotNumber.ZERO }),
292
- getTargetAndNextSlot: () => ({ targetSlot: SlotNumber.ZERO, nextSlot: SlotNumber.ZERO }),
293
282
  getProposerAttesterAddressInSlot: () => Promise.resolve(undefined),
294
- getEpochAndSlotInNextL1Slot: () => ({
295
- epoch: EpochNumber.ZERO,
296
- slot: SlotNumber.ZERO,
297
- ts: 0n,
298
- nowSeconds: 0n,
299
- }),
300
- getTargetEpochAndSlotInNextL1Slot: () => ({
301
- epoch: EpochNumber.ZERO,
302
- slot: SlotNumber.ZERO,
303
- ts: 0n,
304
- nowSeconds: 0n,
305
- }),
283
+ getEpochAndSlotInNextL1Slot: () => ({ epoch: EpochNumber.ZERO, slot: SlotNumber.ZERO, ts: 0n, now: 0n }),
306
284
  isInCommittee: () => Promise.resolve(false),
307
285
  getRegisteredValidators: () => Promise.resolve([]),
308
286
  filterInCommittee: () => Promise.resolve([]),
309
- isEscapeHatchOpen: () => Promise.resolve(false),
310
- isEscapeHatchOpenAtSlot: () => Promise.resolve(false),
311
287
  getL1Constants: () => ({
312
288
  l1StartBlock: 0n,
313
289
  l1GenesisTime: 0n,
@@ -319,7 +295,6 @@ export function createMockEpochCache(): EpochCacheInterface {
319
295
  rollupManaLimit: Number.MAX_SAFE_INTEGER,
320
296
  }),
321
297
  };
322
- return cache;
323
298
  }
324
299
 
325
300
  /**
@@ -4,7 +4,7 @@
4
4
  * Used when running testbench commands.
5
5
  */
6
6
  import { MockL2BlockSource } from '@aztec/archiver/test';
7
- import type { EpochCache, EpochCacheInterface } from '@aztec/epoch-cache';
7
+ import type { EpochCacheInterface } from '@aztec/epoch-cache';
8
8
  import { BlockNumber } from '@aztec/foundation/branded-types';
9
9
  import { SecretValue } from '@aztec/foundation/config';
10
10
  import { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer';
@@ -12,13 +12,13 @@ import { Fr } from '@aztec/foundation/curves/bn254';
12
12
  import { type Logger, createLogger } from '@aztec/foundation/log';
13
13
  import { sleep } from '@aztec/foundation/sleep';
14
14
  import { DateProvider, Timer } from '@aztec/foundation/timer';
15
+ import type { DataStoreConfig } from '@aztec/kv-store/config';
15
16
  import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
16
17
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
17
18
  import { protocolContractsHash } from '@aztec/protocol-contracts';
18
19
  import type { L2BlockSource } from '@aztec/stdlib/block';
19
20
  import type { ContractDataSource } from '@aztec/stdlib/contract';
20
21
  import type { ClientProtocolCircuitVerifier, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
21
- import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
22
22
  import { type BlockProposal, P2PMessage } from '@aztec/stdlib/p2p';
23
23
  import { ChonkProof } from '@aztec/stdlib/proofs';
24
24
  import { makeAztecAddress, makeBlockHeader, makeBlockProposal, mockTx } from '@aztec/stdlib/testing';
@@ -28,7 +28,6 @@ import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-clien
28
28
  import type { Message, PeerId } from '@libp2p/interface';
29
29
  import { TopicValidatorResult } from '@libp2p/interface';
30
30
  import { peerIdFromString } from '@libp2p/peer-id';
31
- import { mock } from 'jest-mock-extended';
32
31
 
33
32
  import type { P2PClient } from '../client/index.js';
34
33
  import type { P2PConfig } from '../config.js';
@@ -41,7 +40,7 @@ import type { IBatchRequestTxValidator } from '../services/reqresp/batch-tx-requ
41
40
  import { RateLimitStatus } from '../services/reqresp/rate-limiter/rate_limiter.js';
42
41
  import type { ReqResp } from '../services/reqresp/reqresp.js';
43
42
  import type { PeerDiscoveryService } from '../services/service.js';
44
- import { RequestTracker } from '../services/tx_collection/request_tracker.js';
43
+ import { MissingTxsTracker } from '../services/tx_collection/missing_txs_tracker.js';
45
44
  import { AlwaysTrueCircuitVerifier } from '../test-helpers/index.js';
46
45
  import {
47
46
  BENCHMARK_CONSTANTS,
@@ -50,6 +49,7 @@ import {
50
49
  InMemoryAttestationPool,
51
50
  InMemoryTxPool,
52
51
  UNLIMITED_RATE_LIMIT_QUOTA,
52
+ createMockEpochCache,
53
53
  createMockWorldStateSynchronizer,
54
54
  filterTxsByDistribution,
55
55
  } from '../test-helpers/index.js';
@@ -273,9 +273,10 @@ async function runAggregatorBenchmark(
273
273
  noopTxValidator,
274
274
  );
275
275
  const fetchedTxs = await collector.collectTxs(
276
- RequestTracker.create(txHashes, new Date(Date.now() + timeoutMs)),
276
+ MissingTxsTracker.fromArray(txHashes),
277
277
  blockProposal,
278
278
  pinnedPeer,
279
+ timeoutMs,
279
280
  );
280
281
  const durationMs = timer.ms();
281
282
  return {
@@ -292,9 +293,10 @@ async function runAggregatorBenchmark(
292
293
  BENCHMARK_CONSTANTS.FIXED_MAX_RETRY_ATTEMPTS,
293
294
  );
294
295
  const fetchedTxs = await collector.collectTxs(
295
- RequestTracker.create(txHashes, new Date(Date.now() + timeoutMs)),
296
+ MissingTxsTracker.fromArray(txHashes),
296
297
  blockProposal,
297
298
  pinnedPeer,
299
+ timeoutMs,
298
300
  );
299
301
  const durationMs = timer.ms();
300
302
  return {
@@ -344,7 +346,7 @@ process.on('message', async msg => {
344
346
  workerConfig = config;
345
347
  workerTxPool = new InMemoryTxPool();
346
348
  workerAttestationPool = new InMemoryAttestationPool();
347
- const epochCache = mock<EpochCache>();
349
+ const epochCache = createMockEpochCache();
348
350
  const worldState = createMockWorldStateSynchronizer();
349
351
  const l2BlockSource = new MockL2BlockSource();
350
352
 
@@ -490,8 +490,7 @@ class WorkerClientManager {
490
490
  };
491
491
 
492
492
  this.processes[0].send(aggregatorCmd);
493
- const aggregatorBudgetMs = config.timeoutMs + BENCHMARK_CONSTANTS.MAX_PEER_WAIT_MS + 30000;
494
- const result = await this.waitForBenchResult(0, aggregatorBudgetMs);
493
+ const result = await this.waitForBenchResult(0, config.timeoutMs + 30000);
495
494
 
496
495
  this.logger.info(
497
496
  `Benchmark complete: fetched=${result.fetchedCount}/${config.txCount}, duration=${result.durationMs.toFixed(0)}ms, success=${result.success}`,
package/src/util.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { SecretValue } from '@aztec/foundation/config';
2
2
  import type { Logger } from '@aztec/foundation/log';
3
3
  import type { AztecAsyncKVStore, AztecAsyncSingleton } from '@aztec/kv-store';
4
- import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
4
+ import type { DataStoreConfig } from '@aztec/kv-store/config';
5
5
 
6
6
  import type { GossipSub } from '@chainsafe/libp2p-gossipsub';
7
7
  import { generateKeyPair, marshalPrivateKey, unmarshalPrivateKey } from '@libp2p/crypto/keys';
@@ -1,53 +0,0 @@
1
- import type { DateProvider } from '@aztec/foundation/timer';
2
- import { TxHash } from '@aztec/stdlib/tx';
3
- import type { Tx } from '@aztec/stdlib/tx';
4
- /**
5
- * Tracks which transactions are still missing and need to be fetched.
6
- * Manages the request deadline and serves as the sole source of cancellation signal.
7
- * The request is cancelled when all txs are fetched or the deadline expires.
8
- */
9
- export interface IRequestTracker {
10
- /** Returns the set of transaction hashes that are still missing. */
11
- get missingTxHashes(): Set<string>;
12
- /** Size of this.missingTxHashes */
13
- get numberOfMissingTxs(): number;
14
- /** Are all requested txs fetched */
15
- allFetched(): boolean;
16
- /** Checks that transaction is still missing */
17
- isMissing(txHash: string): boolean;
18
- /** Marks a transaction as fetched. Returns true if it was previously missing. */
19
- markFetched(tx: Tx): boolean;
20
- /** Get list of collected txs */
21
- get collectedTxs(): Tx[];
22
- /** The deadline for this request. */
23
- get deadline(): Date;
24
- /** Remaining time in milliseconds until deadline. Returns 0 if already past. */
25
- get timeoutMs(): number;
26
- /** Checks whether the request is cancelled (deadline expired or all fetched). May trigger cancellation if deadline has passed. */
27
- checkCancelled(): boolean;
28
- /** Resolves when deadline expires or all txs are fetched. */
29
- get cancellationToken(): Promise<void>;
30
- /** Externally cancel the request. */
31
- cancel(): void;
32
- }
33
- export declare class RequestTracker implements IRequestTracker {
34
- readonly missingTxHashes: Set<string>;
35
- readonly deadline: Date;
36
- private readonly dateProvider?;
37
- readonly collectedTxs: Tx[];
38
- private done;
39
- private readonly cancellationTokenPromise;
40
- private readonly deadlineTimer;
41
- private constructor();
42
- static create(hashes: TxHash[] | string[], deadline: Date, dateProvider?: DateProvider): RequestTracker;
43
- markFetched(tx: Tx): boolean;
44
- get numberOfMissingTxs(): number;
45
- allFetched(): boolean;
46
- isMissing(txHash: string): boolean;
47
- get timeoutMs(): number;
48
- checkCancelled(): boolean;
49
- get cancellationToken(): Promise<void>;
50
- cancel(): void;
51
- private finish;
52
- }
53
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWVzdF90cmFja2VyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2VydmljZXMvdHhfY29sbGVjdGlvbi9yZXF1ZXN0X3RyYWNrZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDNUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzFDLE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRTNDOzs7O0dBSUc7QUFDSCxNQUFNLFdBQVcsZUFBZTtJQUM5QixvRUFBb0U7SUFDcEUsSUFBSSxlQUFlLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ25DLG1DQUFtQztJQUNuQyxJQUFJLGtCQUFrQixJQUFJLE1BQU0sQ0FBQztJQUNqQyxvQ0FBb0M7SUFDcEMsVUFBVSxJQUFJLE9BQU8sQ0FBQztJQUN0QiwrQ0FBK0M7SUFDL0MsU0FBUyxDQUFDLE1BQU0sRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDO0lBQ25DLGlGQUFpRjtJQUNqRixXQUFXLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUM7SUFDN0IsZ0NBQWdDO0lBQ2hDLElBQUksWUFBWSxJQUFJLEVBQUUsRUFBRSxDQUFDO0lBQ3pCLHFDQUFxQztJQUNyQyxJQUFJLFFBQVEsSUFBSSxJQUFJLENBQUM7SUFDckIsZ0ZBQWdGO0lBQ2hGLElBQUksU0FBUyxJQUFJLE1BQU0sQ0FBQztJQUN4QixrSUFBa0k7SUFDbEksY0FBYyxJQUFJLE9BQU8sQ0FBQztJQUMxQiw2REFBNkQ7SUFDN0QsSUFBSSxpQkFBaUIsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkMscUNBQXFDO0lBQ3JDLE1BQU0sSUFBSSxJQUFJLENBQUM7Q0FDaEI7QUFFRCxxQkFBYSxjQUFlLFlBQVcsZUFBZTthQU9sQyxlQUFlLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQzthQUM1QixRQUFRLEVBQUUsSUFBSTtJQUM5QixPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQztJQVJoQyxTQUFnQixZQUFZLEVBQUUsRUFBRSxFQUFFLENBQU07SUFDeEMsT0FBTyxDQUFDLElBQUksQ0FBUztJQUNyQixPQUFPLENBQUMsUUFBUSxDQUFDLHdCQUF3QixDQUE2QjtJQUN0RSxPQUFPLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBNEM7SUFFMUUsT0FBTyxlQW1CTjtJQUVELE9BQWMsTUFBTSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxNQUFNLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFlBQVksQ0FBQyxFQUFFLFlBQVksa0JBRTVGO0lBRUQsV0FBVyxDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQVMzQjtJQUVELElBQUksa0JBQWtCLElBQUksTUFBTSxDQUUvQjtJQUVELFVBQVUsSUFBSSxPQUFPLENBRXBCO0lBRUQsU0FBUyxDQUFDLE1BQU0sRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUVqQztJQUVELElBQUksU0FBUyxJQUFJLE1BQU0sQ0FHdEI7SUFFRCxjQUFjLElBQUksT0FBTyxDQVl4QjtJQUVELElBQUksaUJBQWlCLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUVyQztJQUVELE1BQU0sSUFBSSxJQUFJLENBRWI7SUFFRCxPQUFPLENBQUMsTUFBTTtDQVVmIn0=
@@ -1 +0,0 @@
1
- {"version":3,"file":"request_tracker.d.ts","sourceRoot":"","sources":["../../../src/services/tx_collection/request_tracker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAE3C;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,IAAI,eAAe,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,mCAAmC;IACnC,IAAI,kBAAkB,IAAI,MAAM,CAAC;IACjC,oCAAoC;IACpC,UAAU,IAAI,OAAO,CAAC;IACtB,+CAA+C;IAC/C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,iFAAiF;IACjF,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC;IAC7B,gCAAgC;IAChC,IAAI,YAAY,IAAI,EAAE,EAAE,CAAC;IACzB,qCAAqC;IACrC,IAAI,QAAQ,IAAI,IAAI,CAAC;IACrB,gFAAgF;IAChF,IAAI,SAAS,IAAI,MAAM,CAAC;IACxB,kIAAkI;IAClI,cAAc,IAAI,OAAO,CAAC;IAC1B,6DAA6D;IAC7D,IAAI,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,qCAAqC;IACrC,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,qBAAa,cAAe,YAAW,eAAe;aAOlC,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC;aAC5B,QAAQ,EAAE,IAAI;IAC9B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IARhC,SAAgB,YAAY,EAAE,EAAE,EAAE,CAAM;IACxC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA6B;IACtE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4C;IAE1E,OAAO,eAmBN;IAED,OAAc,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,CAAC,EAAE,YAAY,kBAE5F;IAED,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAS3B;IAED,IAAI,kBAAkB,IAAI,MAAM,CAE/B;IAED,UAAU,IAAI,OAAO,CAEpB;IAED,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEjC;IAED,IAAI,SAAS,IAAI,MAAM,CAGtB;IAED,cAAc,IAAI,OAAO,CAYxB;IAED,IAAI,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAErC;IAED,MAAM,IAAI,IAAI,CAEb;IAED,OAAO,CAAC,MAAM;CAUf"}
@@ -1,84 +0,0 @@
1
- import { promiseWithResolvers } from '@aztec/foundation/promise';
2
- export class RequestTracker {
3
- missingTxHashes;
4
- deadline;
5
- dateProvider;
6
- collectedTxs;
7
- done;
8
- cancellationTokenPromise;
9
- deadlineTimer;
10
- constructor(missingTxHashes, deadline, dateProvider){
11
- this.missingTxHashes = missingTxHashes;
12
- this.deadline = deadline;
13
- this.dateProvider = dateProvider;
14
- this.collectedTxs = [];
15
- this.done = false;
16
- this.cancellationTokenPromise = promiseWithResolvers();
17
- if (missingTxHashes.size === 0) {
18
- this.finish();
19
- return;
20
- }
21
- const now = this.dateProvider?.now() ?? Date.now();
22
- const remaining = deadline.getTime() - now;
23
- if (remaining <= 0) {
24
- this.finish();
25
- } else {
26
- this.deadlineTimer = setTimeout(()=>this.finish(), remaining);
27
- }
28
- }
29
- static create(hashes, deadline, dateProvider) {
30
- return new RequestTracker(new Set(hashes.map((hash)=>hash.toString())), deadline, dateProvider);
31
- }
32
- markFetched(tx) {
33
- if (this.missingTxHashes.delete(tx.txHash.toString())) {
34
- this.collectedTxs.push(tx);
35
- if (this.allFetched()) {
36
- this.finish();
37
- }
38
- return true;
39
- }
40
- return false;
41
- }
42
- get numberOfMissingTxs() {
43
- return this.missingTxHashes.size;
44
- }
45
- allFetched() {
46
- return this.numberOfMissingTxs === 0;
47
- }
48
- isMissing(txHash) {
49
- return this.missingTxHashes.has(txHash.toString());
50
- }
51
- get timeoutMs() {
52
- const now = this.dateProvider?.now() ?? Date.now();
53
- return Math.max(0, this.deadline.getTime() - now);
54
- }
55
- checkCancelled() {
56
- if (this.done) {
57
- return true;
58
- }
59
- // Synchronous fallback: check deadline even if setTimeout hasn't fired yet.
60
- // This prevents macrotask starvation in tight async loops from blocking cancellation.
61
- const now = this.dateProvider?.now() ?? Date.now();
62
- if (now >= this.deadline.getTime()) {
63
- this.finish();
64
- return true;
65
- }
66
- return false;
67
- }
68
- get cancellationToken() {
69
- return this.cancellationTokenPromise.promise;
70
- }
71
- cancel() {
72
- this.finish();
73
- }
74
- finish() {
75
- if (this.done) {
76
- return;
77
- }
78
- this.done = true;
79
- if (this.deadlineTimer) {
80
- clearTimeout(this.deadlineTimer);
81
- }
82
- this.cancellationTokenPromise.resolve();
83
- }
84
- }
@@ -1,127 +0,0 @@
1
- import { type PromiseWithResolvers, promiseWithResolvers } from '@aztec/foundation/promise';
2
- import type { DateProvider } from '@aztec/foundation/timer';
3
- import { TxHash } from '@aztec/stdlib/tx';
4
- import type { Tx } from '@aztec/stdlib/tx';
5
-
6
- /**
7
- * Tracks which transactions are still missing and need to be fetched.
8
- * Manages the request deadline and serves as the sole source of cancellation signal.
9
- * The request is cancelled when all txs are fetched or the deadline expires.
10
- */
11
- export interface IRequestTracker {
12
- /** Returns the set of transaction hashes that are still missing. */
13
- get missingTxHashes(): Set<string>;
14
- /** Size of this.missingTxHashes */
15
- get numberOfMissingTxs(): number;
16
- /** Are all requested txs fetched */
17
- allFetched(): boolean;
18
- /** Checks that transaction is still missing */
19
- isMissing(txHash: string): boolean;
20
- /** Marks a transaction as fetched. Returns true if it was previously missing. */
21
- markFetched(tx: Tx): boolean;
22
- /** Get list of collected txs */
23
- get collectedTxs(): Tx[];
24
- /** The deadline for this request. */
25
- get deadline(): Date;
26
- /** Remaining time in milliseconds until deadline. Returns 0 if already past. */
27
- get timeoutMs(): number;
28
- /** Checks whether the request is cancelled (deadline expired or all fetched). May trigger cancellation if deadline has passed. */
29
- checkCancelled(): boolean;
30
- /** Resolves when deadline expires or all txs are fetched. */
31
- get cancellationToken(): Promise<void>;
32
- /** Externally cancel the request. */
33
- cancel(): void;
34
- }
35
-
36
- export class RequestTracker implements IRequestTracker {
37
- public readonly collectedTxs: Tx[] = [];
38
- private done = false;
39
- private readonly cancellationTokenPromise: PromiseWithResolvers<void>;
40
- private readonly deadlineTimer: ReturnType<typeof setTimeout> | undefined;
41
-
42
- private constructor(
43
- public readonly missingTxHashes: Set<string>,
44
- public readonly deadline: Date,
45
- private readonly dateProvider?: DateProvider,
46
- ) {
47
- this.cancellationTokenPromise = promiseWithResolvers<void>();
48
-
49
- if (missingTxHashes.size === 0) {
50
- this.finish();
51
- return;
52
- }
53
-
54
- const now = this.dateProvider?.now() ?? Date.now();
55
- const remaining = deadline.getTime() - now;
56
- if (remaining <= 0) {
57
- this.finish();
58
- } else {
59
- this.deadlineTimer = setTimeout(() => this.finish(), remaining);
60
- }
61
- }
62
-
63
- public static create(hashes: TxHash[] | string[], deadline: Date, dateProvider?: DateProvider) {
64
- return new RequestTracker(new Set(hashes.map(hash => hash.toString())), deadline, dateProvider);
65
- }
66
-
67
- markFetched(tx: Tx): boolean {
68
- if (this.missingTxHashes.delete(tx.txHash.toString())) {
69
- this.collectedTxs.push(tx);
70
- if (this.allFetched()) {
71
- this.finish();
72
- }
73
- return true;
74
- }
75
- return false;
76
- }
77
-
78
- get numberOfMissingTxs(): number {
79
- return this.missingTxHashes.size;
80
- }
81
-
82
- allFetched(): boolean {
83
- return this.numberOfMissingTxs === 0;
84
- }
85
-
86
- isMissing(txHash: string): boolean {
87
- return this.missingTxHashes.has(txHash.toString());
88
- }
89
-
90
- get timeoutMs(): number {
91
- const now = this.dateProvider?.now() ?? Date.now();
92
- return Math.max(0, this.deadline.getTime() - now);
93
- }
94
-
95
- checkCancelled(): boolean {
96
- if (this.done) {
97
- return true;
98
- }
99
- // Synchronous fallback: check deadline even if setTimeout hasn't fired yet.
100
- // This prevents macrotask starvation in tight async loops from blocking cancellation.
101
- const now = this.dateProvider?.now() ?? Date.now();
102
- if (now >= this.deadline.getTime()) {
103
- this.finish();
104
- return true;
105
- }
106
- return false;
107
- }
108
-
109
- get cancellationToken(): Promise<void> {
110
- return this.cancellationTokenPromise.promise;
111
- }
112
-
113
- cancel(): void {
114
- this.finish();
115
- }
116
-
117
- private finish() {
118
- if (this.done) {
119
- return;
120
- }
121
- this.done = true;
122
- if (this.deadlineTimer) {
123
- clearTimeout(this.deadlineTimer);
124
- }
125
- this.cancellationTokenPromise.resolve();
126
- }
127
- }