@aztec/p2p 0.0.1-commit.e61ad554 → 0.0.1-commit.f146247c

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 (217) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +4 -3
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/bootstrap/bootstrap.js +4 -4
  4. package/dest/client/factory.d.ts +1 -1
  5. package/dest/client/factory.d.ts.map +1 -1
  6. package/dest/client/factory.js +6 -5
  7. package/dest/client/p2p_client.d.ts +1 -1
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +9 -2
  10. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts +2 -0
  11. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.d.ts.map +1 -0
  12. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +305 -0
  13. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts +73 -0
  14. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.d.ts.map +1 -0
  15. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.js +8 -0
  16. package/dest/config.d.ts +8 -2
  17. package/dest/config.d.ts.map +1 -1
  18. package/dest/config.js +2 -0
  19. package/dest/mem_pools/instrumentation.d.ts +1 -1
  20. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  21. package/dest/mem_pools/instrumentation.js +2 -2
  22. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +1 -1
  23. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -1
  24. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +7 -2
  25. package/dest/msg_validators/proposal_validator/proposal_validator.js +5 -5
  26. package/dest/msg_validators/tx_validator/archive_cache.d.ts +3 -3
  27. package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
  28. package/dest/msg_validators/tx_validator/archive_cache.js +1 -1
  29. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +5 -4
  30. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  31. package/dest/msg_validators/tx_validator/block_header_validator.js +4 -3
  32. package/dest/msg_validators/tx_validator/data_validator.d.ts +3 -1
  33. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  34. package/dest/msg_validators/tx_validator/data_validator.js +4 -1
  35. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +3 -2
  36. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  37. package/dest/msg_validators/tx_validator/double_spend_validator.js +3 -2
  38. package/dest/msg_validators/tx_validator/factory.d.ts +8 -3
  39. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  40. package/dest/msg_validators/tx_validator/factory.js +21 -11
  41. package/dest/msg_validators/tx_validator/gas_validator.d.ts +3 -2
  42. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  43. package/dest/msg_validators/tx_validator/gas_validator.js +3 -2
  44. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +3 -2
  45. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  46. package/dest/msg_validators/tx_validator/metadata_validator.js +2 -2
  47. package/dest/msg_validators/tx_validator/phases_validator.d.ts +3 -2
  48. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  49. package/dest/msg_validators/tx_validator/phases_validator.js +3 -3
  50. package/dest/msg_validators/tx_validator/size_validator.d.ts +3 -1
  51. package/dest/msg_validators/tx_validator/size_validator.d.ts.map +1 -1
  52. package/dest/msg_validators/tx_validator/size_validator.js +4 -1
  53. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +3 -2
  54. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  55. package/dest/msg_validators/tx_validator/timestamp_validator.js +2 -2
  56. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +3 -2
  57. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
  58. package/dest/msg_validators/tx_validator/tx_permitted_validator.js +2 -2
  59. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +3 -2
  60. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  61. package/dest/msg_validators/tx_validator/tx_proof_validator.js +2 -2
  62. package/dest/services/data_store.d.ts +1 -1
  63. package/dest/services/data_store.d.ts.map +1 -1
  64. package/dest/services/data_store.js +10 -6
  65. package/dest/services/discv5/discV5_service.js +1 -1
  66. package/dest/services/dummy_service.d.ts +13 -1
  67. package/dest/services/dummy_service.d.ts.map +1 -1
  68. package/dest/services/dummy_service.js +39 -0
  69. package/dest/services/libp2p/instrumentation.d.ts +1 -1
  70. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  71. package/dest/services/libp2p/instrumentation.js +14 -3
  72. package/dest/services/libp2p/libp2p_service.d.ts +9 -3
  73. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  74. package/dest/services/libp2p/libp2p_service.js +37 -28
  75. package/dest/services/peer-manager/metrics.d.ts +2 -2
  76. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  77. package/dest/services/peer-manager/metrics.js +20 -5
  78. package/dest/services/peer-manager/peer_scoring.d.ts +1 -1
  79. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  80. package/dest/services/peer-manager/peer_scoring.js +8 -2
  81. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +47 -0
  82. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -0
  83. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +566 -0
  84. package/dest/services/reqresp/batch-tx-requester/config.d.ts +17 -0
  85. package/dest/services/reqresp/batch-tx-requester/config.d.ts.map +1 -0
  86. package/dest/services/reqresp/batch-tx-requester/config.js +27 -0
  87. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +50 -0
  88. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -0
  89. package/dest/services/reqresp/batch-tx-requester/interface.js +1 -0
  90. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +37 -0
  91. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -0
  92. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +151 -0
  93. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +54 -0
  94. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -0
  95. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +139 -0
  96. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +20 -0
  97. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -0
  98. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +21 -0
  99. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +22 -3
  100. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
  101. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +63 -4
  102. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -1
  103. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  104. package/dest/services/reqresp/connection-sampler/connection_sampler.js +12 -0
  105. package/dest/services/reqresp/interface.d.ts +3 -1
  106. package/dest/services/reqresp/interface.d.ts.map +1 -1
  107. package/dest/services/reqresp/metrics.d.ts +6 -5
  108. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  109. package/dest/services/reqresp/metrics.js +17 -5
  110. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +5 -1
  111. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  112. package/dest/services/reqresp/protocols/block_txs/bitvector.js +5 -0
  113. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
  114. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  115. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +16 -3
  116. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +18 -6
  117. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  118. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +43 -13
  119. package/dest/services/reqresp/reqresp.d.ts +6 -1
  120. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  121. package/dest/services/reqresp/reqresp.js +58 -22
  122. package/dest/services/service.d.ts +4 -1
  123. package/dest/services/service.d.ts.map +1 -1
  124. package/dest/services/tx_collection/config.d.ts +4 -1
  125. package/dest/services/tx_collection/config.d.ts.map +1 -1
  126. package/dest/services/tx_collection/config.js +9 -1
  127. package/dest/services/tx_collection/fast_tx_collection.d.ts +6 -4
  128. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  129. package/dest/services/tx_collection/fast_tx_collection.js +16 -5
  130. package/dest/services/tx_collection/index.d.ts +2 -1
  131. package/dest/services/tx_collection/index.d.ts.map +1 -1
  132. package/dest/services/tx_collection/index.js +1 -0
  133. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  134. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  135. package/dest/services/tx_collection/instrumentation.js +9 -2
  136. package/dest/services/tx_collection/proposal_tx_collector.d.ts +48 -0
  137. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -0
  138. package/dest/services/tx_collection/proposal_tx_collector.js +50 -0
  139. package/dest/services/tx_collection/tx_collection.d.ts +4 -4
  140. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  141. package/dest/services/tx_collection/tx_collection.js +5 -5
  142. package/dest/services/tx_provider_instrumentation.d.ts +1 -1
  143. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
  144. package/dest/services/tx_provider_instrumentation.js +5 -5
  145. package/dest/test-helpers/index.d.ts +3 -1
  146. package/dest/test-helpers/index.d.ts.map +1 -1
  147. package/dest/test-helpers/index.js +2 -0
  148. package/dest/test-helpers/test_tx_provider.d.ts +40 -0
  149. package/dest/test-helpers/test_tx_provider.d.ts.map +1 -0
  150. package/dest/test-helpers/test_tx_provider.js +41 -0
  151. package/dest/test-helpers/testbench-utils.d.ts +158 -0
  152. package/dest/test-helpers/testbench-utils.d.ts.map +1 -0
  153. package/dest/test-helpers/testbench-utils.js +297 -0
  154. package/dest/testbench/p2p_client_testbench_worker.d.ts +28 -2
  155. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  156. package/dest/testbench/p2p_client_testbench_worker.js +212 -131
  157. package/dest/testbench/worker_client_manager.d.ts +51 -6
  158. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  159. package/dest/testbench/worker_client_manager.js +226 -44
  160. package/package.json +14 -14
  161. package/src/bootstrap/bootstrap.ts +7 -4
  162. package/src/client/factory.ts +6 -10
  163. package/src/client/p2p_client.ts +9 -2
  164. package/src/client/test/tx_proposal_collector/README.md +227 -0
  165. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +336 -0
  166. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker_protocol.ts +43 -0
  167. package/src/config.ts +6 -1
  168. package/src/mem_pools/instrumentation.ts +2 -1
  169. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +8 -2
  170. package/src/msg_validators/proposal_validator/proposal_validator.ts +5 -5
  171. package/src/msg_validators/tx_validator/archive_cache.ts +3 -3
  172. package/src/msg_validators/tx_validator/block_header_validator.ts +7 -8
  173. package/src/msg_validators/tx_validator/data_validator.ts +6 -2
  174. package/src/msg_validators/tx_validator/double_spend_validator.ts +4 -3
  175. package/src/msg_validators/tx_validator/factory.ts +64 -23
  176. package/src/msg_validators/tx_validator/gas_validator.ts +9 -3
  177. package/src/msg_validators/tx_validator/metadata_validator.ts +6 -3
  178. package/src/msg_validators/tx_validator/phases_validator.ts +5 -3
  179. package/src/msg_validators/tx_validator/size_validator.ts +6 -2
  180. package/src/msg_validators/tx_validator/timestamp_validator.ts +6 -3
  181. package/src/msg_validators/tx_validator/tx_permitted_validator.ts +8 -3
  182. package/src/msg_validators/tx_validator/tx_proof_validator.ts +8 -3
  183. package/src/services/data_store.ts +10 -7
  184. package/src/services/discv5/discV5_service.ts +1 -1
  185. package/src/services/dummy_service.ts +45 -0
  186. package/src/services/libp2p/instrumentation.ts +15 -2
  187. package/src/services/libp2p/libp2p_service.ts +60 -46
  188. package/src/services/peer-manager/metrics.ts +21 -4
  189. package/src/services/peer-manager/peer_scoring.ts +4 -1
  190. package/src/services/reqresp/batch-tx-requester/README.md +305 -0
  191. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +706 -0
  192. package/src/services/reqresp/batch-tx-requester/config.ts +40 -0
  193. package/src/services/reqresp/batch-tx-requester/interface.ts +57 -0
  194. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +209 -0
  195. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +205 -0
  196. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +37 -0
  197. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +65 -4
  198. package/src/services/reqresp/connection-sampler/connection_sampler.ts +16 -0
  199. package/src/services/reqresp/interface.ts +3 -0
  200. package/src/services/reqresp/metrics.ts +34 -9
  201. package/src/services/reqresp/protocols/block_txs/bitvector.ts +7 -0
  202. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +18 -4
  203. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +51 -9
  204. package/src/services/reqresp/reqresp.ts +66 -19
  205. package/src/services/service.ts +4 -0
  206. package/src/services/tx_collection/config.ts +15 -1
  207. package/src/services/tx_collection/fast_tx_collection.ts +36 -13
  208. package/src/services/tx_collection/index.ts +5 -0
  209. package/src/services/tx_collection/instrumentation.ts +11 -2
  210. package/src/services/tx_collection/proposal_tx_collector.ts +114 -0
  211. package/src/services/tx_collection/tx_collection.ts +4 -4
  212. package/src/services/tx_provider_instrumentation.ts +11 -5
  213. package/src/test-helpers/index.ts +2 -0
  214. package/src/test-helpers/test_tx_provider.ts +64 -0
  215. package/src/test-helpers/testbench-utils.ts +374 -0
  216. package/src/testbench/p2p_client_testbench_worker.ts +321 -122
  217. package/src/testbench/worker_client_manager.ts +304 -47
