@aztec/end-to-end 0.0.1-commit.8c0b8ff → 0.0.1-commit.8cb2d04d8

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 (86) hide show
  1. package/dest/bench/client_flows/client_flows_benchmark.d.ts +1 -1
  2. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  3. package/dest/bench/client_flows/client_flows_benchmark.js +11 -25
  4. package/dest/e2e_epochs/epochs_test.js +3 -3
  5. package/dest/e2e_p2p/inactivity_slash_test.d.ts +1 -1
  6. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
  7. package/dest/e2e_p2p/inactivity_slash_test.js +2 -3
  8. package/dest/e2e_p2p/p2p_network.d.ts +6 -8
  9. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  10. package/dest/e2e_p2p/p2p_network.js +15 -14
  11. package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
  12. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  13. package/dest/e2e_p2p/reqresp/utils.js +16 -3
  14. package/dest/e2e_p2p/shared.d.ts +5 -19
  15. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  16. package/dest/e2e_p2p/shared.js +16 -65
  17. package/dest/fixtures/e2e_prover_test.d.ts +4 -3
  18. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  19. package/dest/fixtures/e2e_prover_test.js +7 -12
  20. package/dest/fixtures/elu_monitor.d.ts +21 -0
  21. package/dest/fixtures/elu_monitor.d.ts.map +1 -0
  22. package/dest/fixtures/elu_monitor.js +102 -0
  23. package/dest/fixtures/get_bb_config.d.ts +1 -1
  24. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  25. package/dest/fixtures/get_bb_config.js +5 -5
  26. package/dest/fixtures/setup.d.ts +11 -7
  27. package/dest/fixtures/setup.d.ts.map +1 -1
  28. package/dest/fixtures/setup.js +11 -9
  29. package/dest/fixtures/setup_p2p_test.d.ts +6 -6
  30. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  31. package/dest/fixtures/setup_p2p_test.js +8 -8
  32. package/dest/fixtures/token_utils.d.ts +1 -1
  33. package/dest/fixtures/token_utils.d.ts.map +1 -1
  34. package/dest/fixtures/token_utils.js +2 -5
  35. package/dest/shared/gas_portal_test_harness.js +1 -1
  36. package/dest/shared/jest_setup.js +41 -1
  37. package/dest/shared/submit-transactions.d.ts +1 -1
  38. package/dest/shared/submit-transactions.d.ts.map +1 -1
  39. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  40. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  41. package/dest/shared/uniswap_l1_l2.js +0 -4
  42. package/dest/simulators/token_simulator.js +1 -1
  43. package/dest/spartan/setup_test_wallets.d.ts +1 -1
  44. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  45. package/dest/spartan/setup_test_wallets.js +58 -40
  46. package/dest/spartan/tx_metrics.js +1 -1
  47. package/dest/spartan/utils/config.d.ts +7 -1
  48. package/dest/spartan/utils/config.d.ts.map +1 -1
  49. package/dest/spartan/utils/config.js +3 -1
  50. package/dest/spartan/utils/index.d.ts +2 -1
  51. package/dest/spartan/utils/index.d.ts.map +1 -1
  52. package/dest/spartan/utils/index.js +2 -0
  53. package/dest/spartan/utils/nodes.d.ts +4 -5
  54. package/dest/spartan/utils/nodes.d.ts.map +1 -1
  55. package/dest/spartan/utils/nodes.js +9 -9
  56. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  57. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  58. package/dest/spartan/utils/pod_logs.js +74 -0
  59. package/dest/test-wallet/worker_wallet_schema.d.ts +6 -1
  60. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
  61. package/package.json +42 -44
  62. package/src/bench/client_flows/client_flows_benchmark.ts +29 -20
  63. package/src/e2e_epochs/epochs_test.ts +3 -3
  64. package/src/e2e_p2p/inactivity_slash_test.ts +2 -3
  65. package/src/e2e_p2p/p2p_network.ts +23 -28
  66. package/src/e2e_p2p/reqresp/utils.ts +24 -3
  67. package/src/e2e_p2p/shared.ts +16 -99
  68. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  69. package/src/fixtures/e2e_prover_test.ts +12 -17
  70. package/src/fixtures/elu_monitor.ts +126 -0
  71. package/src/fixtures/get_bb_config.ts +7 -6
  72. package/src/fixtures/setup.ts +21 -16
  73. package/src/fixtures/setup_p2p_test.ts +9 -9
  74. package/src/fixtures/token_utils.ts +1 -4
  75. package/src/guides/up_quick_start.sh +0 -2
  76. package/src/shared/gas_portal_test_harness.ts +0 -1
  77. package/src/shared/jest_setup.ts +51 -1
  78. package/src/shared/submit-transactions.ts +1 -4
  79. package/src/shared/uniswap_l1_l2.ts +0 -4
  80. package/src/simulators/token_simulator.ts +1 -1
  81. package/src/spartan/setup_test_wallets.ts +59 -36
  82. package/src/spartan/tx_metrics.ts +1 -1
  83. package/src/spartan/utils/config.ts +2 -0
  84. package/src/spartan/utils/index.ts +3 -0
  85. package/src/spartan/utils/nodes.ts +15 -10
  86. package/src/spartan/utils/pod_logs.ts +99 -0
