@aztec/end-to-end 0.0.1-commit.1142ef1 → 0.0.1-commit.1bea0213

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 (155) hide show
  1. package/dest/bench/client_flows/benchmark.d.ts +3 -2
  2. package/dest/bench/client_flows/benchmark.d.ts.map +1 -1
  3. package/dest/bench/client_flows/benchmark.js +21 -1
  4. package/dest/bench/client_flows/client_flows_benchmark.d.ts +12 -13
  5. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  6. package/dest/bench/client_flows/client_flows_benchmark.js +117 -132
  7. package/dest/bench/utils.d.ts +6 -5
  8. package/dest/bench/utils.d.ts.map +1 -1
  9. package/dest/bench/utils.js +9 -7
  10. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +6 -7
  11. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  12. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +96 -112
  13. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +6 -7
  14. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  15. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +65 -62
  16. package/dest/e2e_deploy_contract/deploy_test.d.ts +4 -3
  17. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  18. package/dest/e2e_deploy_contract/deploy_test.js +18 -13
  19. package/dest/e2e_epochs/epochs_test.d.ts +1 -1
  20. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  21. package/dest/e2e_epochs/epochs_test.js +4 -1
  22. package/dest/e2e_fees/bridging_race.notest.js +3 -5
  23. package/dest/e2e_fees/fees_test.d.ts +13 -13
  24. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  25. package/dest/e2e_fees/fees_test.js +122 -140
  26. package/dest/e2e_l1_publisher/write_json.d.ts +2 -2
  27. package/dest/e2e_l1_publisher/write_json.d.ts.map +1 -1
  28. package/dest/e2e_l1_publisher/write_json.js +19 -12
  29. package/dest/e2e_nested_contract/nested_contract_test.d.ts +6 -9
  30. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  31. package/dest/e2e_nested_contract/nested_contract_test.js +31 -39
  32. package/dest/e2e_p2p/inactivity_slash_test.d.ts +3 -3
  33. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
  34. package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
  35. package/dest/e2e_p2p/p2p_network.d.ts +7 -6
  36. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  37. package/dest/e2e_p2p/p2p_network.js +110 -103
  38. package/dest/e2e_p2p/shared.d.ts +6 -6
  39. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  40. package/dest/e2e_p2p/shared.js +7 -14
  41. package/dest/e2e_token_contract/token_contract_test.d.ts +16 -9
  42. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  43. package/dest/e2e_token_contract/token_contract_test.js +89 -91
  44. package/dest/fixtures/e2e_prover_test.d.ts +8 -14
  45. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  46. package/dest/fixtures/e2e_prover_test.js +84 -92
  47. package/dest/fixtures/setup.d.ts +218 -0
  48. package/dest/fixtures/setup.d.ts.map +1 -0
  49. package/dest/fixtures/setup.js +690 -0
  50. package/dest/fixtures/token_utils.d.ts +1 -1
  51. package/dest/fixtures/token_utils.d.ts.map +1 -1
  52. package/dest/fixtures/token_utils.js +7 -4
  53. package/dest/fixtures/utils.d.ts +5 -191
  54. package/dest/fixtures/utils.d.ts.map +1 -1
  55. package/dest/fixtures/utils.js +4 -615
  56. package/dest/quality_of_service/prometheus_client.d.ts +38 -0
  57. package/dest/quality_of_service/prometheus_client.d.ts.map +1 -0
  58. package/dest/quality_of_service/prometheus_client.js +67 -0
  59. package/dest/shared/cross_chain_test_harness.d.ts +14 -4
  60. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  61. package/dest/shared/cross_chain_test_harness.js +11 -11
  62. package/dest/shared/gas_portal_test_harness.d.ts +11 -1
  63. package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
  64. package/dest/shared/gas_portal_test_harness.js +1 -1
  65. package/dest/shared/submit-transactions.d.ts +3 -3
  66. package/dest/shared/submit-transactions.d.ts.map +1 -1
  67. package/dest/shared/submit-transactions.js +9 -11
  68. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  69. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  70. package/dest/shared/uniswap_l1_l2.js +12 -12
  71. package/dest/simulators/lending_simulator.d.ts +5 -1
  72. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  73. package/dest/simulators/lending_simulator.js +2 -2
  74. package/dest/spartan/setup_test_wallets.d.ts +1 -1
  75. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  76. package/dest/spartan/setup_test_wallets.js +61 -34
  77. package/dest/spartan/tx_metrics.d.ts +17 -2
  78. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  79. package/dest/spartan/tx_metrics.js +183 -6
  80. package/dest/spartan/utils/bot.d.ts +27 -0
  81. package/dest/spartan/utils/bot.d.ts.map +1 -0
  82. package/dest/spartan/utils/bot.js +141 -0
  83. package/dest/spartan/utils/chaos.d.ts +79 -0
  84. package/dest/spartan/utils/chaos.d.ts.map +1 -0
  85. package/dest/spartan/utils/chaos.js +142 -0
  86. package/dest/spartan/utils/clients.d.ts +39 -0
  87. package/dest/spartan/utils/clients.d.ts.map +1 -0
  88. package/dest/spartan/utils/clients.js +90 -0
  89. package/dest/spartan/utils/config.d.ts +36 -0
  90. package/dest/spartan/utils/config.d.ts.map +1 -0
  91. package/dest/spartan/utils/config.js +20 -0
  92. package/dest/spartan/utils/health.d.ts +63 -0
  93. package/dest/spartan/utils/health.d.ts.map +1 -0
  94. package/dest/spartan/utils/health.js +202 -0
  95. package/dest/spartan/utils/helm.d.ts +15 -0
  96. package/dest/spartan/utils/helm.d.ts.map +1 -0
  97. package/dest/spartan/utils/helm.js +47 -0
  98. package/dest/spartan/utils/index.d.ts +9 -0
  99. package/dest/spartan/utils/index.d.ts.map +1 -0
  100. package/dest/spartan/utils/index.js +18 -0
  101. package/dest/spartan/utils/k8s.d.ts +98 -0
  102. package/dest/spartan/utils/k8s.d.ts.map +1 -0
  103. package/dest/spartan/utils/k8s.js +257 -0
  104. package/dest/spartan/utils/nodes.d.ts +31 -0
  105. package/dest/spartan/utils/nodes.d.ts.map +1 -0
  106. package/dest/spartan/utils/nodes.js +290 -0
  107. package/dest/spartan/utils/scripts.d.ts +16 -0
  108. package/dest/spartan/utils/scripts.d.ts.map +1 -0
  109. package/dest/spartan/utils/scripts.js +66 -0
  110. package/dest/spartan/utils.d.ts +2 -253
  111. package/dest/spartan/utils.d.ts.map +1 -1
  112. package/dest/spartan/utils.js +1 -892
  113. package/package.json +40 -39
  114. package/src/bench/client_flows/benchmark.ts +24 -2
  115. package/src/bench/client_flows/client_flows_benchmark.ts +137 -203
  116. package/src/bench/utils.ts +9 -7
  117. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +104 -142
  118. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +99 -106
  119. package/src/e2e_deploy_contract/deploy_test.ts +21 -14
  120. package/src/e2e_epochs/epochs_test.ts +30 -25
  121. package/src/e2e_fees/bridging_race.notest.ts +3 -9
  122. package/src/e2e_fees/fees_test.ts +171 -217
  123. package/src/e2e_l1_publisher/write_json.ts +21 -13
  124. package/src/e2e_nested_contract/nested_contract_test.ts +33 -56
  125. package/src/e2e_p2p/inactivity_slash_test.ts +5 -5
  126. package/src/e2e_p2p/p2p_network.ts +171 -167
  127. package/src/e2e_p2p/shared.ts +10 -20
  128. package/src/e2e_token_contract/token_contract_test.ts +103 -118
  129. package/src/fixtures/e2e_prover_test.ts +98 -132
  130. package/src/fixtures/setup.ts +1017 -0
  131. package/src/fixtures/token_utils.ts +6 -5
  132. package/src/fixtures/utils.ts +27 -901
  133. package/src/quality_of_service/prometheus_client.ts +113 -0
  134. package/src/shared/cross_chain_test_harness.ts +13 -27
  135. package/src/shared/gas_portal_test_harness.ts +1 -1
  136. package/src/shared/submit-transactions.ts +9 -15
  137. package/src/shared/uniswap_l1_l2.ts +12 -19
  138. package/src/simulators/lending_simulator.ts +2 -2
  139. package/src/spartan/setup_test_wallets.ts +72 -24
  140. package/src/spartan/tx_metrics.ts +129 -9
  141. package/src/spartan/utils/bot.ts +185 -0
  142. package/src/spartan/utils/chaos.ts +253 -0
  143. package/src/spartan/utils/clients.ts +100 -0
  144. package/src/spartan/utils/config.ts +26 -0
  145. package/src/spartan/utils/health.ts +255 -0
  146. package/src/spartan/utils/helm.ts +84 -0
  147. package/src/spartan/utils/index.ts +62 -0
  148. package/src/spartan/utils/k8s.ts +375 -0
  149. package/src/spartan/utils/nodes.ts +323 -0
  150. package/src/spartan/utils/scripts.ts +63 -0
  151. package/src/spartan/utils.ts +1 -1158
  152. package/dest/fixtures/snapshot_manager.d.ts +0 -93
  153. package/dest/fixtures/snapshot_manager.d.ts.map +0 -1
  154. package/dest/fixtures/snapshot_manager.js +0 -488
  155. package/src/fixtures/snapshot_manager.ts +0 -646