@@ -1,15 +1,19 @@
1
- import { SecretValue } from '@aztec/foundation/config';
2
1
  import { EthAddress } from '@aztec/foundation/eth-address';
3
2
  import { sleep } from '@aztec/foundation/sleep';
4
3
  import { fork } from 'child_process';
4
+ import { existsSync } from 'fs';
5
5
  import path from 'path';
6
6
  import { fileURLToPath } from 'url';
7
7
  import { getP2PDefaultConfig } from '../config.js';
8
8
  import { generatePeerIdPrivateKeys } from '../test-helpers/generate-peer-id-private-keys.js';
9
9
  import { getPorts } from '../test-helpers/get-ports.js';
10
10
  import { makeEnr, makeEnrs } from '../test-helpers/make-enrs.js';
11
+ import { BENCHMARK_CONSTANTS } from '../test-helpers/testbench-utils.js';
11
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
- const workerPath = path.join(__dirname, '../../dest/testbench/p2p_client_testbench_worker.js');
13
+ const p2pRoot = path.resolve(__dirname, '../..');
14
+ const workerTsPath = path.join(__dirname, 'p2p_client_testbench_worker.ts');
15
+ const workerJsPath = path.join(p2pRoot, 'dest/testbench/p2p_client_testbench_worker.js');
16
+ const tsconfigPath = path.join(p2pRoot, 'tsconfig.json');
13
17
  const testChainConfig = {
14
18
  l1ChainId: 31337,
15
19
  rollupVersion: 1,
@@ -22,6 +26,7 @@ class WorkerClientManager {
22
26
  peerIdPrivateKeys = [];
23
27
  peerEnrs = [];
24
28
  ports = [];
29
+ peerIds = [];
25
30
  p2pConfig;
26
31
  logger;
27
32
  messageReceivedByClient = [];
@@ -36,12 +41,15 @@ class WorkerClientManager {
36
41
  });
37
42
  }
