@aztec/end-to-end 0.0.1-commit.d3ec352c → 0.0.1-commit.d431d1c

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 (141) 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 +14 -15
  5. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  6. package/dest/bench/client_flows/client_flows_benchmark.js +110 -138
  7. package/dest/bench/client_flows/data_extractor.js +3 -1
  8. package/dest/bench/utils.d.ts +6 -6
  9. package/dest/bench/utils.d.ts.map +1 -1
  10. package/dest/bench/utils.js +18 -11
  11. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +6 -7
  12. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  13. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +98 -113
  14. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +19 -13
  15. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  16. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +91 -71
  17. package/dest/e2e_deploy_contract/deploy_test.d.ts +4 -3
  18. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  19. package/dest/e2e_deploy_contract/deploy_test.js +18 -13
  20. package/dest/e2e_epochs/epochs_test.d.ts +3 -2
  21. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  22. package/dest/e2e_epochs/epochs_test.js +13 -11
  23. package/dest/e2e_fees/bridging_race.notest.js +3 -5
  24. package/dest/e2e_fees/fees_test.d.ts +18 -15
  25. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  26. package/dest/e2e_fees/fees_test.js +126 -141
  27. package/dest/e2e_l1_publisher/write_json.d.ts +3 -3
  28. package/dest/e2e_l1_publisher/write_json.d.ts.map +1 -1
  29. package/dest/e2e_l1_publisher/write_json.js +19 -15
  30. package/dest/e2e_multi_validator/utils.js +1 -1
  31. package/dest/e2e_nested_contract/nested_contract_test.d.ts +6 -9
  32. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  33. package/dest/e2e_nested_contract/nested_contract_test.js +32 -40
  34. package/dest/e2e_p2p/inactivity_slash_test.d.ts +4 -4
  35. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
  36. package/dest/e2e_p2p/inactivity_slash_test.js +6 -9
  37. package/dest/e2e_p2p/p2p_network.d.ts +13 -11
  38. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  39. package/dest/e2e_p2p/p2p_network.js +116 -111
  40. package/dest/e2e_p2p/shared.d.ts +2 -2
  41. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  42. package/dest/e2e_p2p/shared.js +4 -4
  43. package/dest/e2e_token_contract/token_contract_test.d.ts +16 -9
  44. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  45. package/dest/e2e_token_contract/token_contract_test.js +90 -92
  46. package/dest/fixtures/e2e_prover_test.d.ts +10 -18
  47. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  48. package/dest/fixtures/e2e_prover_test.js +88 -103
  49. package/dest/fixtures/fixtures.d.ts +2 -3
  50. package/dest/fixtures/fixtures.d.ts.map +1 -1
  51. package/dest/fixtures/fixtures.js +1 -2
  52. package/dest/fixtures/get_acvm_config.js +1 -1
  53. package/dest/fixtures/l1_to_l2_messaging.d.ts +4 -3
  54. package/dest/fixtures/l1_to_l2_messaging.d.ts.map +1 -1
  55. package/dest/fixtures/l1_to_l2_messaging.js +2 -2
  56. package/dest/fixtures/setup.d.ts +216 -0
  57. package/dest/fixtures/setup.d.ts.map +1 -0
  58. package/dest/fixtures/setup.js +684 -0
  59. package/dest/fixtures/setup_p2p_test.js +3 -3
  60. package/dest/fixtures/utils.d.ts +5 -638
  61. package/dest/fixtures/utils.d.ts.map +1 -1
  62. package/dest/fixtures/utils.js +4 -647
  63. package/dest/fixtures/web3signer.js +1 -1
  64. package/dest/fixtures/with_telemetry_utils.d.ts +2 -2
  65. package/dest/fixtures/with_telemetry_utils.d.ts.map +1 -1
  66. package/dest/fixtures/with_telemetry_utils.js +2 -2
  67. package/dest/quality_of_service/grafana_client.d.ts +41 -0
  68. package/dest/quality_of_service/grafana_client.d.ts.map +1 -0
  69. package/dest/quality_of_service/{alert_checker.js → grafana_client.js} +1 -1
  70. package/dest/quality_of_service/prometheus_client.d.ts +38 -0
  71. package/dest/quality_of_service/prometheus_client.d.ts.map +1 -0
  72. package/dest/quality_of_service/prometheus_client.js +67 -0
  73. package/dest/shared/cross_chain_test_harness.d.ts +16 -4
  74. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  75. package/dest/shared/cross_chain_test_harness.js +3 -3
  76. package/dest/shared/gas_portal_test_harness.d.ts +12 -2
  77. package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
  78. package/dest/shared/index.d.ts +2 -2
  79. package/dest/shared/index.d.ts.map +1 -1
  80. package/dest/shared/uniswap_l1_l2.d.ts +3 -27
  81. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  82. package/dest/shared/uniswap_l1_l2.js +43 -23
  83. package/dest/simulators/lending_simulator.d.ts +6 -2
  84. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  85. package/dest/simulators/lending_simulator.js +1 -1
  86. package/dest/spartan/setup_test_wallets.d.ts +4 -3
  87. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  88. package/dest/spartan/setup_test_wallets.js +2 -1
  89. package/dest/spartan/tx_metrics.d.ts +52 -0
  90. package/dest/spartan/tx_metrics.d.ts.map +1 -0
  91. package/dest/spartan/tx_metrics.js +248 -0
  92. package/dest/spartan/utils.d.ts +51 -12
  93. package/dest/spartan/utils.d.ts.map +1 -1
  94. package/dest/spartan/utils.js +262 -102
  95. package/package.json +40 -39
  96. package/src/bench/client_flows/benchmark.ts +24 -2
  97. package/src/bench/client_flows/client_flows_benchmark.ts +150 -200
  98. package/src/bench/client_flows/data_extractor.ts +1 -1
  99. package/src/bench/utils.ts +22 -14
  100. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +107 -142
  101. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +140 -125
  102. package/src/e2e_deploy_contract/deploy_test.ts +21 -14
  103. package/src/e2e_epochs/epochs_test.ts +26 -13
  104. package/src/e2e_fees/bridging_race.notest.ts +3 -6
  105. package/src/e2e_fees/fees_test.ts +177 -216
  106. package/src/e2e_l1_publisher/write_json.ts +22 -17
  107. package/src/e2e_multi_validator/utils.ts +1 -1
  108. package/src/e2e_nested_contract/nested_contract_test.ts +35 -56
  109. package/src/e2e_p2p/inactivity_slash_test.ts +9 -12
  110. package/src/e2e_p2p/p2p_network.ts +174 -183
  111. package/src/e2e_p2p/shared.ts +11 -6
  112. package/src/e2e_token_contract/token_contract_test.ts +105 -118
  113. package/src/fixtures/e2e_prover_test.ts +112 -144
  114. package/src/fixtures/fixtures.ts +1 -3
  115. package/src/fixtures/get_acvm_config.ts +1 -1
  116. package/src/fixtures/l1_to_l2_messaging.ts +4 -2
  117. package/src/fixtures/setup.ts +1010 -0
  118. package/src/fixtures/setup_p2p_test.ts +3 -3
  119. package/src/fixtures/utils.ts +27 -966
  120. package/src/fixtures/web3signer.ts +1 -1
  121. package/src/fixtures/with_telemetry_utils.ts +2 -2
  122. package/src/quality_of_service/{alert_checker.ts → grafana_client.ts} +1 -1
  123. package/src/quality_of_service/prometheus_client.ts +113 -0
  124. package/src/shared/cross_chain_test_harness.ts +6 -10
  125. package/src/shared/gas_portal_test_harness.ts +1 -1
  126. package/src/shared/index.ts +1 -1
  127. package/src/shared/uniswap_l1_l2.ts +53 -67
  128. package/src/simulators/lending_simulator.ts +2 -2
  129. package/src/spartan/setup_test_wallets.ts +9 -2
  130. package/src/spartan/tx_metrics.ts +231 -0
  131. package/src/spartan/utils.ts +308 -45
  132. package/dest/fixtures/setup_l1_contracts.d.ts +0 -477
  133. package/dest/fixtures/setup_l1_contracts.d.ts.map +0 -1
  134. package/dest/fixtures/setup_l1_contracts.js +0 -17
  135. package/dest/fixtures/snapshot_manager.d.ts +0 -95
  136. package/dest/fixtures/snapshot_manager.d.ts.map +0 -1
  137. package/dest/fixtures/snapshot_manager.js +0 -505
  138. package/dest/quality_of_service/alert_checker.d.ts +0 -41
  139. package/dest/quality_of_service/alert_checker.d.ts.map +0 -1
  140. package/src/fixtures/setup_l1_contracts.ts +0 -26
  141. package/src/fixtures/snapshot_manager.ts +0 -665