@@ -1,10 +1,11 @@
1
1
  import { generateSchnorrAccounts } from '@aztec/accounts/testing';
2
2
  import { AztecAddress } from '@aztec/aztec.js/addresses';
3
+ import { NO_WAIT } from '@aztec/aztec.js/contracts';
3
4
  import { L1FeeJuicePortalManager } from '@aztec/aztec.js/ethereum';
4
5
  import { FeeJuicePaymentMethodWithClaim } from '@aztec/aztec.js/fee';
5
6
  import { SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee';
6
7
  import { Fr } from '@aztec/aztec.js/fields';
7
- import { createAztecNodeClient } from '@aztec/aztec.js/node';
8
+ import { createAztecNodeClient, waitForTx } from '@aztec/aztec.js/node';
8
9
  import { createEthereumChain } from '@aztec/ethereum/chain';
9
10
  import { createExtendedL1Client } from '@aztec/ethereum/client';
10
11
  import { retryUntil } from '@aztec/foundation/retry';
@@ -46,9 +47,10 @@ export async function deploySponsoredTestAccountsWithTokens(wallet, aztecNode, m
46
47
  from: AztecAddress.ZERO,
47
48
  fee: {
48
49
  paymentMethod
50
+ },
51
+ wait: {
52
+ timeout: 2400
49
53
  }
50
- }).wait({
51
- timeout: 2400
52
54
  });
53
55
  await Promise.all(fundedAccounts.map(async (a)=>{
54
56
  const deployMethod = await a.getDeployMethod();
@@ -56,9 +58,10 @@ export async function deploySponsoredTestAccountsWithTokens(wallet, aztecNode, m
56
58
  from: AztecAddress.ZERO,
57
59
  fee: {
58
60
  paymentMethod
61
+ },
62
+ wait: {
63
+ timeout: 2400
59
64
  }
60
- }).wait({
61
- timeout: 2400
62
65
  }); // increase timeout on purpose in order to account for two empty epochs
63
66
  logger.info(`Account deployed at ${a.address}`);
64
67
  }));
@@ -76,33 +79,52 @@ export async function deploySponsoredTestAccountsWithTokens(wallet, aztecNode, m
76
79
  recipientAddress: recipientAccount.address
77
80
  };
78
81
  }