38
43
  /**
39
- * Creates a client configuration object
44
+ * Creates a client configuration object for IPC.
45
+ * Note: We send the raw peerIdPrivateKey string instead of SecretValue
46
+ * because SecretValue.toJSON() returns '[Redacted]', losing the value.
47
+ * The worker must re-wrap it in SecretValue.
40
48
  */ createClientConfig(clientIndex, port, otherNodes) {
41
49
  return {
42
50
  ...getP2PDefaultConfig(),
43
51
  p2pEnabled: true,
44
- peerIdPrivateKey: new SecretValue(this.peerIdPrivateKeys[clientIndex]),
52
+ peerIdPrivateKey: this.peerIdPrivateKeys[clientIndex],
45
53
  listenAddress: '127.0.0.1',
46
54
  p2pIp: '127.0.0.1',
47
55
  p2pPort: port,
@@ -52,17 +60,29 @@ class WorkerClientManager {
52
60
  };
53
61
  }
54
62
  /**
55
- * Spawns a worker process and returns a promise that resolves when the worker is ready
63
+ * Spawns a worker process and returns a promise that resolves when the worker is ready.
64
+ * Config uses raw string for peerIdPrivateKey (not SecretValue) for IPC serialization.
56
65
  */ spawnWorkerProcess(config, clientIndex) {
57
- const childProcess = fork(workerPath);
58
- // Extract the raw peerIdPrivateKey value since SecretValue can't be serialized via IPC
59
- const serializedConfig = {
60
- ...config,
61
- peerIdPrivateKey: config.peerIdPrivateKey?.getValue()
66
+ const useCompiled = existsSync(workerJsPath);
67
+ const workerPath = useCompiled ? workerJsPath : workerTsPath;
68
+ const execArgv = [
69
+ ...process.execArgv
70
+ ];
71
+ if (!useCompiled && !execArgv.includes('ts-node/esm')) {
72
+ execArgv.push('--loader', 'ts-node/esm');
73
+ }
74
+ const env = {
75
+ ...process.env,
76
+ TS_NODE_PROJECT: tsconfigPath
62
77
  };
78
+ const childProcess = fork(workerPath, {
79
+ cwd: p2pRoot,
80
+ execArgv,
81
+ env
82
+ });
63
83
  childProcess.send({
64
84
  type: 'START',
65
- config: serializedConfig,
85
+ config,
66
86
  clientIndex
67
87
  });
68
88
  // Handle unexpected child process exit
@@ -78,29 +98,54 @@ class WorkerClientManager {
78
98
  });
79
99
  // Create ready signal promise
80
100
  const readySignal = new Promise((resolve, reject)=>{
81
- // Set a timeout to avoid hanging indefinitely
101
+ let resolved = false;
82
102
  const timeout = setTimeout(()=>{
103
+ if (resolved) {
104
+ return;
105
+ }
106
+ resolved = true;
107
+ childProcess.off('message', messageHandler);
108
+ childProcess.off('exit', exitHandler);
83
109
  reject(new Error(`Timeout waiting for worker ${clientIndex} to be ready`));
84
- }, 30000); // 30 second timeout
85
- childProcess.once('message', (msg)=>{
86
- clearTimeout(timeout);
110
+ }, BENCHMARK_CONSTANTS.WORKER_READY_TIMEOUT_MS);
111
+ const messageHandler = (msg)=>{
112
+ if (resolved) {
113
+ return;
114
+ }
115
+ // Only handle READY or ERROR messages; ignore others (e.g., GOSSIP_RECEIVED)
87
116
  if (msg.type === 'READY') {
117
+ resolved = true;
118
+ clearTimeout(timeout);
119
+ childProcess.off('message', messageHandler);
120
+ childProcess.off('exit', exitHandler);
121
+ if (typeof msg.peerId === 'string') {
122
+ this.peerIds[clientIndex] = msg.peerId;
123
+ }
88
124
  resolve();
89
- }
90
- // For future use
91
- if (msg.type === 'ERROR') {
125
+ } else if (msg.type === 'ERROR') {
126
+ resolved = true;
127
+ clearTimeout(timeout);
128
+ childProcess.off('message', messageHandler);
129
+ childProcess.off('exit', exitHandler);
92
130
  reject(new Error(msg.error));
93
131
  }
94
- });
95
- // Also resolve/reject if process exits before sending message
96
- childProcess.once('exit', (code)=>{
132
+ // Ignore other message types and keep waiting for READY/ERROR
133
+ };
134
+ const exitHandler = (code)=>{
135
+ if (resolved) {
136
+ return;
137
+ }
138
+ resolved = true;
97
139
  clearTimeout(timeout);
140
+ childProcess.off('message', messageHandler);
98
141
  if (code === 0) {
99
142
  resolve();
100
143
  } else {
101
144
  reject(new Error(`Worker ${clientIndex} exited with code ${code} before becoming ready`));
102
145
  }
103
- });
146
+ };
147
+ childProcess.on('message', messageHandler);
148
+ childProcess.once('exit', exitHandler);
104
149
  });