@@ -7,6 +7,8 @@ import {
7
7
  BatchCall,
8
8
  type ContractFunctionInteraction,
9
9
  type ContractMethod,
10
+ type DeployInteractionWaitOptions,
11
+ type DeployOptions,
10
12
  getContractClassFromArtifact,
11
13
  waitForProven,
12
14
  } from '@aztec/aztec.js/contracts';
@@ -30,7 +32,8 @@ import {
30
32
  deployAztecL1Contracts,
31
33
  } from '@aztec/ethereum/deploy-aztec-l1-contracts';
32
34
  import type { Delayer } from '@aztec/ethereum/l1-tx-utils';
33
- import { type Anvil, EthCheatCodes, EthCheatCodesWithState, startAnvil } from '@aztec/ethereum/test';
35
+ import { EthCheatCodes, EthCheatCodesWithState, startAnvil } from '@aztec/ethereum/test';
36
+ import type { Anvil } from '@aztec/ethereum/test';
34
37
  import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
35
38
  import { SecretValue } from '@aztec/foundation/config';
36
39
  import { randomBytes } from '@aztec/foundation/crypto/random';
@@ -51,6 +54,7 @@ import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationP
51
54
  import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
52
55
  import { tryStop } from '@aztec/stdlib/interfaces/server';