82
+ async function deployAccountWithDiagnostics(account, paymentMethod, aztecNode, logger, accountLabel) {
83
+ const deployMethod = await account.getDeployMethod();
84
+ let txHash;
85
+ try {
86
+ txHash = await deployMethod.send({
87
+ from: AztecAddress.ZERO,
88
+ fee: {
89
+ paymentMethod
90
+ },
91
+ wait: NO_WAIT
92
+ });
93
+ await waitForTx(aztecNode, txHash, {
94
+ timeout: 2400
95
+ });
96
+ logger.info(`${accountLabel} deployed at ${account.address}`);
97
+ } catch (error) {
98
+ const blockNumber = await aztecNode.getBlockNumber();
99
+ let receipt;
100
+ try {
101
+ receipt = await aztecNode.getTxReceipt(txHash);
102
+ } catch {
103
+ receipt = 'unavailable';
104
+ }
105
+ logger.error(`${accountLabel} deployment failed`, {
106
+ txHash: txHash.toString(),
107
+ receipt: JSON.stringify(receipt),
108
+ currentBlockNumber: blockNumber,
109
+ error: String(error)
110
+ });
111
+ throw error;
112
+ }
113
+ }
114
+ async function deployAccountsInBatches(accounts, paymentMethod, aztecNode, logger, labelPrefix, batchSize = 2) {
115
+ for(let i = 0; i < accounts.length; i += batchSize){
116
+ const batch = accounts.slice(i, i + batchSize);
117
+ await Promise.all(batch.map((account, idx)=>deployAccountWithDiagnostics(account, paymentMethod, aztecNode, logger, `${labelPrefix}${i + idx + 1}`)));
118
+ }
119
+ }
79
120
  export async function deploySponsoredTestAccounts(wallet, aztecNode, logger, numberOfFundedWallets = 1) {
80
121
  const [recipient, ...funded] = await generateSchnorrAccounts(numberOfFundedWallets + 1);
81
122
  const recipientAccount = await wallet.createSchnorrAccount(recipient.secret, recipient.salt);
82
123
  const fundedAccounts = await Promise.all(funded.map((a)=>wallet.createSchnorrAccount(a.secret, a.salt)));
83
124
  await registerSponsoredFPC(wallet);
84
125
  const paymentMethod = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress());
85
- const recipientDeployMethod = await recipientAccount.getDeployMethod();
86
- await recipientDeployMethod.send({
87
- from: AztecAddress.ZERO,
88
- fee: {
89
- paymentMethod
90
- }
91
- }).wait({
92
- timeout: 2400
93
- });
94
- await Promise.all(fundedAccounts.map(async (a)=>{
95
- const deployMethod = await a.getDeployMethod();
96
- await deployMethod.send({
97
- from: AztecAddress.ZERO,
98
- fee: {
99
- paymentMethod
100
- }
101
- }).wait({
102
- timeout: 2400
103
- }); // increase timeout on purpose in order to account for two empty epochs
104
- logger.info(`Account deployed at ${a.address}`);
105
- }));
126
+ await deployAccountWithDiagnostics(recipientAccount, paymentMethod, aztecNode, logger, 'Recipient account');
127
+ await deployAccountsInBatches(fundedAccounts, paymentMethod, aztecNode, logger, 'Funded account ', 2);
106
128
  return {
107
129
  aztecNode,
108
130
  wallet,
@@ -129,7 +151,7 @@ export async function deployTestAccountsWithTokens(nodeUrl, l1RpcUrls, mnemonicO
129
151
  fee: {
130
152
  paymentMethod
131
153
  }
132
- }).wait();
154
+ });
133
155
  logger.info(`Account deployed at ${a.address}`);
134
156
  }));
135
157
  const tokenAdmin = fundedAccounts[0];
@@ -175,13 +197,15 @@ async function advanceL2Block(aztecNode, nodeAdmin) {
175
197
  }
176
198
  async function deployTokenAndMint(wallet, accounts, admin, mintAmount, paymentMethod, logger) {
177
199
  logger.verbose(`Deploying TokenContract...`);
178
- const tokenContract = await TokenContract.deploy(wallet, admin, TOKEN_NAME, TOKEN_SYMBOL, TOKEN_DECIMALS).send({
200
+ const { contract: tokenContract } = await TokenContract.deploy(wallet, admin, TOKEN_NAME, TOKEN_SYMBOL, TOKEN_DECIMALS).send({
179
201
  from: admin,
180
202
  fee: {
181
203
  paymentMethod
204
+ },
205
+ wait: {
206
+ timeout: 600,
207
+ returnReceipt: true
182
208
  }
183
- }).deployed({
184
- timeout: 600
185
209
  });
186
210
  const tokenAddress = tokenContract.address;
187
211
  logger.verbose(`Minting ${mintAmount} public assets to the ${accounts.length} accounts...`);
@@ -189,9 +213,10 @@ async function deployTokenAndMint(wallet, accounts, admin, mintAmount, paymentMe
189
213
  from: admin,
190
214
  fee: {
191
215
  paymentMethod
216
+ },
217
+ wait: {
218
+ timeout: 600
192
219
  }
193
- }).wait({
194
- timeout: 600
195
220
  })));
196
221
  logger.verbose(`Minting complete.`);
197
222
  return tokenAddress;
@@ -211,8 +236,10 @@ export async function performTransfers({ wallet, testAccounts, rounds, transferA
211
236
  });
212
237
  });
213
238
  const provenTxs = await Promise.all(txs);