105
150
  return [
106
151
  childProcess,
@@ -108,34 +153,46 @@ class WorkerClientManager {
108
153
  ];
109
154
  }
110
155
  /**
111
- * Creates a number of worker clients in separate processes
112
- * All are configured to connect to each other and overrided with the test specific config
156
+ * Creates a number of worker clients in separate processes.
157
+ * All are configured to connect to each other and overridden with the test-specific config.
113
158
  *
114
159
  * @param numberOfClients - The number of clients to create
160
+ * @param options - Optional overrides for seeding/bootstrapping strategy
115
161
  * @returns The ENRs of the created clients
116
- */ async makeWorkerClients(numberOfClients) {
162
+ */ async makeWorkerClients(numberOfClients, options = {}) {
117
163
  try {
164
+ const bootstrapMode = options.bootstrapMode ?? (this.p2pConfig.bootstrapNodesAsFullPeers ? 'all' : 'subset');
165
+ const seedPeerLimit = options.seedPeerLimit ?? 10;
166
+ const batchSize = options.batchSize ?? (bootstrapMode === 'all' ? Math.min(5, numberOfClients) : numberOfClients);
167
+ const batchDelayMs = options.batchDelayMs ?? (bootstrapMode === 'all' ? 500 : 0);
118
168
  this.messageReceivedByClient = new Array(numberOfClients).fill(0);
119
169
  this.peerIdPrivateKeys = generatePeerIdPrivateKeys(numberOfClients);
120
170
  this.ports = await getPorts(numberOfClients);
121
171
  this.peerEnrs = await makeEnrs(this.peerIdPrivateKeys, this.ports, testChainConfig);
172
+ this.peerIds = new Array(numberOfClients);
122
173
  this.processes = [];
123
174
  const readySignals = [];
124
- for(let i = 0; i < numberOfClients; i++){
125
- this.logger.info(`Creating client ${i}`);
126
- // Maximum seed with 10 other peers to allow peer discovery to connect them at a smoother rate
127
- const otherNodes = this.peerEnrs.filter((_, ind)=>ind < Math.min(i, 10));
128
- const config = this.createClientConfig(i, this.ports[i], otherNodes);
129
- const [childProcess, readySignal] = this.spawnWorkerProcess(config, i);
130
- readySignals.push(readySignal);
131
- this.processes.push(childProcess);
175
+ for(let batchStart = 0; batchStart < numberOfClients; batchStart += batchSize){
176
+ const batchEnd = Math.min(batchStart + batchSize, numberOfClients);
177
+ const batchPromises = [];
178
+ for(let i = batchStart; i < batchEnd; i++){
179
+ this.logger.info(`Creating client ${i}`);
180
+ const otherNodes = bootstrapMode === 'all' ? this.peerEnrs.filter((_, ind)=>ind !== i) : this.peerEnrs.filter((_, ind)=>ind < Math.min(i, seedPeerLimit));
181
+ const config = this.createClientConfig(i, this.ports[i], otherNodes);
182
+ const [childProcess, readySignal] = this.spawnWorkerProcess(config, i);
183
+ readySignals.push(readySignal);
184
+ batchPromises.push(readySignal);
185
+ this.processes.push(childProcess);
186
+ }
187
+ await Promise.all(batchPromises);
188
+ if (batchEnd < numberOfClients && batchDelayMs > 0) {
189
+ await sleep(batchDelayMs);
190
+ }
132
191
  }
133
- // Wait for peers to all connect with each other
134
- await sleep(10000);
135
- // Wait for all peers to be booted up with timeout
192
+ await sleep(BENCHMARK_CONSTANTS.PEER_DISCOVERY_WAIT_MS);
136
193
  await Promise.race([
137
194
  Promise.all(readySignals),
138
- new Promise((_, reject)=>setTimeout(()=>reject(new Error('Timeout waiting for all workers to be ready')), 30000))
195
+ new Promise((_, reject)=>setTimeout(()=>reject(new Error('Timeout waiting for all workers to be ready')), BENCHMARK_CONSTANTS.WORKER_READY_TIMEOUT_MS))
139
196
  ]);
140
197
  return this.peerEnrs;
141
198
  } catch (error) {
@@ -177,10 +234,9 @@ class WorkerClientManager {
177
234
  const config = this.createClientConfig(clientIndex, newPort, otherNodes);
178
235
  const [childProcess, readySignal] = this.spawnWorkerProcess(config, clientIndex);
179
236
  this.processes[clientIndex] = childProcess;
180
- // Wait for the process to be ready with a timeout
181
237
  await Promise.race([
182
238
  readySignal,
183
- new Promise((_, reject)=>setTimeout(()=>reject(new Error(`Timeout waiting for client ${clientIndex} to be ready`)), 30000))
239
+ new Promise((_, reject)=>setTimeout(()=>reject(new Error(`Timeout waiting for client ${clientIndex} to be ready`)), BENCHMARK_CONSTANTS.WORKER_READY_TIMEOUT_MS))
184
240
  ]);
185
241
  } catch (error) {
186
242
  this.logger.error(`Error during changePort for client ${clientIndex}:`, error);
@@ -196,15 +252,14 @@ class WorkerClientManager {
196
252
  return Promise.resolve();
197
253
  }
198
254
  return new Promise((resolve)=>{
199
- // Set a timeout for the graceful exit
200
255
  const forceKillTimeout = setTimeout(()=>{
201
256
  this.logger.warn(`Process ${index} didn't exit gracefully, force killing...`);
202
257
  try {
203
- process1.kill('SIGKILL'); // Force kill
258
+ process1.kill('SIGKILL');
204
259
  } catch (e) {
205
260
  this.logger.error(`Error force killing process ${index}:`, e);
206
261
  }
207
- }, 5000); // 5 second timeout for graceful exit
262
+ }, BENCHMARK_CONSTANTS.GRACEFUL_SHUTDOWN_TIMEOUT_MS);
208
263
  // Listen for process exit
209
264
  process1.once('exit', ()=>{
210
265
  clearTimeout(forceKillTimeout);
@@ -233,7 +288,6 @@ class WorkerClientManager {
233
288
  this.logger.info(`Cleaning up ${this.processes.length} worker processes`);
234
289
  // Create array of promises for each process termination
235
290
  const terminationPromises = this.processes.map((process1, index)=>this.terminateProcess(process1, index));
236
- // Wait for all processes to terminate with a timeout
237
291
  try {
238
292
  await Promise.race([
239
293
  Promise.all(terminationPromises),
@@ -250,14 +304,142 @@ class WorkerClientManager {
250
304
  }
251
305
  });
252
306
  resolve();
253
- }, 10000); // 10 second timeout for all processes
307
+ }, BENCHMARK_CONSTANTS.CLEANUP_TIMEOUT_MS);
254
308
  })
255
309
  ]);
256
310
  } catch (error) {
257
311
  this.logger.error('Error during cleanup:', error);
258
312
  }