53
56
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
57
+ import type { GenesisData } from '@aztec/stdlib/world-state';
54
58
  import {
55
59
  type TelemetryClient,
56
60
  type TelemetryClientConfig,
@@ -177,6 +181,8 @@ export type SetupOptions = {
177
181
  proverNodeConfig?: Partial<ProverNodeConfig>;
178
182
  /** Whether to use a mock gossip sub network for p2p clients. */
179
183
  mockGossipSubNetwork?: boolean;
184
+ /** Whether to add simulated latency to the mock gossipsub network (in ms) */
185
+ mockGossipSubNetworkLatency?: number;
180
186
  /** Whether to disable the anvil test watcher (can still be manually started) */
181
187
  disableAnvilTestWatcher?: boolean;
182
188
  /** Whether to enable anvil automine during deployment of L1 contracts (consider defaulting this to true). */
@@ -248,8 +254,8 @@ export type EndToEndContext = {
248
254
  sequencerDelayer: Delayer | undefined;
249
255
  /** Delayer for prover node L1 txs (only when enableDelayer and startProverNode are true). */
250
256
  proverDelayer: Delayer | undefined;
251
- /** Prefilled public data used for setting up nodes. */
252
- prefilledPublicData: PublicDataTreeLeaf[] | undefined;
257
+ /** Genesis data used for setting up nodes. */
258
+ genesis: GenesisData | undefined;
253
259
  /** ACVM config (only set if running locally). */
254
260
  acvmConfig: Awaited<ReturnType<typeof getACVMConfig>>;
255
261
  /** BB config (only set if running locally). */
@@ -275,7 +281,7 @@ export async function setup(
275
281
  let anvil: Anvil | undefined;
276
282
  try {
277
283
  opts.aztecTargetCommitteeSize ??= 0;
278
- opts.slasherFlavor ??= 'none';
284
+ opts.slasherEnabled ??= false;
279
285
 
280
286
  const config: AztecNodeConfig & SetupOptions = { ...getConfigEnvVars(), ...opts };
281
287
  // use initialValidators for the node config
@@ -374,10 +380,12 @@ export async function setup(
374
380
  addressesToFund.push(sponsoredFPCAddress);
375
381
  }
376
382
 
377
- const { genesisArchiveRoot, prefilledPublicData, fundingNeeded } = await getGenesisValues(
383
+ const genesisTimestamp = BigInt(Math.floor(Date.now() / 1000));
384
+ const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(
378
385
  addressesToFund,
379
386
  opts.initialAccountFeeJuice,
380
387
  opts.genesisPublicData,
388
+ genesisTimestamp,
381
389
  );
382
390
 
383
391
  const wasAutomining = await ethCheatCodes.isAutoMining();
@@ -466,7 +474,7 @@ export async function setup(
466
474
  let p2pClientDeps: P2PClientDeps | undefined = undefined;
467
475
 
468
476
  if (opts.mockGossipSubNetwork) {
469
- mockGossipSubNetwork = new MockGossipSubNetwork();
477
+ mockGossipSubNetwork = new MockGossipSubNetwork(opts.mockGossipSubNetworkLatency);
470
478
  p2pClientDeps = { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) };
471
479
  }
472
480
 
@@ -495,11 +503,7 @@ export async function setup(
495
503
  }
496
504
 
497
505
  const aztecNodeService = await withLoggerBindings({ actor: 'node-0' }, () =>
498
- AztecNodeService.createAndSync(
499
- config,
500
- { dateProvider, telemetry: telemetryClient, p2pClientDeps },
501
- { prefilledPublicData },
502
- ),
506
+ AztecNodeService.createAndSync(config, { dateProvider, telemetry: telemetryClient, p2pClientDeps }, { genesis }),
503
507
  );
504
508
  const sequencerClient = aztecNodeService.getSequencer();
505
509
 
@@ -523,7 +527,7 @@ export async function setup(
523
527
  dataDirectory: proverNodeDataDirectory,
524
528
  },
525
529
  { dateProvider, p2pClientDeps, telemetry: telemetryClient },
526
- { prefilledPublicData },
530
+ { genesis },
527
531
  ));
528
532
  }
529
533
 
@@ -628,7 +632,7 @@ export async function setup(
628
632
  initialFundedAccounts,
629
633
  logger,
630
634
  mockGossipSubNetwork,
631
- prefilledPublicData,
635
+ genesis,
632
636
  proverNode,
633
637
  sequencerDelayer,
634
638
  proverDelayer,
@@ -728,7 +732,7 @@ export function createAndSyncProverNode(
728
732
  dateProvider: DateProvider;
729
733
  p2pClientDeps?: P2PClientDeps;
730
734
  },
731
- options: { prefilledPublicData: PublicDataTreeLeaf[]; dontStart?: boolean },
735
+ options: { genesis?: GenesisData; dontStart?: boolean },
732
736
  ): Promise<{ proverNode: AztecNodeService }> {
733
737
  return withLoggerBindings({ actor: 'prover-0' }, async () => {
734
738
  const proverNode = await AztecNodeService.createAndSync(
@@ -741,7 +745,7 @@ export function createAndSyncProverNode(
741
745
  proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
742
746
  },
743
747
  deps,
744
- { ...options, dontStartProverNode: options.dontStart },
748
+ { genesis: options.genesis, dontStartProverNode: options.dontStart },
745
749
  );
746
750
 
747
751
  if (!proverNode.getProverNode()) {
@@ -832,7 +836,7 @@ export async function ensureAccountContractsPublished(wallet: Wallet, accountsTo
832
836
  * Returns deployed account data that can be used by tests.
833
837
  */
834
838
  export const deployAccounts =
835
- (numberOfAccounts: number, logger: Logger) =>
839
+ (numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<DeployInteractionWaitOptions>>) =>
836
840
  async ({ wallet, initialFundedAccounts }: { wallet: TestWallet; initialFundedAccounts: InitialAccountData[] }) => {
837
841
  if (initialFundedAccounts.length < numberOfAccounts) {
838
842
  throw new Error(`Cannot deploy more than ${initialFundedAccounts.length} initial accounts.`);
@@ -851,6 +855,7 @@ export const deployAccounts =
851
855
  await deployMethod.send({
852
856
  from: NO_FROM,
853
857
  skipClassPublication: i !== 0, // Publish the contract class at most once.
858
+ ...deployOptions,
854
859
  });
855
860
  }
856
861
 
@@ -7,7 +7,7 @@ import { SecretValue } from '@aztec/foundation/config';
7
7
  import { withLoggerBindings } from '@aztec/foundation/log/server';
8
8
  import { bufferToHex } from '@aztec/foundation/string';
9
9
  import type { DateProvider } from '@aztec/foundation/timer';
10
- import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
10
+ import type { GenesisData } from '@aztec/stdlib/world-state';
11
11
 
12
12
  import getPort from 'get-port';
13
13
 
@@ -40,7 +40,7 @@ export async function createNodes(
40
40
  bootstrapNodeEnr: string,
41
41
  numNodes: number,
42
42
  bootNodePort: number,
43
- prefilledPublicData?: PublicDataTreeLeaf[],
43
+ genesis?: GenesisData,
44
44
  dataDirectory?: string,
45
45
  metricsPort?: number,
46
46
  indexOffset = 0,
@@ -65,7 +65,7 @@ export async function createNodes(
65
65
  port,
66
66
  bootstrapNodeEnr,
67
67
  validatorIndices,
68
- prefilledPublicData,
68
+ genesis,
69
69
  dataDir,
70
70
  metricsPort,
71
71
  );
@@ -97,7 +97,7 @@ export async function createNode(
97
97
  tcpPort: number,
98
98
  bootstrapNode: string | undefined,
99
99
  addressIndex: number | number[],
100
- prefilledPublicData?: PublicDataTreeLeaf[],
100
+ genesis?: GenesisData,
101
101
  dataDirectory?: string,
102
102
  metricsPort?: number,
103
103
  ) {
@@ -108,7 +108,7 @@ export async function createNode(
108
108
  return await AztecNodeService.createAndSync(
109
109
  validatorConfig,
110
110
  { telemetry, dateProvider },
111
- { prefilledPublicData, dontStartSequencer: config.dontStartSequencer },
111
+ { genesis, dontStartSequencer: config.dontStartSequencer },
112
112
  );
113
113
  });
114
114
  }
@@ -119,7 +119,7 @@ export async function createNonValidatorNode(
119
119
  dateProvider: DateProvider,
120
120
  tcpPort: number,
121
121
  bootstrapNode: string | undefined,
122
- prefilledPublicData?: PublicDataTreeLeaf[],
122
+ genesis?: GenesisData,
123
123
  dataDirectory?: string,
124
124
  metricsPort?: number,
125
125
  ) {
@@ -133,7 +133,7 @@ export async function createNonValidatorNode(
133
133
  sequencerPublisherPrivateKeys: [],
134
134
  };
135
135
  const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
136
- return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { prefilledPublicData });
136
+ return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { genesis });
137
137
  });
138
138
  }
139
139
 
@@ -143,7 +143,7 @@ export async function createProverNode(
143
143
  bootstrapNode: string | undefined,
144
144
  addressIndex: number,
145
145
  deps: { dateProvider: DateProvider },
146
- prefilledPublicData?: PublicDataTreeLeaf[],
146
+ genesis?: GenesisData,
147
147
  dataDirectory?: string,
148
148
  metricsPort?: number,
149
149
  ): Promise<{ proverNode: AztecNodeService }> {
@@ -159,7 +159,7 @@ export async function createProverNode(
159
159
  { ...config, ...p2pConfig },
160
160
  { dataDirectory },
161
161
  { ...deps, telemetry },
162
- { prefilledPublicData: prefilledPublicData ?? [] },
162
+ { genesis },
163
163
  );
164
164
  });
165
165
  }
@@ -6,11 +6,8 @@ import { TokenContract } from '@aztec/noir-contracts.js/Token';
6
6
 
7
7
  export async function deployToken(wallet: Wallet, admin: AztecAddress, initialAdminBalance: bigint, logger: Logger) {
8
8
  logger.info(`Deploying Token contract...`);
9
- const {
10
- receipt: { contract, instance },
11
- } = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
9
+ const { contract, instance } = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
12
10
  from: admin,
13
- wait: { returnReceipt: true },
14
11
  });
15
12
 
16
13
  if (initialAdminBalance > 0n) {
@@ -18,10 +18,8 @@ aztec-wallet() {
18
18
 
19
19
  aztec-wallet import-test-accounts
20
20
 
21
- # docs:start:declare-accounts
22
21
  aztec-wallet create-account -a alice -f test0
23
22
  aztec-wallet create-account -a bob -f test0
24
- # docs:end:declare-accounts
25
23
 
26
24
  aztec-wallet bridge-fee-juice 1000000000000000000000 accounts:alice --mint --no-wait
27
25
 
@@ -178,4 +178,3 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
178
178
  }
179
179
  }
180
180
  }
181
- // docs:end:cross_chain_test_harness
@@ -1,8 +1,19 @@
1
1
  import { createLogger } from '@aztec/aztec.js/log';
2
2
 
3
- import { beforeEach, expect } from '@jest/globals';
3
+ import { afterAll, afterEach, beforeEach, expect } from '@jest/globals';
4
+ import { readlinkSync } from 'fs';
4
5
  import { basename } from 'path';
5
6
 
7
+ import { EluMonitor } from '../fixtures/elu_monitor.js';
8
+
9
+ const eluMonitor = process.env.ELU_MONITOR_FILE
10
+ ? new EluMonitor(process.env.ELU_MONITOR_FILE, Number(process.env.ELU_MONITOR_INTERVAL_MS) || undefined)
11
+ : undefined;
12
+
13
+ if (eluMonitor) {
14
+ process.on('exit', () => eluMonitor.stop());
15
+ }
16
+
6
17
  beforeEach(() => {
7
18
  const { testPath, currentTestName } = expect.getState();
8
19
  if (!testPath || !currentTestName) {
@@ -10,4 +21,43 @@ beforeEach(() => {
10
21
  }
11
22
  const logger = createLogger(`e2e:${basename(testPath).replace('.test.ts', '')}`);
12
23
  logger.info(`Running test: ${currentTestName}`);
24
+ eluMonitor?.startTest(currentTestName);
25
+ });
26
+
27
+ afterEach(() => {
28
+ eluMonitor?.stopTest();
29
+ });
30
+
31
+ // Log leaked handles after all tests complete. This runs after test-level afterAll hooks,
32
+ // so any handles still alive at this point were not properly cleaned up during teardown.
33
+ // This diagnostic helps identify the source of exit hangs without masking them.
34
+ afterAll(() => {
35
+ const handles = (process as any)._getActiveHandles();
36
+ if (handles.length > 0) {
37
+ const details = handles.map((h: any) => {
38
+ const type = h?.constructor?.name ?? typeof h;
39
+ const fd = h?.fd ?? h?._handle?.fd ?? '?';
40
+ const destroyed = h?.destroyed ?? '?';
41
+ const hasRef = typeof h?.hasRef === 'function' ? h.hasRef() : '?';
42
+ const localAddr = h?.localAddress ?? '';
43
+ const remoteAddr = h?.remoteAddress ?? '';
44
+ const localPort = h?.localPort ?? '';
45
+ const remotePort = h?.remotePort ?? '';
46
+ const proto = Object.getPrototypeOf(h)?.constructor?.name ?? '?';
47
+ const keys = Object.keys(h).slice(0, 10).join(',');
48
+ let fdTarget = '';
49
+ if (typeof fd === 'number') {
50
+ try {
51
+ fdTarget = ` -> ${readlinkSync(`/proc/self/fd/${fd}`)}`;
52
+ } catch {
53
+ // ignore
54
+ }
55
+ }
56
+ return ` ${type}(fd=${fd}, destroyed=${destroyed}, hasRef=${hasRef}${fdTarget}) proto=${proto} addr=${localAddr}:${localPort}->${remoteAddr}:${remotePort} keys=[${keys}]`;
57
+ });
58
+ process.stderr.write(
59
+ `\n[jest_setup] WARNING: ${handles.length} handle(s) still active after teardown:\n${details.join('\n')}\n` +
60
+ `These may prevent Jest from exiting. Investigate and fix the leak.\n\n`,
61
+ );
62
+ }
13
63
  });
@@ -19,10 +19,7 @@ export const submitTxsTo = async (
19
19
  times(numTxs, async () => {
20
20
  const accountManager = await wallet.createSchnorrAccount(Fr.random(), Fr.random(), GrumpkinScalar.random());
21
21
  const deployMethod = await accountManager.getDeployMethod();
22
- const { txHash } = await deployMethod.send({
23
- from: submitter,
24
- wait: NO_WAIT,
25
- });
22
+ const { txHash } = await deployMethod.send({ from: submitter, wait: NO_WAIT });
26
23
 
27
24
  logger.info(`Tx sent with hash ${txHash}`);
28
25
  const receipt: TxReceipt = await wallet.getTxReceipt(txHash);
@@ -154,7 +154,6 @@ export const uniswapL1L2TestSuite = (
154
154
  await cleanup();
155
155
  });
156
156
 
157
- // docs:start:uniswap_private
158
157
  it('should uniswap trade on L1 from L2 funds privately (swaps WETH -> DAI)', async () => {
159
158
  const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
160
159
 
@@ -345,10 +344,8 @@ export const uniswapL1L2TestSuite = (
345
344
  logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
346
345
  logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
347
346
  });
348
- // docs:end:uniswap_private
349
347
 
350
348
  // TODO(#7463): reenable look into this failure https://github.com/AztecProtocol/aztec-packages/actions/runs/9912612912/job/27388320150?pr=7462
351
- // // docs:start:uniswap_public
352
349
  // it('should uniswap trade on L1 from L2 funds publicly (swaps WETH -> DAI)', async () => {
353
350
  // const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
354
351
 
@@ -581,7 +578,6 @@ export const uniswapL1L2TestSuite = (
581
578
  // logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
582
579
  // logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
583
580
  // });
584
- // // docs:end:uniswap_public
585
581
 
586
582
  // Edge cases for the private flow:
587
583
  // note - tests for uniswapPortal.sol and minting asset on L2 are covered in other tests.
@@ -110,7 +110,7 @@ export class TokenSimulator {
110
110
  chunk(calls, 5).map(batch => new BatchCall(this.defaultWallet, batch).simulate({ from: this.defaultAddress })),
111
111
  )
112
112
  )
113
- .flat()
113
+ .flatMap(r => r.result)
114
114
  .map(r => r.result);
115
115
  expect(results[0]).toEqual(this.totalSupply);
116
116
 
@@ -11,7 +11,7 @@ import type { Wallet } from '@aztec/aztec.js/wallet';
11
11
  import { createEthereumChain } from '@aztec/ethereum/chain';
12
12
  import { createExtendedL1Client } from '@aztec/ethereum/client';
13
13
  import type { Logger } from '@aztec/foundation/log';
14
- import { retryUntil } from '@aztec/foundation/retry';
14
+ import { makeBackoff, retry, retryUntil } from '@aztec/foundation/retry';
15
15
  import { TokenContract } from '@aztec/noir-contracts.js/Token';
16
16
  import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
17
17
  import { registerInitialLocalNetworkAccountsInWallet } from '@aztec/wallets/testing';
@@ -138,38 +138,57 @@ async function deployAccountWithDiagnostics(
138
138
  estimateGas?: boolean,
139
139
  ): Promise<void> {
140
140
  const deployMethod = await account.getDeployMethod();
141
- let txHash;
142
- try {
143
- let gasSettings;
144
- if (estimateGas) {
145
- const sim = await deployMethod.simulate({ from: NO_FROM, fee: { paymentMethod } });
146
- gasSettings = sim.estimatedGas;
147
- logger.info(`${accountLabel} estimated gas: DA=${gasSettings.gasLimits.daGas} L2=${gasSettings.gasLimits.l2Gas}`);
148
- }
149
- const deployResult = await deployMethod.send({
150
- from: NO_FROM,
151
- fee: { paymentMethod, gasSettings },
152
- wait: NO_WAIT,
153
- });
154
- txHash = deployResult.txHash;
155
- await waitForTx(aztecNode, txHash, { timeout: 2400 });
156
- logger.info(`${accountLabel} deployed at ${account.address}`);
157
- } catch (error) {
158
- const blockNumber = await aztecNode.getBlockNumber();
159
- let receipt;
160
- try {
161
- receipt = await aztecNode.getTxReceipt(txHash);
162
- } catch {
163
- receipt = 'unavailable';
164
- }
165
- logger.error(`${accountLabel} deployment failed`, {
166
- txHash: txHash.toString(),
167
- receipt: JSON.stringify(receipt),
168
- currentBlockNumber: blockNumber,
169
- error: String(error),
170
- });
171
- throw error;
141
+ let gasSettings: any;
142
+ if (estimateGas) {
143
+ const sim = await deployMethod.simulate({ from: NO_FROM, fee: { paymentMethod } });
144
+ gasSettings = sim.estimatedGas;
145
+ logger.info(`${accountLabel} estimated gas: DA=${gasSettings.gasLimits.daGas} L2=${gasSettings.gasLimits.l2Gas}`);
172
146
  }
147
+
148
+ // Track the tx hash across retries so we don't re-send when the previous tx is still pending.
149
+ let sentTxHash: { txHash: any } | undefined;
150
+
151
+ await retry(
152
+ async () => {
153
+ // Check if already deployed (handles case where previous attempt succeeded but waitForTx timed out)
154
+ const existing = await aztecNode.getContract(account.address);
155
+ if (existing) {
156
+ logger.info(`${accountLabel} already deployed at ${account.address}, skipping`);
157
+ return;
158
+ }
159
+
160
+ // If we already sent a tx, check if it was dropped before deciding to re-send.
161
+ if (sentTxHash) {
162
+ const prevReceipt = await aztecNode.getTxReceipt(sentTxHash.txHash);
163
+ if (prevReceipt.isDropped()) {
164
+ logger.info(`${accountLabel} previous tx ${sentTxHash.txHash} was dropped, re-sending`);
165
+ sentTxHash = undefined;
166
+ } else {
167
+ logger.info(`${accountLabel} previous tx ${sentTxHash.txHash} still pending, waiting again...`);
168
+ }
169
+ }
170
+
171
+ if (!sentTxHash) {
172
+ const deployResult = await deployMethod.send({
173
+ from: NO_FROM,
174
+ fee: { paymentMethod, gasSettings },
175
+ wait: NO_WAIT,
176
+ });
177
+ sentTxHash = { txHash: deployResult.txHash };
178
+ logger.info(`${accountLabel} tx sent`, { txHash: sentTxHash.txHash.toString() });
179
+ }
180
+
181
+ const receipt = await waitForTx(aztecNode, sentTxHash.txHash, { timeout: 600 });
182
+ if (receipt.isDropped()) {
183
+ sentTxHash = undefined;
184
+ throw new Error(`${accountLabel} tx was dropped, retrying...`);
185
+ }
186
+ logger.info(`${accountLabel} deployed at ${account.address}`);
187
+ },
188
+ `deploy ${accountLabel}`,
189
+ makeBackoff([1, 2, 4, 8, 16]),
190
+ logger,
191
+ );
173
192
  }
174
193
 
175
194
  async function deployAccountsInBatches(
@@ -346,14 +365,18 @@ async function deployTokenAndMint(
346
365
  logger: Logger,
347
366
  ) {
348
367
  logger.verbose(`Deploying TokenContract...`);
349
- const {
350
- receipt: { contract: tokenContract },
351
- } = await TokenContract.deploy(wallet, admin, TOKEN_NAME, TOKEN_SYMBOL, TOKEN_DECIMALS).send({
368
+ const { contract: tokenContract } = await TokenContract.deploy(
369
+ wallet,
370
+ admin,
371
+ TOKEN_NAME,
372
+ TOKEN_SYMBOL,
373
+ TOKEN_DECIMALS,
374
+ ).send({
352
375
  from: admin,
353
376
  fee: {
354
377
  paymentMethod,
355
378
  },
356
- wait: { timeout: 600, returnReceipt: true },
379
+ wait: { timeout: 600 },
357
380
  });
358
381
 
359
382
  const tokenAddress = tokenContract.address;
@@ -296,7 +296,7 @@ export class TxInclusionMetrics {
296
296
  value: stats.mean,
297
297
  },
298
298
  {
299
- name: `${group}/median_inclusion`,
299
+ name: `${group}/p50_inclusion`,
300
300
  unit: 's',
301
301
  value: stats.median,
302
302
  },
@@ -8,6 +8,7 @@ const logger = createLogger('e2e:k8s-utils');
8
8
  const testConfigSchema = z.object({
9
9
  NAMESPACE: z.string().default('scenario'),
10
10
  REAL_VERIFIER: schemas.Boolean.optional().default(true),
11
+ DEBUG_FORCE_TX_PROOF_VERIFICATION: schemas.Boolean.optional().default(true),
11
12
  CREATE_ETH_DEVNET: schemas.Boolean.optional().default(false),
12
13
  L1_RPC_URLS_JSON: z.string().optional(),
13
14
  L1_ACCOUNT_MNEMONIC: z.string().optional(),
@@ -16,6 +17,7 @@ const testConfigSchema = z.object({
16
17
  AZTEC_PROOF_SUBMISSION_WINDOW: z.coerce.number().optional().default(5),
17
18
  AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: z.coerce.number().optional().default(2),
18
19
  FUNDING_PRIVATE_KEY: z.string().optional(),
20
+ AZTEC_ADMIN_API_KEY: z.string().optional(),
19
21
  });
20
22
 
21
23
  export type TestConfig = z.infer<typeof testConfigSchema>;
@@ -66,3 +66,6 @@ export { getPublicViemClient, getL1DeploymentAddresses, getNodeClient } from './
66
66
 
67
67
  // Health checks
68
68
  export { ChainHealth, type ChainHealthSnapshot } from './health.js';
69
+
70
+ // Pod log extraction
71
+ export { type BlockBuiltLogEntry, fetchBlockBuiltLogs } from './pod_logs.js';
@@ -173,7 +173,7 @@ export async function withSequencersAdmin<T>(env: TestConfig, fn: (node: AztecNo
173
173
  if (statusRes.status !== 200) {
174
174
  throw new Error(`Admin endpoint returned status ${statusRes.status}`);
175
175
  }
176
- const client = createAztecNodeAdminClient(url);
176
+ const client = createAztecNodeAdminClient(url, {}, undefined, env.AZTEC_ADMIN_API_KEY);
177
177
  return { result: await fn(client), process };
178
178
  } catch (err) {
179
179
  // Kill the port-forward before retrying
@@ -255,21 +255,18 @@ export async function initHADb(namespace: string): Promise<void> {
255
255
  }
256
256
 
257
257
  /**
258
- * Enables or disables probabilistic transaction dropping on validators and waits for rollout.
259
- * Wired to env vars P2P_DROP_TX and P2P_DROP_TX_CHANCE via Helm values.
258
+ * Sets probabilistic transaction dropping on validators and waits for rollout.
259
+ * Use probability=0 to disable. Wired to env var P2P_DROP_TX_CHANCE via Helm values.
260
260
  */
261
261
  export async function setValidatorTxDrop({
262
262
  namespace,
263
- enabled,
264
263
  probability,
265
264
  logger: log,
266
265
  }: {
267
266
  namespace: string;
268
- enabled: boolean;
269
267
  probability: number;
270
268
  logger: Logger;
271
269
  }) {
272
- const drop = enabled ? 'true' : 'false';
273
270
  const prob = String(probability);
274
271
 
275
272
  const selectors = ['app.kubernetes.io/name=validator', 'app.kubernetes.io/component=validator', 'app=validator'];
@@ -284,7 +281,7 @@ export async function setValidatorTxDrop({
284
281
  if (names.length === 0) {
285
282
  continue;
286
283
  }
287
- const cmd = `kubectl set env statefulset -l ${selector} -n ${namespace} P2P_DROP_TX=${drop} P2P_DROP_TX_CHANCE=${prob}`;
284
+ const cmd = `kubectl set env statefulset -l ${selector} -n ${namespace} P2P_DROP_TX_CHANCE=${prob}`;
288
285
  log.info(`command: ${cmd}`);
289
286
  await execAsync(cmd);
290
287
  updated = true;
@@ -366,16 +363,24 @@ export async function enableValidatorDynamicBootNode(
366
363
  */
367
364
  export async function rollAztecPods(namespace: string, clearState: boolean = false) {
368
365
  // Pod components use 'validator', but StatefulSets and PVCs use 'sequencer-node' for validators
366
+ // RPC nodes have nodeType='rpc-node' in Helm values, so their component label is 'rpc-node' (not 'rpc')
369
367
  const podComponents = [
370
368
  'p2p-bootstrap',
371
369
  'prover-node',
372
370
  'prover-broker',
373
371
  'prover-agent',
374
372
  'sequencer-node',
375
- 'rpc',
373
+ 'rpc-node',
374
+ 'validator-ha-db',
375
+ ];
376
+ const pvcComponents = [
377
+ 'p2p-bootstrap',
378
+ 'prover-node',
379
+ 'prover-broker',
380
+ 'sequencer-node',
381
+ 'rpc-node',
376
382
  'validator-ha-db',
377
383
  ];
378
- const pvcComponents = ['p2p-bootstrap', 'prover-node', 'prover-broker', 'sequencer-node', 'rpc', 'validator-ha-db'];
379
384
  // StatefulSet components that need to be scaled down before PVC deletion
380
385
  // Note: validators use 'sequencer-node' as component label, not 'validator'
381
386
  const statefulSetComponents = [
@@ -383,7 +388,7 @@ export async function rollAztecPods(namespace: string, clearState: boolean = fal
383
388
  'prover-node',
384
389
  'prover-broker',
385
390
  'sequencer-node',
386
- 'rpc',
391
+ 'rpc-node',
387
392
  'validator-ha-db',
388
393
  ];
389
394