214
- await Promise.all(provenTxs.map((t)=>t.send().wait({
215
- timeout: 600
239
+ await Promise.all(provenTxs.map((t)=>t.send({
240
+ wait: {
241
+ timeout: 600
242
+ }
216
243
  })));
217
244
  logger.info(`Completed round ${i + 1} / ${rounds}`);
218
245
  }
@@ -1,4 +1,6 @@
1
1
  import type { AztecNode } from '@aztec/aztec.js/node';
2
+ import type { Logger } from '@aztec/foundation/log';
3
+ import type { TopicType } from '@aztec/stdlib/p2p';
2
4
  import { Tx, type TxReceipt } from '@aztec/stdlib/tx';
3
5
  export type TxInclusionData = {
4
6
  txHash: string;
@@ -13,10 +15,17 @@ export type TxInclusionData = {
13
15
  };
14
16
  export declare class TxInclusionMetrics {
15
17
  private aztecNode;
18
+ private logger?;
16
19
  private data;
17
20
  private groups;
18
21
  private blocks;
19
- constructor(aztecNode: AztecNode);
22
+ private p2pGossipLatencyByTopic;
23
+ private attestationLatency;
24
+ private attestationCounts;
25
+ private reqRespStats;
26
+ private peerStats;
27
+ private mempoolMinedDelay;
28
+ constructor(aztecNode: AztecNode, logger?: Logger | undefined);
20
29
  recordSentTx(tx: Tx, group: string): void;
21
30
  recordMinedTx(txReceipt: TxReceipt): Promise<void>;
22
31
  inclusionTimeInSeconds(group: string): {
@@ -28,6 +37,12 @@ export declare class TxInclusionMetrics {
28
37
  median: number;
29
38
  p99: number;
30
39
  };
40
+ recordP2PGossipLatency(topicName: TopicType, p50: number, p95: number): void;
41
+ recordAttestationLatency(p50: number, p95: number): void;
42
+ recordAttestationCounts(success: number, failedBad: number, failedNode: number): void;
43
+ recordReqRespStats(fraction: number, delayP50: number, delayP95: number): void;
44
+ recordPeerStats(avgCount: number, connectionDurationP50: number, connectionDurationP95: number): void;
45
+ recordMempoolMinedDelay(txP50: number, txP95: number, attestationP50: number, attestationP95: number): void;
31
46
  toGithubActionBenchmarkJSON(): Array<{
32
47
  name: string;
33
48
  unit: string;
@@ -36,4 +51,4 @@ export declare class TxInclusionMetrics {
36
51
  extra?: string;
37
52
  }>;
38
53
  }
39
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhfbWV0cmljcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NwYXJ0YW4vdHhfbWV0cmljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUV0RCxPQUFPLEVBQUUsRUFBRSxFQUFFLEtBQUssU0FBUyxFQUFZLE1BQU0sa0JBQWtCLENBQUM7QUFJaEUsTUFBTSxNQUFNLGVBQWUsR0FBRztJQUM1QixNQUFNLEVBQUUsTUFBTSxDQUFDO0lBQ2YsTUFBTSxFQUFFLE1BQU0sQ0FBQztJQUNmLE9BQU8sRUFBRSxNQUFNLENBQUM7SUFDaEIsVUFBVSxFQUFFLE1BQU0sQ0FBQztJQUNuQixXQUFXLEVBQUUsTUFBTSxDQUFDO0lBQ3BCLFdBQVcsRUFBRSxNQUFNLENBQUM7SUFDcEIsUUFBUSxFQUFFLE1BQU0sQ0FBQztJQUNqQixlQUFlLEVBQUUsTUFBTSxDQUFDO0lBQ3hCLEtBQUssRUFBRSxNQUFNLENBQUM7Q0FDZixDQUFDO0FBRUYscUJBQWEsa0JBQWtCO0lBS2pCLE9BQU8sQ0FBQyxTQUFTO0lBSjdCLE9BQU8sQ0FBQyxJQUFJLENBQXNDO0lBQ2xELE9BQU8sQ0FBQyxNQUFNLENBQXFCO0lBQ25DLE9BQU8sQ0FBQyxNQUFNLENBQXVDO0lBRXJELFlBQW9CLFNBQVMsRUFBRSxTQUFTLEVBQUk7SUFFNUMsWUFBWSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sR0FBRyxJQUFJLENBZ0J4QztJQUVLLGFBQWEsQ0FBQyxTQUFTLEVBQUUsU0FBUyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FpQnZEO0lBRU0sc0JBQXNCLENBQUMsS0FBSyxFQUFFLE1BQU0sR0FBRztRQUM1QyxLQUFLLEVBQUUsTUFBTSxDQUFDO1FBQ2QsS0FBSyxFQUFFLE1BQU0sQ0FBQztRQUNkLEdBQUcsRUFBRSxNQUFNLENBQUM7UUFDWixJQUFJLEVBQUUsTUFBTSxDQUFDO1FBQ2IsR0FBRyxFQUFFLE1BQU0sQ0FBQztRQUNaLE1BQU0sRUFBRSxNQUFNLENBQUM7UUFDZixHQUFHLEVBQUUsTUFBTSxDQUFDO0tBQ2IsQ0ErQkE7SUFFRCwyQkFBMkIsSUFBSSxLQUFLLENBQUM7UUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDO1FBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQztRQUFDLEtBQUssRUFBRSxNQUFNLENBQUM7UUFBQyxLQUFLLENBQUMsRUFBRSxNQUFNLENBQUM7UUFBQyxLQUFLLENBQUMsRUFBRSxNQUFNLENBQUE7S0FBRSxDQUFDLENBeUJsSDtDQUNGIn0=
54
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhfbWV0cmljcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NwYXJ0YW4vdHhfbWV0cmljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN0RCxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUVwRCxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsRUFBRSxFQUFFLEtBQUssU0FBUyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFJdEQsTUFBTSxNQUFNLGVBQWUsR0FBRztJQUM1QixNQUFNLEVBQUUsTUFBTSxDQUFDO0lBQ2YsTUFBTSxFQUFFLE1BQU0sQ0FBQztJQUNmLE9BQU8sRUFBRSxNQUFNLENBQUM7SUFDaEIsVUFBVSxFQUFFLE1BQU0sQ0FBQztJQUNuQixXQUFXLEVBQUUsTUFBTSxDQUFDO0lBQ3BCLFdBQVcsRUFBRSxNQUFNLENBQUM7SUFDcEIsUUFBUSxFQUFFLE1BQU0sQ0FBQztJQUNqQixlQUFlLEVBQUUsTUFBTSxDQUFDO0lBQ3hCLEtBQUssRUFBRSxNQUFNLENBQUM7Q0FDZixDQUFDO0FBRUYscUJBQWEsa0JBQWtCO0lBZ0IzQixPQUFPLENBQUMsU0FBUztJQUNqQixPQUFPLENBQUMsTUFBTSxDQUFDO0lBaEJqQixPQUFPLENBQUMsSUFBSSxDQUFzQztJQUNsRCxPQUFPLENBQUMsTUFBTSxDQUFxQjtJQUNuQyxPQUFPLENBQUMsTUFBTSxDQUFtRDtJQUVqRSxPQUFPLENBQUMsdUJBQXVCLENBQWdFO0lBRS9GLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBMkM7SUFDckUsT0FBTyxDQUFDLGlCQUFpQixDQUF5RTtJQUNsRyxPQUFPLENBQUMsWUFBWSxDQUF1RTtJQUMzRixPQUFPLENBQUMsU0FBUyxDQUFpRztJQUNsSCxPQUFPLENBQUMsaUJBQWlCLENBRVg7SUFFZCxZQUNVLFNBQVMsRUFBRSxTQUFTLEVBQ3BCLE1BQU0sQ0FBQyxvQkFBUSxFQUNyQjtJQUVKLFlBQVksQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxNQUFNLEdBQUcsSUFBSSxDQW9CeEM7SUFFSyxhQUFhLENBQUMsU0FBUyxFQUFFLFNBQVMsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBK0J2RDtJQUVNLHNCQUFzQixDQUFDLEtBQUssRUFBRSxNQUFNLEdBQUc7UUFDNUMsS0FBSyxFQUFFLE1BQU0sQ0FBQztRQUNkLEtBQUssRUFBRSxNQUFNLENBQUM7UUFDZCxHQUFHLEVBQUUsTUFBTSxDQUFDO1FBQ1osSUFBSSxFQUFFLE1BQU0sQ0FBQztRQUNiLEdBQUcsRUFBRSxNQUFNLENBQUM7UUFDWixNQUFNLEVBQUUsTUFBTSxDQUFDO1FBQ2YsR0FBRyxFQUFFLE1BQU0sQ0FBQztLQUNiLENBK0JBO0lBRU0sc0JBQXNCLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxNQUFNLEdBQUcsSUFBSSxDQUVsRjtJQUVNLHdCQUF3QixDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE1BQU0sR0FBRyxJQUFJLENBRTlEO0lBRU0sdUJBQXVCLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLEdBQUcsSUFBSSxDQUUzRjtJQUVNLGtCQUFrQixDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTSxHQUFHLElBQUksQ0FFcEY7SUFFTSxlQUFlLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxHQUFHLElBQUksQ0FFM0c7SUFFTSx1QkFBdUIsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxjQUFjLEVBQUUsTUFBTSxHQUFHLElBQUksQ0FFakg7SUFFRCwyQkFBMkIsSUFBSSxLQUFLLENBQUM7UUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDO1FBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQztRQUFDLEtBQUssRUFBRSxNQUFNLENBQUM7UUFBQyxLQUFLLENBQUMsRUFBRSxNQUFNLENBQUM7UUFBQyxLQUFLLENBQUMsRUFBRSxNQUFNLENBQUE7S0FBRSxDQUFDLENBd0ZsSDtDQUNGIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"tx_metrics.d.ts","sourceRoot":"","sources":["../../src/spartan/tx_metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,EAAE,EAAE,KAAK,SAAS,EAAY,MAAM,kBAAkB,CAAC;AAIhE,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,qBAAa,kBAAkB;IAKjB,OAAO,CAAC,SAAS;IAJ7B,OAAO,CAAC,IAAI,CAAsC;IAClD,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAuC;IAErD,YAAoB,SAAS,EAAE,SAAS,EAAI;IAE5C,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAgBxC;IAEK,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBvD;IAEM,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG;QAC5C,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CA+BA;IAED,2BAA2B,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAyBlH;CACF"}
1
+ {"version":3,"file":"tx_metrics.d.ts","sourceRoot":"","sources":["../../src/spartan/tx_metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAItD,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,qBAAa,kBAAkB;IAgB3B,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,MAAM,CAAC;IAhBjB,OAAO,CAAC,IAAI,CAAsC;IAClD,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAmD;IAEjE,OAAO,CAAC,uBAAuB,CAAgE;IAE/F,OAAO,CAAC,kBAAkB,CAA2C;IACrE,OAAO,CAAC,iBAAiB,CAAyE;IAClG,OAAO,CAAC,YAAY,CAAuE;IAC3F,OAAO,CAAC,SAAS,CAAiG;IAClH,OAAO,CAAC,iBAAiB,CAEX;IAEd,YACU,SAAS,EAAE,SAAS,EACpB,MAAM,CAAC,oBAAQ,EACrB;IAEJ,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAoBxC;IAEK,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BvD;IAEM,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG;QAC5C,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CA+BA;IAEM,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAElF;IAEM,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAE9D;IAEM,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAE3F;IAEM,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAEpF;IAEM,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAE3G;IAEM,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAEjH;IAED,2BAA2B,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAwFlH;CACF"}
@@ -1,19 +1,33 @@
1
- import { TxStatus } from '@aztec/stdlib/tx';
2
1
  import { createHistogram } from 'perf_hooks';
3
2
  export class TxInclusionMetrics {
4
3
  aztecNode;
4
+ logger;
5
5
  data;
6
6
  groups;
7
7
  blocks;
8
- constructor(aztecNode){
8
+ p2pGossipLatencyByTopic;
9
+ attestationLatency;
10
+ attestationCounts;
11
+ reqRespStats;
12
+ peerStats;
13
+ mempoolMinedDelay;
14
+ constructor(aztecNode, logger){
9
15
  this.aztecNode = aztecNode;
16
+ this.logger = logger;
10
17
  this.data = new Map();
11
18
  this.groups = new Set();
12
19
  this.blocks = new Map();
20
+ this.p2pGossipLatencyByTopic = {};
13
21
  }
14
22
  recordSentTx(tx, group) {
15
23
  const txHash = tx.getTxHash().toString();
16
24
  const priorityFees = tx.getGasSettings().maxPriorityFeesPerGas;
25
+ if (this.data.has(txHash)) {
26
+ this.logger?.debug(`Overwriting tx inclusion data for ${txHash}`, {
27
+ txHash,
28
+ group
29
+ });
30
+ }
17
31
  this.data.set(txHash, {
18
32
  txHash,
19
33
  sentAt: Math.trunc(Date.now() / 1000),
@@ -28,15 +42,35 @@ export class TxInclusionMetrics {
28
42
  this.groups.add(group);
29
43
  }
30
44
  async recordMinedTx(txReceipt) {
31
- const { status, txHash, blockNumber } = txReceipt;
32
- if (status !== TxStatus.SUCCESS || !blockNumber) {
45
+ const { txHash, blockNumber } = txReceipt;
46
+ if (!txReceipt.isMined() || !txReceipt.hasExecutionSucceeded() || !blockNumber) {
47
+ this.logger?.debug('Skipping mined tx record due to receipt status', {
48
+ txHash: txHash.toString(),
49
+ status: txReceipt.status,
50
+ blockNumber
51
+ });
33
52
  return;
34
53
  }
35
54
  if (!this.blocks.has(blockNumber)) {
36
55
  this.blocks.set(blockNumber, this.aztecNode.getBlock(blockNumber));
37
56
  }
38
57
  const block = await this.blocks.get(blockNumber);
58
+ if (!block) {
59
+ this.logger?.warn('Failed to load block for mined tx receipt', {
60
+ txHash: txHash.toString(),
61
+ blockNumber
62
+ });
63
+ return;
64
+ }
39
65
  const data = this.data.get(txHash.toString());
66
+ if (!data) {
67
+ const message = `Missing sent tx record for mined tx ${txHash.toString()}`;
68
+ this.logger?.warn(message, {
69
+ txHash: txHash.toString(),
70
+ blockNumber
71
+ });
72
+ throw new Error(message);
73
+ }
40
74
  data.blocknumber = blockNumber;
41
75
  data.minedAt = Number(block.header.globalVariables.timestamp);
42
76
  data.attestedAt = -1;
@@ -46,7 +80,7 @@ export class TxInclusionMetrics {
46
80
  inclusionTimeInSeconds(group) {
47
81
  const histogram = createHistogram({});
48
82
  for (const tx of this.data.values()){
49
- if (!tx.blocknumber || tx.group !== group) {
83
+ if (!tx.blocknumber || tx.group !== group || tx.minedAt === -1) {
50
84
  continue;
51
85
  }
52
86
  histogram.record(tx.minedAt - tx.sentAt);
@@ -72,6 +106,47 @@ export class TxInclusionMetrics {
72
106
  p99: histogram.percentile(99)
73
107
  };
74
108
  }
109
+ recordP2PGossipLatency(topicName, p50, p95) {
110
+ this.p2pGossipLatencyByTopic[topicName] = {
111
+ p50,
112
+ p95
113
+ };
114
+ }
115
+ recordAttestationLatency(p50, p95) {
116
+ this.attestationLatency = {
117
+ p50,
118
+ p95
119
+ };
120
+ }
121
+ recordAttestationCounts(success, failedBad, failedNode) {
122
+ this.attestationCounts = {
123
+ success,
124
+ failedBad,
125
+ failedNode
126
+ };
127
+ }
128
+ recordReqRespStats(fraction, delayP50, delayP95) {
129
+ this.reqRespStats = {
130
+ fraction,
131
+ delayP50,
132
+ delayP95
133
+ };
134
+ }
135
+ recordPeerStats(avgCount, connectionDurationP50, connectionDurationP95) {
136
+ this.peerStats = {
137
+ avgCount,
138
+ connectionDurationP50,
139
+ connectionDurationP95
140
+ };
141
+ }
142
+ recordMempoolMinedDelay(txP50, txP95, attestationP50, attestationP95) {
143
+ this.mempoolMinedDelay = {
144
+ txP50,
145
+ txP95,
146
+ attestationP50,
147
+ attestationP95
148
+ };
149
+ }
75
150
  toGithubActionBenchmarkJSON() {
76
151
  const data = [];
77
152
  for (const group of this.groups){
@@ -90,6 +165,108 @@ export class TxInclusionMetrics {
90
165
  value: stats.p99
91
166
  });
92
167
  }
93
- return data;
168
+ for (const [topic, { p50, p95 }] of Object.entries(this.p2pGossipLatencyByTopic)){
169
+ data.push({
170
+ name: `p2p_gossip_latency/${topic}/p50`,
171
+ unit: 'ms',
172
+ value: p50
173
+ });
174
+ data.push({
175
+ name: `p2p_gossip_latency/${topic}/p95`,
176
+ unit: 'ms',
177
+ value: p95
178
+ });
179
+ }
180
+ if (this.attestationLatency) {
181
+ data.push({
182
+ name: 'attestation_latency/p50',
183
+ unit: 'ms',
184
+ value: this.attestationLatency.p50
185
+ }, {
186
+ name: 'attestation_latency/p95',
187
+ unit: 'ms',
188
+ value: this.attestationLatency.p95
189
+ });
190
+ }
191
+ if (this.attestationCounts) {
192
+ const { success, failedBad, failedNode } = this.attestationCounts;
193
+ const total = success + failedBad + failedNode;
194
+ const ratio = total > 0 ? success / total : 0;
195
+ data.push({
196
+ name: 'attestation/success_count',
197
+ unit: 'count',
198
+ value: success
199
+ }, {
200
+ name: 'attestation/failed_bad_proposal_count',
201
+ unit: 'count',
202
+ value: failedBad
203
+ }, {
204
+ name: 'attestation/failed_node_issue_count',
205
+ unit: 'count',
206
+ value: failedNode
207
+ }, {
208
+ name: 'attestation/success_ratio',
209
+ unit: 'ratio',
210
+ value: ratio
211
+ });
212
+ }
213
+ if (this.reqRespStats) {
214
+ data.push({
215
+ name: 'req_resp/txs_requested_fraction',
216
+ unit: 'ratio',
217
+ value: this.reqRespStats.fraction
218
+ }, {
219
+ name: 'req_resp/delay_p50',
220
+ unit: 'ms',
221
+ value: this.reqRespStats.delayP50
222
+ }, {
223
+ name: 'req_resp/delay_p95',
224
+ unit: 'ms',
225
+ value: this.reqRespStats.delayP95
226
+ });
227
+ }
228
+ if (this.peerStats) {
229
+ data.push({
230
+ name: 'peers/avg_count',
231
+ unit: 'peers',
232
+ value: this.peerStats.avgCount
233
+ }, {
234
+ name: 'peers/connection_duration_p50',
235
+ unit: 'ms',
236
+ value: this.peerStats.connectionDurationP50
237
+ }, {
238
+ name: 'peers/connection_duration_p95',
239
+ unit: 'ms',
240
+ value: this.peerStats.connectionDurationP95
241
+ });
242
+ }
243
+ if (this.mempoolMinedDelay) {
244
+ data.push({
245
+ name: 'mempool/tx_mined_delay_p50',
246
+ unit: 'ms',
247
+ value: this.mempoolMinedDelay.txP50
248
+ }, {
249
+ name: 'mempool/tx_mined_delay_p95',
250
+ unit: 'ms',
251
+ value: this.mempoolMinedDelay.txP95
252
+ }, {
253
+ name: 'mempool/attestation_mined_delay_p50',
254
+ unit: 'ms',
255
+ value: this.mempoolMinedDelay.attestationP50
256
+ }, {
257
+ name: 'mempool/attestation_mined_delay_p95',
258
+ unit: 'ms',
259
+ value: this.mempoolMinedDelay.attestationP95
260
+ });
261
+ }
262
+ const scenario = process.env.BENCH_SCENARIO?.trim();
263
+ if (!scenario) {
264
+ return data;
265
+ }
266
+ const scenarioPrefix = `scenario/${scenario}/`;
267
+ return data.map((entry)=>({
268
+ ...entry,
269
+ name: `${scenarioPrefix}${entry.name}`
270
+ }));
94
271
  }
95
272
  }
@@ -0,0 +1,27 @@
1
+ import type { Logger } from '@aztec/foundation/log';
2
+ export declare function restartBot(namespace: string, log: Logger): Promise<void>;
3
+ /**
4
+ * Installs or upgrades the transfer bot Helm release for the given namespace.
5
+ * Intended for test setup to enable L2 traffic generation only when needed.
6
+ */
7
+ export declare function installTransferBot({ namespace, spartanDir, logger: log, replicas, txIntervalSeconds, followChain, mnemonic, mnemonicStartIndex, botPrivateKey, nodeUrl, timeout, reuseValues, aztecSlotDuration }: {
8
+ namespace: string;
9
+ spartanDir: string;
10
+ logger: Logger;
11
+ replicas?: number;
12
+ txIntervalSeconds?: number;
13
+ followChain?: string;
14
+ mnemonic?: string;
15
+ mnemonicStartIndex?: number | string;
16
+ botPrivateKey?: string;
17
+ nodeUrl?: string;
18
+ timeout?: string;
19
+ reuseValues?: boolean;
20
+ aztecSlotDuration?: number;
21
+ }): Promise<void>;
22
+ /**
23
+ * Uninstalls the transfer bot Helm release from the given namespace.
24
+ * Intended for test teardown to clean up bot resources.
25
+ */
26
+ export declare function uninstallTransferBot(namespace: string, log: Logger): Promise<void>;
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm90LmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3BhcnRhbi91dGlscy9ib3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFXcEQsd0JBQXNCLFVBQVUsQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxNQUFNLGlCQWE5RDtBQUVEOzs7R0FHRztBQUNILHdCQUFzQixrQkFBa0IsQ0FBQyxFQUN2QyxTQUFTLEVBQ1QsVUFBVSxFQUNWLE1BQU0sRUFBRSxHQUFHLEVBQ1gsUUFBWSxFQUNaLGlCQUFzQixFQUN0QixXQUF1QixFQUN2QixRQUEyRyxFQUMzRyxrQkFBa0IsRUFDbEIsYUFBc0UsRUFDdEUsT0FBTyxFQUNQLE9BQWUsRUFDZixXQUFrQixFQUNsQixpQkFBaUUsRUFDbEUsRUFBRTtJQUNELFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIsVUFBVSxFQUFFLE1BQU0sQ0FBQztJQUNuQixNQUFNLEVBQUUsTUFBTSxDQUFDO0lBQ2YsUUFBUSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2xCLGlCQUFpQixDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQzNCLFdBQVcsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNyQixRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDbEIsa0JBQWtCLENBQUMsRUFBRSxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQ3JDLGFBQWEsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUN2QixPQUFPLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDakIsT0FBTyxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2pCLFdBQVcsQ0FBQyxFQUFFLE9BQU8sQ0FBQztJQUN0QixpQkFBaUIsQ0FBQyxFQUFFLE1BQU0sQ0FBQztDQUM1QixpQkFnSEE7QUFFRDs7O0dBR0c7QUFDSCx3QkFBc0Isb0JBQW9CLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsTUFBTSxpQkFReEUifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../../src/spartan/utils/bot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAWpD,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,iBAa9D;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,EACvC,SAAS,EACT,UAAU,EACV,MAAM,EAAE,GAAG,EACX,QAAY,EACZ,iBAAsB,EACtB,WAAuB,EACvB,QAA2G,EAC3G,kBAAkB,EAClB,aAAsE,EACtE,OAAO,EACP,OAAe,EACf,WAAkB,EAClB,iBAAiE,EAClE,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,iBAgHA;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,iBAQxE"}
@@ -0,0 +1,141 @@
1
+ import { sleep } from '@aztec/foundation/sleep';
2
+ import { exec } from 'child_process';
3
+ import { promisify } from 'util';
4
+ import { execHelmCommand, forceDeleteHelmReleaseRecord, getHelmReleaseStatus, hasDeployedHelmRelease } from './helm.js';
5
+ import { deleteResourceByLabel, getChartDir, waitForResourceByLabel } from './k8s.js';
6
+ const execAsync = promisify(exec);
7
+ export async function restartBot(namespace, log) {
8
+ log.info(`Restarting bot`);
9
+ await deleteResourceByLabel({
10
+ resource: 'pods',
11
+ namespace,
12
+ label: 'app.kubernetes.io/name=bot'
13
+ });
14
+ await sleep(10 * 1000);
15
+ // Some bot images may take time to report Ready due to heavy boot-time proving.
16
+ // Waiting for PodReadyToStartContainers ensures the pod is scheduled and starting without blocking on full readiness.
17
+ await waitForResourceByLabel({
18
+ resource: 'pods',
19
+ namespace,
20
+ label: 'app.kubernetes.io/name=bot',
21
+ condition: 'PodReadyToStartContainers'
22
+ });
23
+ log.info(`Bot restarted`);
24
+ }
25
+ /**
26
+ * Installs or upgrades the transfer bot Helm release for the given namespace.
27
+ * Intended for test setup to enable L2 traffic generation only when needed.
28
+ */ export async function installTransferBot({ namespace, spartanDir, logger: log, replicas = 1, txIntervalSeconds = 10, followChain = 'PENDING', mnemonic = process.env.LABS_INFRA_MNEMONIC ?? 'test test test test test test test test test test test junk', mnemonicStartIndex, botPrivateKey = process.env.BOT_TRANSFERS_L2_PRIVATE_KEY ?? '0xcafe01', nodeUrl, timeout = '15m', reuseValues = true, aztecSlotDuration = Number(process.env.AZTEC_SLOT_DURATION ?? 12) }) {
29
+ const instanceName = `${namespace}-bot-transfers`;
30
+ const helmChartDir = getChartDir(spartanDir, 'aztec-bot');
31
+ const resolvedNodeUrl = nodeUrl ?? `http://${namespace}-rpc-aztec-node.${namespace}.svc.cluster.local:8080`;
32
+ log.info(`Installing/upgrading transfer bot: replicas=${replicas}, followChain=${followChain}`);
33
+ const values = {
34
+ 'bot.replicaCount': replicas,
35
+ 'bot.txIntervalSeconds': txIntervalSeconds,
36
+ 'bot.followChain': followChain,
37
+ 'bot.botPrivateKey': botPrivateKey,
38
+ 'bot.nodeUrl': resolvedNodeUrl,
39
+ 'bot.mnemonic': mnemonic,
40
+ 'bot.feePaymentMethod': 'fee_juice',
41
+ 'aztec.slotDuration': aztecSlotDuration,
42
+ // Ensure bot can reach its own PXE started in-process (default rpc.port is 8080)
43
+ // Note: since aztec-bot depends on aztec-node with alias `bot`, env vars go under `bot.node.env`.
44
+ 'bot.node.env.BOT_PXE_URL': 'http://127.0.0.1:8080',
45
+ // Provide L1 execution RPC for bridging fee juice
46
+ 'bot.node.env.ETHEREUM_HOSTS': `http://${namespace}-eth-execution.${namespace}.svc.cluster.local:8545`,
47
+ // Provide L1 mnemonic for bridging (falls back to labs mnemonic)
48
+ 'bot.node.env.BOT_L1_MNEMONIC': mnemonic,
49
+ // The bot does not need Kubernetes API access. Disable RBAC + ServiceAccount creation so the chart
50
+ // can be installed by users without cluster-scoped RBAC permissions.
51
+ 'bot.rbac.create': false,
52
+ 'bot.serviceAccount.create': false,
53
+ 'bot.serviceAccount.name': 'default'
54
+ };
55
+ // Ensure we derive a funded L1 key (index 0 is funded on anvil default mnemonic)
56
+ if (mnemonicStartIndex === undefined) {
57
+ values['bot.mnemonicStartIndex'] = 0;
58
+ }
59
+ // Also pass a funded private key directly if available
60
+ if (process.env.FUNDING_PRIVATE_KEY) {
61
+ values['bot.node.env.BOT_L1_PRIVATE_KEY'] = process.env.FUNDING_PRIVATE_KEY;
62
+ }
63
+ // Align bot image with the running network image: prefer env var, else detect from a validator pod
64
+ let repositoryFromEnv;
65
+ let tagFromEnv;
66
+ const aztecDockerImage = process.env.AZTEC_DOCKER_IMAGE;
67
+ if (aztecDockerImage && aztecDockerImage.includes(':')) {
68
+ const lastColon = aztecDockerImage.lastIndexOf(':');
69
+ repositoryFromEnv = aztecDockerImage.slice(0, lastColon);
70
+ tagFromEnv = aztecDockerImage.slice(lastColon + 1);
71
+ }
72
+ let repository = repositoryFromEnv;
73
+ let tag = tagFromEnv;
74
+ if (!repository || !tag) {
75
+ try {
76
+ const { stdout } = await execAsync(`kubectl get pods -l app.kubernetes.io/name=validator -n ${namespace} -o jsonpath='{.items[0].spec.containers[?(@.name=="aztec")].image}' | cat`);
77
+ const image = stdout.trim().replace(/^'|'$/g, '');
78
+ if (image && image.includes(':')) {
79
+ const lastColon = image.lastIndexOf(':');
80
+ repository = image.slice(0, lastColon);
81
+ tag = image.slice(lastColon + 1);
82
+ }
83
+ } catch (err) {
84
+ log.warn(`Could not detect aztec image from validator pod: ${String(err)}`);
85
+ }
86
+ }
87
+ if (repository && tag) {
88
+ values['global.aztecImage.repository'] = repository;
89
+ values['global.aztecImage.tag'] = tag;
90
+ }
91
+ if (mnemonicStartIndex !== undefined) {
92
+ values['bot.mnemonicStartIndex'] = typeof mnemonicStartIndex === 'string' ? mnemonicStartIndex : Number(mnemonicStartIndex);
93
+ }
94
+ // If a previous install attempt left the release in a non-deployed state (e.g. FAILED),
95
+ // `helm upgrade --install` can error with "has no deployed releases".
96
+ // In that case, clear the release record and do a clean install.
97
+ const existingStatus = await getHelmReleaseStatus(instanceName, namespace);
98
+ if (existingStatus && existingStatus.toLowerCase() !== 'deployed') {
99
+ log.warn(`Transfer bot release ${instanceName} is in status '${existingStatus}'. Reinstalling cleanly.`);
100
+ await execAsync(`helm uninstall ${instanceName} --namespace ${namespace} --wait --ignore-not-found`).catch(()=>undefined);
101
+ // If helm left the release in `uninstalling`, force-delete the record so we can reinstall.
102
+ const afterUninstallStatus = await getHelmReleaseStatus(instanceName, namespace);
103
+ if (afterUninstallStatus?.toLowerCase() === 'uninstalling') {
104
+ await forceDeleteHelmReleaseRecord(instanceName, namespace, log);
105
+ }
106
+ }
107
+ // `--reuse-values` fails if the release has never successfully deployed (e.g. first install, or a previous failed install).
108
+ // Only reuse values when we have a deployed release to reuse from.
109
+ const effectiveReuseValues = reuseValues && await hasDeployedHelmRelease(instanceName, namespace);
110
+ await execHelmCommand({
111
+ instanceName,
112
+ helmChartDir,
113
+ namespace,
114
+ valuesFile: undefined,
115
+ timeout,
116
+ values: values,
117
+ reuseValues: effectiveReuseValues
118
+ });
119
+ if (replicas > 0) {
120
+ await waitForResourceByLabel({
121
+ resource: 'pods',
122
+ namespace,
123
+ label: 'app.kubernetes.io/name=bot',
124
+ condition: 'PodReadyToStartContainers'
125
+ });
126
+ }
127
+ }
128
+ /**
129
+ * Uninstalls the transfer bot Helm release from the given namespace.
130
+ * Intended for test teardown to clean up bot resources.
131
+ */ export async function uninstallTransferBot(namespace, log) {
132
+ const instanceName = `${namespace}-bot-transfers`;
133
+ log.info(`Uninstalling transfer bot release ${instanceName}`);
134
+ await execAsync(`helm uninstall ${instanceName} --namespace ${namespace} --wait --ignore-not-found`);
135
+ // Ensure any leftover pods are removed
136
+ await deleteResourceByLabel({
137
+ resource: 'pods',
138
+ namespace,
139
+ label: 'app.kubernetes.io/name=bot'
140
+ }).catch(()=>undefined);
141
+ }