259
313
  this.processes = [];
314
+ this.peerIds = [];
260
315
  this.logger.info('All worker processes cleaned up');
261
316
  }
317
+ /**
318
+ * Run a req/resp benchmark across all worker clients.
319
+ *
320
+ * This sends a BENCH_REQRESP command to all workers:
321
+ * - Aggregator (client 0) runs the collector and returns timing results
322
+ * - Responders (clients 1..N) populate their tx pools based on distribution
323
+ *
324
+ * All workers generate the same txs deterministically from a shared seed,
325
+ * then filter based on their peerIndex and distribution pattern.
326
+ */ async runReqRespBenchmark(config) {
327
+ const peerCount = this.processes.length;
328
+ if (peerCount < 2) {
329
+ throw new Error('Need at least 2 peers to run req/resp benchmark');
330
+ }
331
+ const seed = config.seed ?? Date.now();
332
+ const blockNumber = config.blockNumber ?? 1;
333
+ const pinnedPeerId = config.pinnedPeerIndex !== undefined ? this.peerIds[config.pinnedPeerIndex] : undefined;
334
+ this.logger.info(`Starting req/resp benchmark: txCount=${config.txCount}, distribution=${config.distribution}, collector=${config.collectorType}`);
335
+ const readyPromises = [];
336
+ for(let i = 1; i < peerCount; i++){
337
+ const cmd = {
338
+ type: 'BENCH_REQRESP',
339
+ txCount: config.txCount,
340
+ peerCount,
341
+ distribution: config.distribution,
342
+ collectorType: config.collectorType,
343
+ timeoutMs: config.timeoutMs,
344
+ isAggregator: false,
345
+ peerIndex: i,
346
+ pinnedPeerIndex: config.pinnedPeerIndex,
347
+ pinnedPeerId,
348
+ blockNumber,
349
+ seed
350
+ };
351
+ this.processes[i].send(cmd);
352
+ readyPromises.push(this.waitForBenchReady(i, 30000));
353
+ }
354
+ await Promise.all(readyPromises);
355
+ this.logger.info('All responder peers ready, starting aggregator benchmark...');
356
+ const aggregatorCmd = {
357
+ type: 'BENCH_REQRESP',
358
+ txCount: config.txCount,
359
+ peerCount,
360
+ distribution: config.distribution,
361
+ collectorType: config.collectorType,
362
+ timeoutMs: config.timeoutMs,
363
+ isAggregator: true,
364
+ peerIndex: 0,
365
+ pinnedPeerIndex: config.pinnedPeerIndex,
366
+ pinnedPeerId,
367
+ blockNumber,
368
+ seed
369
+ };
370
+ this.processes[0].send(aggregatorCmd);
371
+ const result = await this.waitForBenchResult(0, config.timeoutMs + 30000);
372
+ this.logger.info(`Benchmark complete: fetched=${result.fetchedCount}/${config.txCount}, duration=${result.durationMs.toFixed(0)}ms, success=${result.success}`);
373
+ return {
374
+ txCount: config.txCount,
375
+ distribution: config.distribution,
376
+ collector: config.collectorType,
377
+ durationMs: result.durationMs,
378
+ fetchedCount: result.fetchedCount,
379
+ success: result.success,
380
+ error: result.error
381
+ };
382
+ }
383
+ waitForBenchReady(clientIndex, timeoutMs) {
384
+ return new Promise((resolve, reject)=>{
385
+ let resolved = false;
386
+ const handler = (msg)=>{
387
+ if (resolved) {
388
+ return;
389
+ }
390
+ if (msg.type === 'BENCH_READY') {
391
+ resolved = true;
392
+ clearTimeout(timeout);
393
+ this.processes[clientIndex].off('message', handler);
394
+ resolve();
395
+ } else if (msg.type === 'ERROR') {
396
+ resolved = true;
397
+ clearTimeout(timeout);
398
+ this.processes[clientIndex].off('message', handler);
399
+ reject(new Error(`Client ${clientIndex} error: ${msg.error}`));
400
+ }
401
+ };
402
+ const timeout = setTimeout(()=>{
403
+ if (resolved) {
404
+ return;
405
+ }
406
+ resolved = true;
407
+ this.processes[clientIndex].off('message', handler);
408
+ reject(new Error(`Timeout waiting for BENCH_READY from client ${clientIndex}`));
409
+ }, timeoutMs);
410
+ this.processes[clientIndex].on('message', handler);
411
+ });
412
+ }
413
+ waitForBenchResult(clientIndex, timeoutMs) {
414
+ return new Promise((resolve, reject)=>{
415
+ let resolved = false;
416
+ const handler = (msg)=>{
417
+ if (resolved) {
418
+ return;
419
+ }
420
+ if (msg.type === 'BENCH_RESULT') {
421
+ resolved = true;
422
+ clearTimeout(timeout);
423
+ this.processes[clientIndex].off('message', handler);
424
+ resolve(msg);
425
+ } else if (msg.type === 'ERROR') {
426
+ resolved = true;
427
+ clearTimeout(timeout);
428
+ this.processes[clientIndex].off('message', handler);
429
+ reject(new Error(`Client ${clientIndex} error: ${msg.error}`));
430
+ }
431
+ };
432
+ const timeout = setTimeout(()=>{
433
+ if (resolved) {
434
+ return;
435
+ }
436
+ resolved = true;
437
+ this.processes[clientIndex].off('message', handler);
438
+ reject(new Error(`Timeout waiting for BENCH_RESULT from client ${clientIndex}`));
439
+ }, timeoutMs);
440
+ this.processes[clientIndex].on('message', handler);
441
+ });
442
+ }
262
443
  }