@@ -18,7 +18,9 @@ const testConfigSchema = z.object({
18
18
  L1_RPC_URLS_JSON: z.string().optional(),
19
19
  L1_ACCOUNT_MNEMONIC: z.string().optional(),
20
20
  AZTEC_SLOT_DURATION: z.coerce.number().optional().default(24),
21
- AZTEC_PROOF_SUBMISSION_WINDOW: z.coerce.number().optional().default(5)
21
+ AZTEC_EPOCH_DURATION: z.coerce.number().optional().default(32),
22
+ AZTEC_PROOF_SUBMISSION_WINDOW: z.coerce.number().optional().default(5),
23
+ AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: z.coerce.number().optional().default(2)
22
24
  });
23
25
  export function setupEnvironment(env) {
24
26
  const config = testConfigSchema.parse(env);
@@ -91,7 +93,7 @@ export async function startPortForward({ resource, namespace, containerPort, hos
91
93
  ]
92
94
  });
93
95
  let isResolved = false;
94
- const connected = new Promise((resolve)=>{
96
+ const connected = new Promise((resolve, reject)=>{
95
97
  process1.stdout?.on('data', (data)=>{
96
98
  const str = data.toString();
97
99
  if (!isResolved && str.includes('Forwarding from')) {
@@ -99,7 +101,8 @@ export async function startPortForward({ resource, namespace, containerPort, hos
99
101
  logger.debug(`Port forward for ${resource}: ${str}`);
100
102
  const port = str.search(/:\d+/);
101
103
  if (port === -1) {
102
- throw new Error('Port not found in port forward output');
104
+ reject(new Error('Port not found in port forward output'));
105
+ return;
103
106
  }
104
107
  const portNumber = parseInt(str.slice(port + 1));
105
108
  logger.verbose(`Port forwarded for ${resource} at ${portNumber}:${containerPort}`);
@@ -119,17 +122,26 @@ export async function startPortForward({ resource, namespace, containerPort, hos
119
122
  process1.on('close', ()=>{
120
123
  if (!isResolved) {
121
124
  isResolved = true;
122
- logger.warn(`Port forward for ${resource} closed before connection established`);
123
- resolve(0);
125
+ const msg = `Port forward for ${resource} closed before connection established`;
126
+ logger.warn(msg);
127
+ reject(new Error(msg));
124
128
  }
125
129
  });
126
130
  process1.on('error', (error)=>{
127
- logger.error(`Port forward for ${resource} error: ${error}`);
128
- resolve(0);
131
+ if (!isResolved) {
132
+ isResolved = true;
133
+ const msg = `Port forward for ${resource} error: ${error}`;
134
+ logger.error(msg);
135
+ reject(new Error(msg));
136
+ }
129
137
  });
130
138
  process1.on('exit', (code)=>{
131
- logger.verbose(`Port forward for ${resource} exited with code ${code}`);
132
- resolve(0);
139
+ if (!isResolved) {
140
+ isResolved = true;
141
+ const msg = `Port forward for ${resource} exited with code ${code}`;
142
+ logger.verbose(msg);
143
+ reject(new Error(msg));
144
+ }
133
145
  });
134
146
  });
135
147
  const port = await connected;
@@ -164,6 +176,13 @@ export function getExternalIP(namespace, serviceName) {
164
176
  });
165
177
  return promise;
166
178
  }
179
+ export function startPortForwardForPrometeheus(namespace) {
180
+ return startPortForward({
181
+ resource: `svc/${namespace}-prometheus-server`,
182
+ namespace,
183
+ containerPort: 80
184
+ });
185
+ }
167
186
  export function startPortForwardForRPC(namespace, index = 0) {
168
187
  return startPortForward({
169
188
  resource: `pod/${namespace}-rpc-aztec-node-${index}`,
@@ -185,9 +204,11 @@ export async function deleteResourceByName({ resource, namespace, name, force =
185
204
  return stdout;
186
205
  }
187
206
  export async function deleteResourceByLabel({ resource, namespace, label, timeout = '5m', force = false }) {
188
- // Check if the resource type exists before attempting to delete
189
207
  try {
190
- await execAsync(`kubectl api-resources --api-group="" --no-headers -o name | grep -q "^${resource}$" || kubectl api-resources --no-headers -o name | grep -q "^${resource}$"`);
208
+ // Match both plain and group-qualified names (e.g., "podchaos" or "podchaos.chaos-mesh.org")
209
+ const escaped = resource.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
210
+ const regex = `(^|\\.)${escaped}(\\.|$)`;
211
+ await execAsync(`kubectl api-resources --no-headers -o name | grep -Eq '${regex}'`);
191
212
  } catch (error) {
192
213
  logger.warn(`Resource type '${resource}' not found in cluster, skipping deletion ${error}`);
193
214
  return '';
@@ -203,6 +224,31 @@ export async function waitForResourceByLabel({ resource, label, namespace, condi
203
224
  const { stdout } = await execAsync(command);
204
225
  return stdout;
205
226
  }
227
+ export async function waitForResourceByName({ resource, name, namespace, condition = 'Ready', timeout = '10m' }) {
228
+ const command = `kubectl wait ${resource}/${name} --for=condition=${condition} -n ${namespace} --timeout=${timeout}`;
229
+ logger.info(`command: ${command}`);
230
+ const { stdout } = await execAsync(command);
231
+ return stdout;
232
+ }
233
+ export async function waitForResourcesByName({ resource, names, namespace, condition = 'Ready', timeout = '10m' }) {
234
+ if (!names.length) {
235
+ throw new Error(`No ${resource} names provided to waitForResourcesByName`);
236
+ }
237
+ // Wait all in parallel; if any fails, surface which one.
238
+ await Promise.all(names.map(async (name)=>{
239
+ try {
240
+ await waitForResourceByName({
241
+ resource,
242
+ name,
243
+ namespace,
244
+ condition,
245
+ timeout
246
+ });
247
+ } catch (err) {
248
+ throw new Error(`Failed waiting for ${resource}/${name} condition=${condition} timeout=${timeout} namespace=${namespace}: ${String(err)}`);
249
+ }
250
+ }));
251
+ }
206
252
  export function getChartDir(spartanDir, chartName) {
207
253
  return path.join(spartanDir.trim(), chartName);
208
254
  }
@@ -224,7 +270,31 @@ async function execHelmCommand(args) {
224
270
  const { stdout } = await execAsync(helmCommand);
225
271
  return stdout;
226
272
  }
227
- export async function cleanHelm(instanceName, namespace, logger) {
273
+ async function getHelmReleaseStatus(instanceName, namespace) {
274
+ try {
275
+ const { stdout } = await execAsync(`helm list --namespace ${namespace} --all --filter '^${instanceName}$' --output json | cat`);
276
+ const parsed = JSON.parse(stdout);
277
+ const row = parsed.find((r)=>r.name === instanceName);
278
+ return row?.status;
279
+ } catch {
280
+ return undefined;
281
+ }
282
+ }
283
+ async function forceDeleteHelmReleaseRecord(instanceName, namespace, logger) {
284
+ const labelSelector = `owner=helm,name=${instanceName}`;
285
+ const cmd = `kubectl delete secret -n ${namespace} -l ${labelSelector} --ignore-not-found=true`;
286
+ logger.warn(`Force deleting Helm release record: ${cmd}`);
287
+ await execAsync(cmd).catch(()=>undefined);
288
+ }
289
+ async function hasDeployedHelmRelease(instanceName, namespace) {
290
+ try {
291
+ const status = await getHelmReleaseStatus(instanceName, namespace);
292
+ return status?.toLowerCase() === 'deployed';
293
+ } catch {
294
+ return false;
295
+ }
296
+ }
297
+ export async function uninstallChaosMesh(instanceName, namespace, logger) {
228
298
  // uninstall the helm chart if it exists
229
299
  logger.info(`Uninstalling helm chart ${instanceName}`);
230
300
  await execAsync(`helm uninstall ${instanceName} --namespace ${namespace} --wait --ignore-not-found`);
@@ -269,7 +339,7 @@ export async function cleanHelm(instanceName, namespace, logger) {
269
339
  * ```
270
340
  */ export async function installChaosMeshChart({ instanceName, targetNamespace, valuesFile, helmChartDir, timeout = '10m', clean = true, values = {}, logger }) {
271
341
  if (clean) {
272
- await cleanHelm(instanceName, targetNamespace, logger);
342
+ await uninstallChaosMesh(instanceName, targetNamespace, logger);
273
343
  }
274
344
  return execHelmCommand({
275
345
  instanceName,
@@ -295,51 +365,66 @@ export function applyProverFailure({ namespace, spartanDir, durationSeconds, log
295
365
  logger
296
366
  });
297
367
  }
298
- export function applyProverKill({ namespace, spartanDir, logger }) {
368
+ export function applyValidatorFailure({ namespace, spartanDir, logger, values, instanceName }) {
369
+ return installChaosMeshChart({
370
+ instanceName: instanceName ?? 'validator-failure',
371
+ targetNamespace: namespace,
372
+ valuesFile: 'validator-failure.yaml',
373
+ helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
374
+ values,
375
+ logger
376
+ });
377
+ }
378
+ export function applyProverKill({ namespace, spartanDir, logger, values }) {
299
379
  return installChaosMeshChart({
300
380
  instanceName: 'prover-kill',
301
381
  targetNamespace: namespace,
302
382
  valuesFile: 'prover-kill.yaml',
303
383
  helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
384
+ chaosMeshNamespace: namespace,
304
385
  clean: true,
305
- logger
386
+ logger,
387
+ values
306
388
  });
307
389
  }
308
- export function applyProverBrokerKill({ namespace, spartanDir, logger }) {
390
+ export function applyProverBrokerKill({ namespace, spartanDir, logger, values }) {
309
391
  return installChaosMeshChart({
310
392
  instanceName: 'prover-broker-kill',
311
393
  targetNamespace: namespace,
312
394
  valuesFile: 'prover-broker-kill.yaml',
313
395
  helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
314
396
  clean: true,
315
- logger
397
+ logger,
398
+ values
316
399
  });
317
400
  }
318
- export function applyBootNodeFailure({ namespace, spartanDir, durationSeconds, logger }) {
401
+ export function applyBootNodeFailure({ instanceName = 'boot-node-failure', namespace, spartanDir, durationSeconds, logger, values }) {
319
402
  return installChaosMeshChart({
320
- instanceName: 'boot-node-failure',
403
+ instanceName,
321
404
  targetNamespace: namespace,
322
405
  valuesFile: 'boot-node-failure.yaml',
323
406
  helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
324
407
  values: {
325
- 'bootNodeFailure.duration': `${durationSeconds}s`
408
+ 'bootNodeFailure.duration': `${durationSeconds}s`,
409
+ ...values ?? {}
326
410
  },
327
411
  logger
328
412
  });
329
413
  }
330
- export function applyValidatorKill({ namespace, spartanDir, logger, values }) {
414
+ export function applyValidatorKill({ instanceName = 'validator-kill', namespace, spartanDir, logger, values, clean = true }) {
331
415
  return installChaosMeshChart({
332
- instanceName: 'validator-kill',
416
+ instanceName: instanceName ?? 'validator-kill',
333
417
  targetNamespace: namespace,
334
418
  valuesFile: 'validator-kill.yaml',
335
419
  helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
420
+ clean,
336
421
  logger,
337
422
  values
338
423
  });
339
424
  }
340
- export function applyNetworkShaping({ valuesFile, namespace, spartanDir, logger }) {
425
+ export function applyNetworkShaping({ instanceName = 'network-shaping', valuesFile, namespace, spartanDir, logger }) {
341
426
  return installChaosMeshChart({
342
- instanceName: 'network-shaping',
427
+ instanceName,
343
428
  targetNamespace: namespace,
344
429
  valuesFile,
345
430
  helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
@@ -402,7 +487,12 @@ export async function restartBot(namespace, logger) {
402
487
  // Provide L1 execution RPC for bridging fee juice
403
488
  'bot.node.env.ETHEREUM_HOSTS': `http://${namespace}-eth-execution.${namespace}.svc.cluster.local:8545`,
404
489
  // Provide L1 mnemonic for bridging (falls back to labs mnemonic)
405
- 'bot.node.env.BOT_L1_MNEMONIC': mnemonic
490
+ 'bot.node.env.BOT_L1_MNEMONIC': mnemonic,
491
+ // The bot does not need Kubernetes API access. Disable RBAC + ServiceAccount creation so the chart
492
+ // can be installed by users without cluster-scoped RBAC permissions.
493
+ 'bot.rbac.create': false,
494
+ 'bot.serviceAccount.create': false,
495
+ 'bot.serviceAccount.name': 'default'
406
496
  };
407
497
  // Ensure we derive a funded L1 key (index 0 is funded on anvil default mnemonic)
408
498
  if (mnemonicStartIndex === undefined) {
@@ -425,7 +515,7 @@ export async function restartBot(namespace, logger) {
425
515
  let tag = tagFromEnv;
426
516
  if (!repository || !tag) {
427
517
  try {
428
- const { stdout } = await execAsync(`kubectl get pods -l app.kubernetes.io/component=validator -n ${namespace} -o jsonpath='{.items[0].spec.containers[?(@.name=="aztec")].image}' | cat`);
518
+ 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`);
429
519
  const image = stdout.trim().replace(/^'|'$/g, '');
430
520
  if (image && image.includes(':')) {
431
521
  const lastColon = image.lastIndexOf(':');
@@ -443,6 +533,22 @@ export async function restartBot(namespace, logger) {
443
533
  if (mnemonicStartIndex !== undefined) {
444
534
  values['bot.mnemonicStartIndex'] = typeof mnemonicStartIndex === 'string' ? mnemonicStartIndex : Number(mnemonicStartIndex);
445
535
  }
536
+ // If a previous install attempt left the release in a non-deployed state (e.g. FAILED),
537
+ // `helm upgrade --install` can error with "has no deployed releases".
538
+ // In that case, clear the release record and do a clean install.
539
+ const existingStatus = await getHelmReleaseStatus(instanceName, namespace);
540
+ if (existingStatus && existingStatus.toLowerCase() !== 'deployed') {
541
+ logger.warn(`Transfer bot release ${instanceName} is in status '${existingStatus}'. Reinstalling cleanly.`);
542
+ await execAsync(`helm uninstall ${instanceName} --namespace ${namespace} --wait --ignore-not-found`).catch(()=>undefined);
543
+ // If helm left the release in `uninstalling`, force-delete the record so we can reinstall.
544
+ const afterUninstallStatus = await getHelmReleaseStatus(instanceName, namespace);
545
+ if (afterUninstallStatus?.toLowerCase() === 'uninstalling') {
546
+ await forceDeleteHelmReleaseRecord(instanceName, namespace, logger);
547
+ }
548
+ }
549
+ // `--reuse-values` fails if the release has never successfully deployed (e.g. first install, or a previous failed install).
550
+ // Only reuse values when we have a deployed release to reuse from.
551
+ const effectiveReuseValues = reuseValues && await hasDeployedHelmRelease(instanceName, namespace);
446
552
  await execHelmCommand({
447
553
  instanceName,
448
554
  helmChartDir,
@@ -450,7 +556,7 @@ export async function restartBot(namespace, logger) {
450
556
  valuesFile: undefined,
451
557
  timeout,
452
558
  values: values,
453
- reuseValues
559
+ reuseValues: effectiveReuseValues
454
560
  });
455
561
  if (replicas > 0) {
456
562
  await waitForResourceByLabel({
@@ -482,8 +588,9 @@ export async function restartBot(namespace, logger) {
482
588
  const drop = enabled ? 'true' : 'false';
483
589
  const prob = String(probability);
484
590
  const selectors = [
485
- 'app=validator',
486
- 'app.kubernetes.io/component=validator'
591
+ 'app.kubernetes.io/name=validator',
592
+ 'app.kubernetes.io/component=validator',
593
+ 'app=validator'
487
594
  ];
488
595
  let updated = false;
489
596
  for (const selector of selectors){
@@ -510,8 +617,9 @@ export async function restartBot(namespace, logger) {
510
617
  }
511
618
  export async function restartValidators(namespace, logger) {
512
619
  const selectors = [
513
- 'app=validator',
514
- 'app.kubernetes.io/component=validator'
620
+ 'app.kubernetes.io/name=validator',
621
+ 'app.kubernetes.io/component=validator',
622
+ 'app=validator'
515
623
  ];
516
624
  let any = false;
517
625
  for (const selector of selectors){
@@ -565,11 +673,27 @@ export async function enableValidatorDynamicBootNode(instanceName, namespace, sp
565
673
  logger.info(`Validator dynamic boot node enabled`);
566
674
  }
567
675
  export async function getSequencers(namespace) {
568
- const command = `kubectl get pods -l app.kubernetes.io/component=validator -n ${namespace} -o jsonpath='{.items[*].metadata.name}'`;
569
- const { stdout } = await execAsync(command);
570
- const sequencers = stdout.split(' ');
571
- logger.verbose(`Found sequencer pods ${sequencers.join(', ')}`);
572
- return sequencers;
676
+ const selectors = [
677
+ 'app.kubernetes.io/name=validator',
678
+ 'app.kubernetes.io/component=validator',
679
+ 'app.kubernetes.io/component=sequencer-node',
680
+ 'app=validator'
681
+ ];
682
+ for (const selector of selectors){
683
+ try {
684
+ const command = `kubectl get pods -l ${selector} -n ${namespace} -o jsonpath='{.items[*].metadata.name}'`;
685
+ const { stdout } = await execAsync(command);
686
+ const sequencers = stdout.split(' ').map((s)=>s.trim()).filter(Boolean);
687
+ if (sequencers.length > 0) {
688
+ logger.verbose(`Found sequencer pods ${sequencers.join(', ')} (selector=${selector})`);
689
+ return sequencers;
690
+ }
691
+ } catch {
692
+ // try next selector
693
+ }
694
+ }
695
+ // Fail fast instead of returning [''] which leads to attempts to port-forward `pod/`.
696
+ throw new Error(`No sequencer/validator pods found in namespace ${namespace}. Tried selectors: ${selectors.join(', ')}`);
573
697
  }
574
698
  export function updateSequencersConfig(env, config) {
575
699
  return withSequencersAdmin(env, async (client)=>{
@@ -619,7 +743,9 @@ export async function withSequencersAdmin(env, fn) {
619
743
  const url = `http://127.0.0.1:${port}`;
620
744
  const client = createPublicClient({
621
745
  transport: fallback([
622
- http(url)
746
+ http(url, {
747
+ batch: false
748
+ })
623
749
  ])
624
750
  });
625
751
  if (processes) {
@@ -637,7 +763,9 @@ export async function withSequencersAdmin(env, fn) {
637
763
  }
638
764
  const client = createPublicClient({
639
765
  transport: fallback([
640
- http(L1_RPC_URLS_JSON)
766
+ http(L1_RPC_URLS_JSON, {
767
+ batch: false
768
+ })
641
769
  ])
642
770
  });
643
771
  return {
@@ -670,71 +798,103 @@ export async function withSequencersAdmin(env, fn) {
670
798
  /**
671
799
  * Rolls the Aztec pods in the given namespace.
672
800
  * @param namespace - The namespace to roll the Aztec pods in.
673
- * @dev - IMPORTANT: This function DOES NOT delete the underlying PVCs.
674
- * This means that the pods will be restarted with the same persistent storage.
675
- * This is useful for testing, but you should be aware of the implications.
676
- */ export async function rollAztecPods(namespace) {
677
- await deleteResourceByLabel({
678
- resource: 'pods',
679
- namespace: namespace,
680
- label: 'app=boot-node'
681
- });
682
- await deleteResourceByLabel({
683
- resource: 'pods',
684
- namespace: namespace,
685
- label: 'app=prover-node'
686
- });
687
- await deleteResourceByLabel({
688
- resource: 'pods',
689
- namespace: namespace,
690
- label: 'app=prover-broker'
691
- });
692
- await deleteResourceByLabel({
693
- resource: 'pods',
694
- namespace: namespace,
695
- label: 'app=prover-agent'
696
- });
697
- await deleteResourceByLabel({
698
- resource: 'pods',
699
- namespace: namespace,
700
- label: 'app=validator'
701
- });
702
- await deleteResourceByLabel({
703
- resource: 'pods',
704
- namespace: namespace,
705
- label: 'app=pxe'
706
- });
801
+ * @param clearState - If true, also deletes the underlying PVCs to clear persistent storage.
802
+ * This is required for rollup upgrades where the old state is incompatible with the new rollup.
803
+ * Defaults to false, which preserves the existing storage.
804
+ */ export async function rollAztecPods(namespace, clearState = false) {
805
+ // Pod components use 'validator', but StatefulSets and PVCs use 'sequencer-node' for validators
806
+ const podComponents = [
807
+ 'p2p-bootstrap',
808
+ 'prover-node',
809
+ 'prover-broker',
810
+ 'prover-agent',
811
+ 'sequencer-node',
812
+ 'rpc'
813
+ ];
814
+ const pvcComponents = [
815
+ 'p2p-bootstrap',
816
+ 'prover-node',
817
+ 'prover-broker',
818
+ 'sequencer-node',
819
+ 'rpc'
820
+ ];
821
+ // StatefulSet components that need to be scaled down before PVC deletion
822
+ // Note: validators use 'sequencer-node' as component label, not 'validator'
823
+ const statefulSetComponents = [
824
+ 'p2p-bootstrap',
825
+ 'prover-node',
826
+ 'prover-broker',
827
+ 'sequencer-node',
828
+ 'rpc'
829
+ ];
830
+ if (clearState) {
831
+ // To delete PVCs, we must first scale down StatefulSets so pods release the volumes
832
+ // Otherwise PVC deletion will hang waiting for pods to terminate
833
+ // First, save original replica counts
834
+ const originalReplicas = new Map();
835
+ for (const component of statefulSetComponents){
836
+ try {
837
+ const getCmd = `kubectl get statefulset -l app.kubernetes.io/component=${component} -n ${namespace} -o jsonpath='{.items[0].spec.replicas}'`;
838
+ const { stdout } = await execAsync(getCmd);
839
+ const replicas = parseInt(stdout.replace(/'/g, '').trim(), 10);
840
+ if (!isNaN(replicas) && replicas > 0) {
841
+ originalReplicas.set(component, replicas);
842
+ }
843
+ } catch {
844
+ // Component might not exist, continue
845
+ }
846
+ }
847
+ // Scale down to 0
848
+ for (const component of statefulSetComponents){
849
+ try {
850
+ const scaleCmd = `kubectl scale statefulset -l app.kubernetes.io/component=${component} -n ${namespace} --replicas=0 --timeout=2m`;
851
+ logger.info(`command: ${scaleCmd}`);
852
+ await execAsync(scaleCmd);
853
+ } catch (e) {
854
+ // Component might not exist or might be a Deployment, continue
855
+ logger.verbose(`Scale down ${component} skipped: ${e}`);
856
+ }
857
+ }
858
+ // Wait for pods to terminate
859
+ await sleep(15 * 1000);
860
+ // Now delete PVCs (they should no longer be in use)
861
+ for (const component of pvcComponents){
862
+ await deleteResourceByLabel({
863
+ resource: 'persistentvolumeclaims',
864
+ namespace: namespace,
865
+ label: `app.kubernetes.io/component=${component}`
866
+ });
867
+ }
868
+ // Scale StatefulSets back up to original replica counts
869
+ for (const component of statefulSetComponents){
870
+ const replicas = originalReplicas.get(component) ?? 1;
871
+ try {
872
+ const scaleCmd = `kubectl scale statefulset -l app.kubernetes.io/component=${component} -n ${namespace} --replicas=${replicas} --timeout=2m`;
873
+ logger.info(`command: ${scaleCmd}`);
874
+ await execAsync(scaleCmd);
875
+ } catch (e) {
876
+ logger.verbose(`Scale up ${component} skipped: ${e}`);
877
+ }
878
+ }
879
+ } else {
880
+ // Just delete pods (no state clearing)
881
+ for (const component of podComponents){
882
+ await deleteResourceByLabel({
883
+ resource: 'pods',
884
+ namespace: namespace,
885
+ label: `app.kubernetes.io/component=${component}`
886
+ });
887
+ }
888
+ }
707
889
  await sleep(10 * 1000);
708
- await waitForResourceByLabel({
709
- resource: 'pods',
710
- namespace: namespace,
711
- label: 'app=boot-node'
712
- });
713
- await waitForResourceByLabel({
714
- resource: 'pods',
715
- namespace: namespace,
716
- label: 'app=prover-node'
717
- });
718
- await waitForResourceByLabel({
719
- resource: 'pods',
720
- namespace: namespace,
721
- label: 'app=prover-broker'
722
- });
723
- await waitForResourceByLabel({
724
- resource: 'pods',
725
- namespace: namespace,
726
- label: 'app=prover-agent'
727
- });
728
- await waitForResourceByLabel({
729
- resource: 'pods',
730
- namespace: namespace,
731
- label: 'app=validator'
732
- });
733
- await waitForResourceByLabel({
734
- resource: 'pods',
735
- namespace: namespace,
736
- label: 'app=pxe'
737
- });
890
+ // Wait for pods to come back
891
+ for (const component of podComponents){
892
+ await waitForResourceByLabel({
893
+ resource: 'pods',
894
+ namespace: namespace,
895
+ label: `app.kubernetes.io/component=${component}`
896
+ });
897
+ }
738
898
  }
739
899
  /**
740
900
  * Returns the absolute path to the git repository root
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/end-to-end",
3
- "version": "0.0.1-commit.d3ec352c",
3
+ "version": "0.0.1-commit.d431d1c",
4
4
  "type": "module",
5
5
  "exports": "./dest/index.js",
6
6
  "inherits": [
@@ -25,43 +25,44 @@
25
25
  "formatting": "run -T prettier --check ./src && run -T eslint ./src"
26
26
  },
27
27
  "dependencies": {
28
- "@aztec/accounts": "0.0.1-commit.d3ec352c",
29
- "@aztec/archiver": "0.0.1-commit.d3ec352c",
30
- "@aztec/aztec": "0.0.1-commit.d3ec352c",
31
- "@aztec/aztec-node": "0.0.1-commit.d3ec352c",
32
- "@aztec/aztec.js": "0.0.1-commit.d3ec352c",
33
- "@aztec/bb-prover": "0.0.1-commit.d3ec352c",
34
- "@aztec/bb.js": "0.0.1-commit.d3ec352c",
35
- "@aztec/blob-lib": "0.0.1-commit.d3ec352c",
36
- "@aztec/blob-sink": "0.0.1-commit.d3ec352c",
37
- "@aztec/bot": "0.0.1-commit.d3ec352c",
38
- "@aztec/cli": "0.0.1-commit.d3ec352c",
39
- "@aztec/constants": "0.0.1-commit.d3ec352c",
40
- "@aztec/entrypoints": "0.0.1-commit.d3ec352c",
41
- "@aztec/epoch-cache": "0.0.1-commit.d3ec352c",
42
- "@aztec/ethereum": "0.0.1-commit.d3ec352c",
43
- "@aztec/foundation": "0.0.1-commit.d3ec352c",
44
- "@aztec/kv-store": "0.0.1-commit.d3ec352c",
45
- "@aztec/l1-artifacts": "0.0.1-commit.d3ec352c",
46
- "@aztec/merkle-tree": "0.0.1-commit.d3ec352c",
47
- "@aztec/node-keystore": "0.0.1-commit.d3ec352c",
48
- "@aztec/noir-contracts.js": "0.0.1-commit.d3ec352c",
49
- "@aztec/noir-noirc_abi": "0.0.1-commit.d3ec352c",
50
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.d3ec352c",
51
- "@aztec/noir-test-contracts.js": "0.0.1-commit.d3ec352c",
52
- "@aztec/p2p": "0.0.1-commit.d3ec352c",
53
- "@aztec/protocol-contracts": "0.0.1-commit.d3ec352c",
54
- "@aztec/prover-client": "0.0.1-commit.d3ec352c",
55
- "@aztec/prover-node": "0.0.1-commit.d3ec352c",
56
- "@aztec/pxe": "0.0.1-commit.d3ec352c",
57
- "@aztec/sequencer-client": "0.0.1-commit.d3ec352c",
58
- "@aztec/simulator": "0.0.1-commit.d3ec352c",
59
- "@aztec/slasher": "0.0.1-commit.d3ec352c",
60
- "@aztec/stdlib": "0.0.1-commit.d3ec352c",
61
- "@aztec/telemetry-client": "0.0.1-commit.d3ec352c",
62
- "@aztec/test-wallet": "0.0.1-commit.d3ec352c",
63
- "@aztec/validator-client": "0.0.1-commit.d3ec352c",
64
- "@aztec/world-state": "0.0.1-commit.d3ec352c",
28
+ "@aztec/accounts": "0.0.1-commit.d431d1c",
29
+ "@aztec/archiver": "0.0.1-commit.d431d1c",
30
+ "@aztec/aztec": "0.0.1-commit.d431d1c",
31
+ "@aztec/aztec-node": "0.0.1-commit.d431d1c",
32
+ "@aztec/aztec.js": "0.0.1-commit.d431d1c",
33
+ "@aztec/bb-prover": "0.0.1-commit.d431d1c",
34
+ "@aztec/bb.js": "0.0.1-commit.d431d1c",
35
+ "@aztec/blob-client": "0.0.1-commit.d431d1c",
36
+ "@aztec/blob-lib": "0.0.1-commit.d431d1c",
37
+ "@aztec/bot": "0.0.1-commit.d431d1c",
38
+ "@aztec/cli": "0.0.1-commit.d431d1c",
39
+ "@aztec/constants": "0.0.1-commit.d431d1c",
40
+ "@aztec/entrypoints": "0.0.1-commit.d431d1c",
41
+ "@aztec/epoch-cache": "0.0.1-commit.d431d1c",
42
+ "@aztec/ethereum": "0.0.1-commit.d431d1c",
43
+ "@aztec/foundation": "0.0.1-commit.d431d1c",
44
+ "@aztec/kv-store": "0.0.1-commit.d431d1c",
45
+ "@aztec/l1-artifacts": "0.0.1-commit.d431d1c",
46
+ "@aztec/merkle-tree": "0.0.1-commit.d431d1c",
47
+ "@aztec/node-keystore": "0.0.1-commit.d431d1c",
48
+ "@aztec/noir-contracts.js": "0.0.1-commit.d431d1c",
49
+ "@aztec/noir-noirc_abi": "0.0.1-commit.d431d1c",
50
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.d431d1c",
51
+ "@aztec/noir-test-contracts.js": "0.0.1-commit.d431d1c",
52
+ "@aztec/p2p": "0.0.1-commit.d431d1c",
53
+ "@aztec/protocol-contracts": "0.0.1-commit.d431d1c",
54
+ "@aztec/prover-client": "0.0.1-commit.d431d1c",
55
+ "@aztec/prover-node": "0.0.1-commit.d431d1c",
56
+ "@aztec/pxe": "0.0.1-commit.d431d1c",
57
+ "@aztec/sequencer-client": "0.0.1-commit.d431d1c",
58
+ "@aztec/simulator": "0.0.1-commit.d431d1c",
59
+ "@aztec/slasher": "0.0.1-commit.d431d1c",
60
+ "@aztec/stdlib": "0.0.1-commit.d431d1c",
61
+ "@aztec/telemetry-client": "0.0.1-commit.d431d1c",
62
+ "@aztec/test-wallet": "0.0.1-commit.d431d1c",
63
+ "@aztec/validator-client": "0.0.1-commit.d431d1c",
64
+ "@aztec/validator-ha-signer": "0.0.1-commit.d431d1c",
65
+ "@aztec/world-state": "0.0.1-commit.d431d1c",
65
66
  "@iarna/toml": "^2.2.5",
66
67
  "@jest/globals": "^30.0.0",
67
68
  "@noble/curves": "=1.0.0",
@@ -107,7 +108,7 @@
107
108
  "@types/jest": "^30.0.0",
108
109
  "@types/js-yaml": "^4.0.9",
109
110
  "@types/lodash.chunk": "^4.2.9",
110
- "@typescript/native-preview": "7.0.0-dev.20251126.1",
111
+ "@typescript/native-preview": "7.0.0-dev.20260113.1",
111
112
  "concurrently": "^7.6.0",
112
113
  "jest": "^30.0.0",
113
114
  "jest-extended": "^6.0.0",