263
444
  export { WorkerClientManager, testChainConfig };
445
+ export { COLLECTOR_DISPLAY_NAMES } from './p2p_client_testbench_worker.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/p2p",
3
- "version": "0.0.1-commit.e61ad554",
3
+ "version": "0.0.1-commit.f146247c",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -67,17 +67,17 @@
67
67
  ]
68
68
  },
69
69
  "dependencies": {
70
- "@aztec/constants": "0.0.1-commit.e61ad554",
71
- "@aztec/epoch-cache": "0.0.1-commit.e61ad554",
72
- "@aztec/ethereum": "0.0.1-commit.e61ad554",
73
- "@aztec/foundation": "0.0.1-commit.e61ad554",
74
- "@aztec/kv-store": "0.0.1-commit.e61ad554",
75
- "@aztec/noir-contracts.js": "0.0.1-commit.e61ad554",
76
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.e61ad554",
77
- "@aztec/protocol-contracts": "0.0.1-commit.e61ad554",
78
- "@aztec/simulator": "0.0.1-commit.e61ad554",
79
- "@aztec/stdlib": "0.0.1-commit.e61ad554",
80
- "@aztec/telemetry-client": "0.0.1-commit.e61ad554",
70
+ "@aztec/constants": "0.0.1-commit.f146247c",
71
+ "@aztec/epoch-cache": "0.0.1-commit.f146247c",
72
+ "@aztec/ethereum": "0.0.1-commit.f146247c",
73
+ "@aztec/foundation": "0.0.1-commit.f146247c",
74
+ "@aztec/kv-store": "0.0.1-commit.f146247c",
75
+ "@aztec/noir-contracts.js": "0.0.1-commit.f146247c",
76
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.f146247c",
77
+ "@aztec/protocol-contracts": "0.0.1-commit.f146247c",
78
+ "@aztec/simulator": "0.0.1-commit.f146247c",
79
+ "@aztec/stdlib": "0.0.1-commit.f146247c",
80
+ "@aztec/telemetry-client": "0.0.1-commit.f146247c",
81
81
  "@chainsafe/libp2p-gossipsub": "13.0.0",
82
82
  "@chainsafe/libp2p-noise": "^15.0.0",
83
83
  "@chainsafe/libp2p-yamux": "^6.0.2",
@@ -104,8 +104,8 @@
104
104
  "xxhash-wasm": "^1.1.0"
105
105
  },
106
106
  "devDependencies": {
107
- "@aztec/archiver": "0.0.1-commit.e61ad554",
108
- "@aztec/world-state": "0.0.1-commit.e61ad554",
107
+ "@aztec/archiver": "0.0.1-commit.f146247c",
108
+ "@aztec/world-state": "0.0.1-commit.f146247c",
109
109
  "@jest/globals": "^30.0.0",
110
110
  "@types/jest": "^30.0.0",
111
111
  "@types/node": "^22.15.17",
@@ -1,4 +1,4 @@
1
- import { createLogger } from '@aztec/foundation/log';
1
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
2
2
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
3
3
  import type { P2PBootstrapApi } from '@aztec/stdlib/interfaces/server';
4
4
  import { OtelMetricsAdapter, type TelemetryClient } from '@aztec/telemetry-client';
@@ -18,12 +18,15 @@ import { convertToMultiaddr, getPeerIdPrivateKey, getPublicIp } from '../util.js
18
18
  export class BootstrapNode implements P2PBootstrapApi {
19
19
  private node?: Discv5EventEmitter = undefined;
20
20
  private peerId?: PeerId;
21
+ private logger: Logger;
21
22
 
22
23
  constructor(
23
24
  private store: AztecAsyncKVStore,
24
25
  private telemetry: TelemetryClient,
25
- private logger = createLogger('p2p:bootstrap'),
26
- ) {}
26
+ bindings?: LoggerBindings,
27
+ ) {
28
+ this.logger = createLogger('p2p:bootstrap', bindings);
29
+ }
27
30
 
28
31
  /**
29
32
  * Starts the bootstrap node.
@@ -65,7 +68,7 @@ export class BootstrapNode implements P2PBootstrapApi {
65
68
 
66
69
  this.logger.debug(`Starting bootstrap node ${peerId} listening on ${listenAddrUdp.toString()}`);
67
70
 
68
- const metricsRegistry = new OtelMetricsAdapter(this.telemetry);
71
+ const metricsRegistry = new OtelMetricsAdapter(this.telemetry, this.logger.getBindings());
69
72
  this.node = Discv5.create({
70
73
  enr: ourEnr,
71
74
  peerId,
@@ -62,15 +62,11 @@ export async function createP2PClient<T extends P2PClientType>(
62
62
  );
63
63
  }
64
64
 
65
- const store = deps.store ?? (await createStore(P2P_STORE_NAME, 2, config, createLogger('p2p:lmdb-v2')));
66
- const archive = await createStore(P2P_ARCHIVE_STORE_NAME, 1, config, createLogger('p2p-archive:lmdb-v2'));
67
- const peerStore = await createStore(P2P_PEER_STORE_NAME, 1, config, createLogger('p2p-peer:lmdb-v2'));
68
- const attestationStore = await createStore(
69
- P2P_ATTESTATION_STORE_NAME,
70
- 1,
71
- config,
72
- createLogger('p2p-attestation:lmdb-v2'),
73
- );
65
+ const bindings = logger.getBindings();
66
+ const store = deps.store ?? (await createStore(P2P_STORE_NAME, 2, config, bindings));
67
+ const archive = await createStore(P2P_ARCHIVE_STORE_NAME, 1, config, bindings);
68
+ const peerStore = await createStore(P2P_PEER_STORE_NAME, 1, config, bindings);
69
+ const attestationStore = await createStore(P2P_ATTESTATION_STORE_NAME, 1, config, bindings);
74
70
  const l1Constants = await archiver.getL1Constants();
75
71
 
76
72
  const mempools: MemPools = {
@@ -110,7 +106,7 @@ export async function createP2PClient<T extends P2PClientType>(
110
106
  }
111
107
 
112
108
  const txCollection = new TxCollection(
113
- p2pService,
109
+ p2pService.getBatchTxRequesterService(),
114
110
  nodeSources,
115
111
  l1Constants,
116
112
  mempools.txPool,
@@ -326,8 +326,10 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
326
326
  [Attributes.BLOCK_ARCHIVE]: proposal.archive.toString(),
327
327
  [Attributes.P2P_ID]: (await proposal.p2pMessageLoggingIdentifier()).toString(),
328
328
  }))
329
- public broadcastProposal(proposal: BlockProposal): Promise<void> {
329
+ public async broadcastProposal(proposal: BlockProposal): Promise<void> {
330
330
  this.log.verbose(`Broadcasting proposal for slot ${proposal.slotNumber} to peers`);
331
+ // Store our own proposal so we can respond to req/resp requests for it
332
+ await this.attestationPool.addBlockProposal(proposal);
331
333
  return this.p2pService.propagate(proposal);
332
334
  }
333
335
 
@@ -336,8 +338,13 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
336
338
  [Attributes.BLOCK_ARCHIVE]: proposal.archive.toString(),
337
339
  [Attributes.P2P_ID]: (await proposal.p2pMessageLoggingIdentifier()).toString(),
338
340
  }))
339
- public broadcastCheckpointProposal(proposal: CheckpointProposal): Promise<void> {
341
+ public async broadcastCheckpointProposal(proposal: CheckpointProposal): Promise<void> {
340
342
  this.log.verbose(`Broadcasting checkpoint proposal for slot ${proposal.slotNumber} to peers`);
343
+ const blockProposal = proposal.getBlockProposal();
344
+ if (blockProposal) {
345
+ // Store our own last-block proposal so we can respond to req/resp requests for it.
346
+ await this.attestationPool.addBlockProposal(blockProposal);
347
+ }
341
348
  return this.p2pService.propagate(proposal);
342
349
  }
343
350