@aztec/end-to-end 0.0.1-commit.5de5ca79e → 0.0.1-commit.6201a7b05

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 (109) hide show
  1. package/README.md +27 -0
  2. package/dest/bench/client_flows/client_flows_benchmark.d.ts +1 -1
  3. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  4. package/dest/bench/client_flows/client_flows_benchmark.js +15 -30
  5. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +3 -2
  6. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  7. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +1 -1
  8. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +1 -1
  9. package/dest/e2e_epochs/epochs_test.d.ts +16 -1
  10. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  11. package/dest/e2e_epochs/epochs_test.js +56 -8
  12. package/dest/e2e_fees/fees_test.d.ts +1 -1
  13. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  14. package/dest/e2e_fees/fees_test.js +4 -4
  15. package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
  16. package/dest/e2e_p2p/p2p_network.d.ts +10 -9
  17. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  18. package/dest/e2e_p2p/p2p_network.js +46 -27
  19. package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
  20. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  21. package/dest/e2e_p2p/reqresp/utils.js +10 -7
  22. package/dest/e2e_p2p/shared.d.ts +5 -7
  23. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  24. package/dest/e2e_p2p/shared.js +36 -47
  25. package/dest/fixtures/authwit_proxy.d.ts +1 -1
  26. package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
  27. package/dest/fixtures/authwit_proxy.js +4 -0
  28. package/dest/fixtures/e2e_prover_test.d.ts +4 -3
  29. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  30. package/dest/fixtures/e2e_prover_test.js +7 -12
  31. package/dest/fixtures/fixtures.d.ts +12 -1
  32. package/dest/fixtures/fixtures.d.ts.map +1 -1
  33. package/dest/fixtures/fixtures.js +10 -0
  34. package/dest/fixtures/get_bb_config.d.ts +1 -1
  35. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  36. package/dest/fixtures/get_bb_config.js +5 -5
  37. package/dest/fixtures/ha_setup.d.ts +2 -2
  38. package/dest/fixtures/ha_setup.d.ts.map +1 -1
  39. package/dest/fixtures/ha_setup.js +1 -1
  40. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
  41. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
  42. package/dest/fixtures/schnorr_hardcoded_account_contract.js +39 -0
  43. package/dest/fixtures/setup.d.ts +17 -10
  44. package/dest/fixtures/setup.d.ts.map +1 -1
  45. package/dest/fixtures/setup.js +41 -22
  46. package/dest/fixtures/setup_p2p_test.d.ts +6 -6
  47. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  48. package/dest/fixtures/setup_p2p_test.js +8 -8
  49. package/dest/fixtures/token_utils.d.ts +1 -1
  50. package/dest/fixtures/token_utils.d.ts.map +1 -1
  51. package/dest/fixtures/token_utils.js +2 -5
  52. package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
  53. package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
  54. package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
  55. package/dest/forward-compatibility/wallet_service.d.ts +3 -0
  56. package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
  57. package/dest/forward-compatibility/wallet_service.js +109 -0
  58. package/dest/legacy-jest-resolver.d.cts +3 -0
  59. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  60. package/dest/shared/gas_portal_test_harness.js +1 -1
  61. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  62. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  63. package/dest/shared/uniswap_l1_l2.js +0 -4
  64. package/dest/simulators/lending_simulator.d.ts +1 -1
  65. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  66. package/dest/simulators/lending_simulator.js +2 -2
  67. package/dest/spartan/setup_test_wallets.d.ts +1 -1
  68. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  69. package/dest/spartan/setup_test_wallets.js +63 -45
  70. package/dest/spartan/tx_metrics.d.ts +1 -1
  71. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  72. package/dest/spartan/tx_metrics.js +18 -2
  73. package/dest/test-wallet/test_wallet.d.ts +16 -8
  74. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  75. package/dest/test-wallet/test_wallet.js +111 -70
  76. package/dest/test-wallet/worker_wallet.d.ts +4 -4
  77. package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
  78. package/dest/test-wallet/worker_wallet_schema.d.ts +9 -4
  79. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
  80. package/package.json +40 -39
  81. package/src/bench/client_flows/client_flows_benchmark.ts +33 -24
  82. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +3 -6
  83. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +1 -1
  84. package/src/e2e_epochs/epochs_test.ts +56 -7
  85. package/src/e2e_fees/fees_test.ts +5 -3
  86. package/src/e2e_p2p/inactivity_slash_test.ts +3 -3
  87. package/src/e2e_p2p/p2p_network.ts +57 -39
  88. package/src/e2e_p2p/reqresp/utils.ts +8 -7
  89. package/src/e2e_p2p/shared.ts +33 -61
  90. package/src/fixtures/authwit_proxy.ts +4 -0
  91. package/src/fixtures/e2e_prover_test.ts +12 -17
  92. package/src/fixtures/fixtures.ts +22 -0
  93. package/src/fixtures/get_bb_config.ts +7 -6
  94. package/src/fixtures/ha_setup.ts +4 -2
  95. package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
  96. package/src/fixtures/setup.ts +55 -26
  97. package/src/fixtures/setup_p2p_test.ts +9 -9
  98. package/src/fixtures/token_utils.ts +1 -4
  99. package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
  100. package/src/forward-compatibility/wallet_service.ts +104 -0
  101. package/src/guides/up_quick_start.sh +0 -2
  102. package/src/legacy-jest-resolver.cjs +135 -0
  103. package/src/shared/gas_portal_test_harness.ts +0 -1
  104. package/src/shared/uniswap_l1_l2.ts +0 -4
  105. package/src/simulators/lending_simulator.ts +4 -2
  106. package/src/spartan/setup_test_wallets.ts +63 -39
  107. package/src/spartan/tx_metrics.ts +16 -4
  108. package/src/test-wallet/test_wallet.ts +137 -74
  109. package/src/test-wallet/worker_wallet.ts +3 -2
@@ -1,11 +1,14 @@
1
1
  import { SchnorrAccountContractArtifact } from '@aztec/accounts/schnorr';
2
2
  import { type InitialAccountData, generateSchnorrAccounts } from '@aztec/accounts/testing';
3
3
  import { type AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node';
4
+ import { NO_FROM } from '@aztec/aztec.js/account';
4
5
  import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
5
6
  import {
6
7
  BatchCall,
7
8
  type ContractFunctionInteraction,
8
9
  type ContractMethod,
10
+ type DeployInteractionWaitOptions,
11
+ type DeployOptions,
9
12
  getContractClassFromArtifact,
10
13
  waitForProven,
11
14
  } from '@aztec/aztec.js/contracts';
@@ -14,7 +17,7 @@ import { Fr } from '@aztec/aztec.js/fields';
14
17
  import { type Logger, createLogger } from '@aztec/aztec.js/log';
15
18
  import type { AztecNode } from '@aztec/aztec.js/node';
16
19
  import type { Wallet } from '@aztec/aztec.js/wallet';
17
- import { AnvilTestWatcher, CheatCodes } from '@aztec/aztec/testing';
20
+ import { AnvilTestWatcher, type AnvilTestWatcherOpts, CheatCodes } from '@aztec/aztec/testing';
18
21
  import { SPONSORED_FPC_SALT } from '@aztec/constants';
19
22
  import { isAnvilTestChain } from '@aztec/ethereum/chain';
20
23
  import { createExtendedL1Client } from '@aztec/ethereum/client';
@@ -48,9 +51,10 @@ import type { ProverNodeConfig } from '@aztec/prover-node';
48
51
  import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
49
52
  import type { SequencerClient } from '@aztec/sequencer-client';
50
53
  import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
51
- import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
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,8 +181,11 @@ 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;
188
+ anvilTestWatcherOpts?: AnvilTestWatcherOpts;
182
189
  /** Whether to enable anvil automine during deployment of L1 contracts (consider defaulting this to true). */
183
190
  automineL1Setup?: boolean;
184
191
  /** How many accounts to seed and unlock in anvil. */
@@ -200,8 +207,11 @@ export type SetupOptions = {
200
207
  skipAccountDeployment?: boolean;
201
208
  /** L1 contracts deployment arguments. */
202
209
  l1ContractsArgs?: Partial<DeployAztecL1ContractsArgs>;
203
- /** Wallet minimum fee padding multiplier (defaults to 0.5, which is 50% padding). */
210
+ /** Wallet minimum fee padding multiplier */
204
211
  walletMinFeePadding?: number;
212
+ /** Whether the initial node should be a lightweight RPC-only node (no sequencer, no validator).
213
+ * Use for tests that create their own validator nodes and don't need the initial sequencer. */
214
+ skipInitialSequencer?: boolean;
205
215
  } & Partial<AztecNodeConfig>;
206
216
 
207
217
  /** Context for an end-to-end test as returned by the `setup` function */
@@ -209,7 +219,7 @@ export type EndToEndContext = {
209
219
  /** The Anvil instance (only set if anvil was started locally). */
210
220
  anvil: Anvil | undefined;
211
221
  /** The Aztec Node service or client a connected to it. */
212
- aztecNode: AztecNode;
222
+ aztecNode: AztecNode & AztecNodeDebug;
213
223
  /** The Aztec Node as a service. */
214
224
  aztecNodeService: AztecNodeService;
215
225
  /** Client to the Aztec Node admin interface. */
@@ -248,8 +258,8 @@ export type EndToEndContext = {
248
258
  sequencerDelayer: Delayer | undefined;
249
259
  /** Delayer for prover node L1 txs (only when enableDelayer and startProverNode are true). */
250
260
  proverDelayer: Delayer | undefined;
251
- /** Prefilled public data used for setting up nodes. */
252
- prefilledPublicData: PublicDataTreeLeaf[] | undefined;
261
+ /** Genesis data used for setting up nodes. */
262
+ genesis: GenesisData | undefined;
253
263
  /** ACVM config (only set if running locally). */
254
264
  acvmConfig: Awaited<ReturnType<typeof getACVMConfig>>;
255
265
  /** BB config (only set if running locally). */
@@ -275,7 +285,7 @@ export async function setup(
275
285
  let anvil: Anvil | undefined;
276
286
  try {
277
287
  opts.aztecTargetCommitteeSize ??= 0;
278
- opts.slasherFlavor ??= 'none';
288
+ opts.slasherEnabled ??= false;
279
289
 
280
290
  const config: AztecNodeConfig & SetupOptions = { ...getConfigEnvVars(), ...opts };
281
291
  // use initialValidators for the node config
@@ -302,6 +312,8 @@ export async function setup(
302
312
  config.dataDirectory = directoryToCleanup;
303
313
  }
304
314
 
315
+ const dateProvider = new TestDateProvider();
316
+
305
317
  if (!config.l1RpcUrls?.length) {
306
318
  if (!isAnvilTestChain(chain.id)) {
307
319
  throw new Error(`No ETHEREUM_HOSTS set but non anvil chain requested`);
@@ -311,6 +323,7 @@ export async function setup(
311
323
  accounts: opts.anvilAccounts,
312
324
  port: opts.anvilPort ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : undefined),
313
325
  slotsInAnEpoch: opts.anvilSlotsInAnEpoch,
326
+ dateProvider,
314
327
  });
315
328
  anvil = res.anvil;
316
329
  config.l1RpcUrls = [res.rpcUrl];
@@ -322,8 +335,6 @@ export async function setup(
322
335
  logger.info(`Logging metrics to ${filename}`);
323
336
  setupMetricsLogger(filename);
324
337
  }
325
-
326
- const dateProvider = new TestDateProvider();
327
338
  const ethCheatCodes = new EthCheatCodesWithState(config.l1RpcUrls, dateProvider);
328
339
 
329
340
  if (opts.stateLoad) {
@@ -373,10 +384,12 @@ export async function setup(
373
384
  addressesToFund.push(sponsoredFPCAddress);
374
385
  }
375
386
 
376
- const { genesisArchiveRoot, prefilledPublicData, fundingNeeded } = await getGenesisValues(
387
+ const genesisTimestamp = BigInt(Math.floor(Date.now() / 1000));
388
+ const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(
377
389
  addressesToFund,
378
390
  opts.initialAccountFeeJuice,
379
391
  opts.genesisPublicData,
392
+ genesisTimestamp,
380
393
  );
381
394
 
382
395
  const wasAutomining = await ethCheatCodes.isAutoMining();
@@ -419,11 +432,12 @@ export async function setup(
419
432
  await ethCheatCodes.setIntervalMining(config.ethereumSlotDuration);
420
433
  }
421
434
 
422
- // Always sync dateProvider to L1 time after deploying L1 contracts, regardless of mining mode.
423
- // In compose mode, L1 time may have drifted ahead of system time due to the local-network watcher
424
- // warping time forward on each filled slot. Without this sync, the sequencer computes the wrong
425
- // slot from its dateProvider and cannot propose blocks.
426
- dateProvider.setTime((await ethCheatCodes.timestamp()) * 1000);
435
+ // In compose mode (no local anvil), sync dateProvider to L1 time since it may have drifted
436
+ // ahead of system time due to the local-network watcher warping time forward on each filled slot.
437
+ // When running with a local anvil, the dateProvider is kept in sync via the stdout listener.
438
+ if (!anvil) {
439
+ dateProvider.setTime((await ethCheatCodes.lastBlockTimestamp()) * 1000);
440
+ }
427
441
 
428
442
  if (opts.l2StartTime) {
429
443
  await ethCheatCodes.warp(opts.l2StartTime, { resetBlockInterval: true });
@@ -434,6 +448,7 @@ export async function setup(
434
448
  deployL1ContractsValues.l1ContractAddresses.rollupAddress,
435
449
  deployL1ContractsValues.l1Client,
436
450
  dateProvider,
451
+ opts.anvilTestWatcherOpts,
437
452
  );
438
453
  if (!opts.disableAnvilTestWatcher) {
439
454
  await watcher.start();
@@ -464,7 +479,7 @@ export async function setup(
464
479
  let p2pClientDeps: P2PClientDeps | undefined = undefined;
465
480
 
466
481
  if (opts.mockGossipSubNetwork) {
467
- mockGossipSubNetwork = new MockGossipSubNetwork();
482
+ mockGossipSubNetwork = new MockGossipSubNetwork(opts.mockGossipSubNetworkLatency);
468
483
  p2pClientDeps = { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) };
469
484
  }
470
485
 
@@ -492,11 +507,22 @@ export async function setup(
492
507
  }
493
508
  }
494
509
 
510
+ // When skipInitialSequencer is set, the initial node is a lightweight RPC-only node.
511
+ // We apply these overrides to a copy so they don't leak into the returned config.
512
+ // Keep P2P enabled if mockGossipSubNetwork is used (needed for tx propagation to validators).
513
+ const initialNodeConfig = opts.skipInitialSequencer
514
+ ? {
515
+ ...config,
516
+ disableValidator: true,
517
+ ...(opts.mockGossipSubNetwork ? {} : { p2pEnabled: false, bootstrapNodes: [] as string[] }),
518
+ }
519
+ : config;
520
+
495
521
  const aztecNodeService = await withLoggerBindings({ actor: 'node-0' }, () =>
496
522
  AztecNodeService.createAndSync(
497
- config,
523
+ initialNodeConfig,
498
524
  { dateProvider, telemetry: telemetryClient, p2pClientDeps },
499
- { prefilledPublicData },
525
+ { genesis, dontStartSequencer: opts.skipInitialSequencer },
500
526
  ),
501
527
  );
502
528
  const sequencerClient = aztecNodeService.getSequencer();
@@ -521,7 +547,7 @@ export async function setup(
521
547
  dataDirectory: proverNodeDataDirectory,
522
548
  },
523
549
  { dateProvider, p2pClientDeps, telemetry: telemetryClient },
524
- { prefilledPublicData },
550
+ { genesis },
525
551
  ));
526
552
  }
527
553
 
@@ -557,7 +583,9 @@ export async function setup(
557
583
 
558
584
  let accounts: AztecAddress[] = [];
559
585
 
560
- if (shouldDeployAccounts) {
586
+ if (opts.skipInitialSequencer) {
587
+ logger.info('Sequencer not started on initial node, skipping block progression');
588
+ } else if (shouldDeployAccounts) {
561
589
  logger.info(
562
590
  `${numberOfAccounts} accounts are being deployed. Reliably progressing past genesis by setting minTxsPerBlock to 1 and waiting for the accounts to be deployed`,
563
591
  );
@@ -626,7 +654,7 @@ export async function setup(
626
654
  initialFundedAccounts,
627
655
  logger,
628
656
  mockGossipSubNetwork,
629
- prefilledPublicData,
657
+ genesis,
630
658
  proverNode,
631
659
  sequencerDelayer,
632
660
  proverDelayer,
@@ -706,7 +734,7 @@ export async function waitForProvenChain(node: AztecNode, targetBlock?: BlockNum
706
734
  targetBlock ??= await node.getBlockNumber();
707
735
 
708
736
  await retryUntil(
709
- async () => (await node.getProvenBlockNumber()) >= targetBlock,
737
+ async () => (await node.getBlockNumber('proven')) >= targetBlock,
710
738
  'proven chain status',
711
739
  timeoutSec,
712
740
  intervalSec,
@@ -726,7 +754,7 @@ export function createAndSyncProverNode(
726
754
  dateProvider: DateProvider;
727
755
  p2pClientDeps?: P2PClientDeps;
728
756
  },
729
- options: { prefilledPublicData: PublicDataTreeLeaf[]; dontStart?: boolean },
757
+ options: { genesis?: GenesisData; dontStart?: boolean },
730
758
  ): Promise<{ proverNode: AztecNodeService }> {
731
759
  return withLoggerBindings({ actor: 'prover-0' }, async () => {
732
760
  const proverNode = await AztecNodeService.createAndSync(
@@ -739,7 +767,7 @@ export function createAndSyncProverNode(
739
767
  proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
740
768
  },
741
769
  deps,
742
- { ...options, dontStartProverNode: options.dontStart },
770
+ { genesis: options.genesis, dontStartProverNode: options.dontStart },
743
771
  );
744
772
 
745
773
  if (!proverNode.getProverNode()) {
@@ -830,7 +858,7 @@ export async function ensureAccountContractsPublished(wallet: Wallet, accountsTo
830
858
  * Returns deployed account data that can be used by tests.
831
859
  */
832
860
  export const deployAccounts =
833
- (numberOfAccounts: number, logger: Logger) =>
861
+ (numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<DeployInteractionWaitOptions>>) =>
834
862
  async ({ wallet, initialFundedAccounts }: { wallet: TestWallet; initialFundedAccounts: InitialAccountData[] }) => {
835
863
  if (initialFundedAccounts.length < numberOfAccounts) {
836
864
  throw new Error(`Cannot deploy more than ${initialFundedAccounts.length} initial accounts.`);
@@ -847,8 +875,9 @@ export const deployAccounts =
847
875
  );
848
876
  const deployMethod = await accountManager.getDeployMethod();
849
877
  await deployMethod.send({
850
- from: AztecAddress.ZERO,
878
+ from: NO_FROM,
851
879
  skipClassPublication: i !== 0, // Publish the contract class at most once.
880
+ ...deployOptions,
852
881
  });
853
882
  }
854
883
 
@@ -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) {
@@ -0,0 +1,14 @@
1
+ import type { Wallet } from '@aztec/aztec.js/wallet';
2
+ import { WalletSchema } from '@aztec/aztec.js/wallet';
3
+ import { createSafeJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client';
4
+
5
+ /**
6
+ * Creates a JSON-RPC client that connects to a remote wallet service.
7
+ * The returned object implements the {@link Wallet} interface, proxying all calls over HTTP to the specified URL.
8
+ */
9
+ export function createWalletClient(url: string): Wallet {
10
+ return createSafeJsonRpcClient<Wallet>(url, WalletSchema, {
11
+ namespaceMethods: 'wallet',
12
+ fetch: makeFetch([1, 2, 3], false),
13
+ });
14
+ }
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env -S node --no-warnings
2
+ /**
3
+ * Standalone entrypoint that spins up a local Aztec network (L1 + node) and exposes a {@link NodeEmbeddedWallet} over
4
+ * JSON-RPC.
5
+ *
6
+ * Intended for forward-compatibility testing: an **old** release image runs this script so that **new** tests can send
7
+ * new artifacts to old runtime code (loadContractArtifact, ACIR simulator, class-ID computation, entrypoint encoding,
8
+ * etc.).
9
+ */
10
+ import { getSchnorrAccountContractAddress } from '@aztec/accounts/schnorr';
11
+ import { getInitialTestAccountsData } from '@aztec/accounts/testing';
12
+ import { createLocalNetwork } from '@aztec/aztec';
13
+ import { Fr } from '@aztec/aztec.js/fields';
14
+ import { WalletSchema } from '@aztec/aztec.js/wallet';
15
+ import { GrumpkinScalar } from '@aztec/foundation/curves/grumpkin';
16
+ import { createNamespacedSafeJsonRpcServer, startHttpRpcServer } from '@aztec/foundation/json-rpc/server';
17
+ import { createLogger } from '@aztec/foundation/log';
18
+ import { AztecNodeApiSchema } from '@aztec/stdlib/interfaces/client';
19
+ import { EmbeddedWallet } from '@aztec/wallets/embedded';
20
+
21
+ const logger = createLogger('wallet-service');
22
+
23
+ const { ETHEREUM_HOSTS = 'http://localhost:8545', NODE_PORT = '8080', WALLET_PORT = '8081' } = process.env;
24
+
25
+ async function main() {
26
+ const l1RpcUrls = ETHEREUM_HOSTS.split(',').map(url => url.trim());
27
+
28
+ // Some tests (e.g. AMM) need 4 accounts but only 3 are funded via genesis. Generate deterministic keys for a 4th
29
+ // account so we can compute its address before network startup and include it in genesis funding. We cannot do this
30
+ // in the test because Wallet interface does not expose account creation functionality (only TestWallet exposes that
31
+ // but that's not used in forward compatibility testing).
32
+ const extraAccountSecret = Fr.fromHexString('0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef');
33
+ const extraAccountSalt = Fr.ZERO;
34
+ const extraAccountSigningKey = GrumpkinScalar.random();
35
+ const extraAccountAddress = await getSchnorrAccountContractAddress(
36
+ extraAccountSecret,
37
+ extraAccountSalt,
38
+ extraAccountSigningKey,
39
+ );
40
+
41
+ logger.info('Starting wallet service...', { l1RpcUrls });
42
+
43
+ // createLocalNetwork deploys L1 contracts, starts the node, and optionally deploys funded test accounts (when
44
+ // TEST_ACCOUNTS=true via env). We are not proving anything just like is done when local network is started by
45
+ // the `aztecStart` function. The extra account address is passed via prefundAddresses so it gets fee juice at genesis.
46
+ const { node, stop: stopNetwork } = await createLocalNetwork(
47
+ { l1RpcUrls, realProofs: false, prefundAddresses: [extraAccountAddress.toString()] },
48
+ logger.info,
49
+ );
50
+
51
+ // Create an ephemeral embedded wallet backed by the local node.
52
+ const wallet = await EmbeddedWallet.create(node, { ephemeral: true });
53
+
54
+ // Re-register the initial test accounts so they are available via wallet.getAccounts(). createLocalNetwork deploys
55
+ // them onchain but uses a temporary wallet that is then stopped.
56
+ //
57
+ // We use the non-lazy import path (@aztec/accounts/testing, not /lazy) to avoid the dynamic JSON import that is
58
+ // incompatible with Node.js import attribute enforcement.
59
+ const testAccountsData = await getInitialTestAccountsData();
60
+ const accounts = await Promise.all(
61
+ testAccountsData.map(({ secret, salt, signingKey }) => wallet.createSchnorrAccount(secret, salt, signingKey)),
62
+ );
63
+
64
+ // Register and deploy the 4th account.
65
+ const extraAccount = await wallet.createSchnorrAccount(extraAccountSecret, extraAccountSalt, extraAccountSigningKey);
66
+ const deployMethod = await extraAccount.getDeployMethod();
67
+ await deployMethod.send({ from: accounts[0].address });
68
+
69
+ logger.info('Embedded wallet created', {
70
+ accounts: [...accounts, extraAccount].map(a => a.address.toString()),
71
+ });
72
+
73
+ // Contract artifacts are large, so allow generous body sizes for RPC requests.
74
+ const rpcOptions = { maxBodySizeBytes: '50mb' };
75
+
76
+ // Serve node RPC
77
+ const nodeRpcServer = createNamespacedSafeJsonRpcServer({ node: [node, AztecNodeApiSchema] }, rpcOptions);
78
+ const nodeHttpServer = await startHttpRpcServer(nodeRpcServer, { port: NODE_PORT });
79
+ logger.info(`Node JSON-RPC server listening on port ${nodeHttpServer.port}`);
80
+
81
+ // Serve wallet RPC
82
+ const walletRpcServer = createNamespacedSafeJsonRpcServer({ wallet: [wallet, WalletSchema] }, rpcOptions);
83
+ const walletHttpServer = await startHttpRpcServer(walletRpcServer, { port: WALLET_PORT });
84
+ logger.info(`Wallet JSON-RPC server listening on port ${walletHttpServer.port}`);
85
+
86
+ const shutdown = async () => {
87
+ logger.info('Shutting down...');
88
+ nodeHttpServer.close();
89
+ walletHttpServer.close();
90
+ await wallet.stop();
91
+ await stopNetwork();
92
+ process.exit(0);
93
+ };
94
+
95
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
96
+ process.once('SIGINT', shutdown);
97
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
98
+ process.once('SIGTERM', shutdown);
99
+ }
100
+
101
+ main().catch(err => {
102
+ logger.error('Wallet service failed to start', err);
103
+ process.exit(1);
104
+ });
@@ -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
 
@@ -0,0 +1,135 @@
1
+ // Custom Jest resolver. When CONTRACT_ARTIFACTS_VERSION is set, redirects *only* JSON artifact files under
2
+ // @aztec/noir-contracts.js/artifacts/, @aztec/noir-test-contracts.js/artifacts/, and @aztec/accounts/artifacts/ to a local cache of the pinned
3
+ // legacy versions. TypeScript wrapper classes (e.g. Token.ts) continue to load from the current workspace and use the
4
+ // current @aztec/aztec.js — only the artifact JSON (the deployed-contract ABI / bytecode / notes surface) is swapped.
5
+ //
6
+ // Why JSON-only: the JSON artifact is the actual interchange surface a "deployed contract" exposes. The TS wrapper is
7
+ // generated client-side ergonomics that's tightly coupled to the current @aztec/aztec.js API. Redirecting the wrapper
8
+ // would couple this test to a moving aztec.js surface and break at import time on unrelated breaking changes; we want
9
+ // to fail only on actual artifact-compat regressions.
10
+ //
11
+ // The cache is populated on demand by running `npm install` into .legacy-contracts/<version>/.
12
+ //
13
+ // Activated by env var; passthrough otherwise.
14
+ /* eslint-disable @typescript-eslint/no-require-imports */
15
+
16
+ const path = require('path');
17
+ const fs = require('fs');
18
+ const { execSync } = require('child_process');
19
+
20
+ const version = process.env.CONTRACT_ARTIFACTS_VERSION;
21
+ const REDIRECTED = ['@aztec/noir-contracts.js', '@aztec/noir-test-contracts.js', '@aztec/accounts'];
22
+
23
+ // Jest sets rootDir to <e2e>/src; this file lives there too.
24
+ const e2eRoot = path.resolve(__dirname, '..');
25
+ const cacheRoot = version ? path.join(e2eRoot, '.legacy-contracts', version) : null;
26
+
27
+ function pkgJsonPath(name) {
28
+ return path.join(cacheRoot, 'node_modules', name, 'package.json');
29
+ }
30
+
31
+ function ensureCache() {
32
+ const missing = REDIRECTED.some(p => !fs.existsSync(pkgJsonPath(p)));
33
+ if (!missing) {
34
+ return;
35
+ }
36
+ fs.mkdirSync(cacheRoot, { recursive: true });
37
+ // Seed a standalone package.json so `npm install --prefix` treats cacheRoot as its own project. Without this, npm
38
+ // walks up and finds the yarn-project workspace root, which breaks on `workspace:` protocol deps and risks
39
+ // clobbering the monorepo's node_modules.
40
+ const seed = path.join(cacheRoot, 'package.json');
41
+ if (!fs.existsSync(seed)) {
42
+ fs.writeFileSync(seed, JSON.stringify({ name: 'legacy-contracts-cache', private: true }));
43
+ }
44
+
45
+ const specs = REDIRECTED.map(p => `${p}@${version}`).join(' ');
46
+ process.stderr.write(`[legacy-contracts] installing ${specs} into ${cacheRoot}\n`);
47
+ // --prefix: install into cacheRoot instead of cwd, so the cache is isolated from the monorepo.
48
+ // --no-save: don't write the installed packages back to the seeded package.json.
49
+ // --ignore-scripts: skip lifecycle scripts (preinstall/postinstall) of the legacy packages and their transitive
50
+ // deps; we only want the files on disk, not to run any build steps.
51
+ // --legacy-peer-deps: tolerate peer-dependency mismatches between the pinned legacy @aztec/* graph and whatever
52
+ // current versions npm would otherwise try to reconcile.
53
+ execSync(`npm install --prefix "${cacheRoot}" --no-save --ignore-scripts --legacy-peer-deps ${specs}`, {
54
+ stdio: 'inherit',
55
+ });
56
+
57
+ // Verify versions on disk match the requested version.
58
+ for (const p of REDIRECTED) {
59
+ const onDisk = JSON.parse(fs.readFileSync(pkgJsonPath(p), 'utf8')).version;
60
+ if (onDisk !== version) {
61
+ throw new Error(`[legacy-contracts] ${p} on disk is ${onDisk}, expected ${version}`);
62
+ }
63
+ }
64
+ }
65
+
66
+ if (version) {
67
+ ensureCache();
68
+ }
69
+
70
+ let bannerPrinted = false;
71
+ const seen = new Set();
72
+
73
+ function printBannerOnce() {
74
+ if (bannerPrinted || !version) {
75
+ return;
76
+ }
77
+ bannerPrinted = true;
78
+ const lines = ['='.repeat(60), `[legacy-contracts][jest] CONTRACT_ARTIFACTS_VERSION=${version}`];
79
+ for (const p of REDIRECTED) {
80
+ const v = JSON.parse(fs.readFileSync(pkgJsonPath(p), 'utf8')).version;
81
+ if (v !== version) {
82
+ throw new Error(`[legacy-contracts] ${p} on disk is ${v}, expected ${version}`);
83
+ }
84
+ lines.push(`[legacy-contracts][jest] redirecting ${p}/artifacts/*.json -> .legacy-contracts/${version}/...`);
85
+ }
86
+ lines.push('='.repeat(60));
87
+ process.stderr.write(lines.join('\n') + '\n');
88
+ }
89
+
90
+ // Match a resolved absolute path against the workspace artifacts dirs and return the legacy cache equivalent, or null
91
+ // if it's not an artifact path we should redirect.
92
+ function legacyArtifactPath(resolved) {
93
+ if (!resolved.endsWith('.json')) {
94
+ return null;
95
+ }
96
+ for (const pkg of REDIRECTED) {
97
+ // pkg = '@aztec/noir-contracts.js' -> match '/noir-contracts.js/artifacts/'
98
+ const dirName = pkg.split('/')[1];
99
+ const marker = `/${dirName}/artifacts/`;
100
+ const idx = resolved.indexOf(marker);
101
+ if (idx === -1) {
102
+ continue;
103
+ }
104
+ const basename = resolved.slice(idx + marker.length);
105
+ return path.join(cacheRoot, 'node_modules', pkg, 'artifacts', basename);
106
+ }
107
+ return null;
108
+ }
109
+
110
+ module.exports = function legacyResolver(request, options) {
111
+ // Always run the default resolver first. We only inspect (and possibly rewrite) the *result*; this catches both
112
+ // bare-specifier imports of `@aztec/noir-contracts.js/artifacts/foo.json` and the relative `../artifacts/foo.json`
113
+ // imports inside the workspace TS wrapper classes — both resolve to the same workspace artifact path that we then
114
+ // redirect.
115
+ const resolved = options.defaultResolver(request, options);
116
+ if (!version) {
117
+ return resolved;
118
+ }
119
+ printBannerOnce();
120
+ const legacy = legacyArtifactPath(resolved);
121
+ if (!legacy) {
122
+ return resolved;
123
+ }
124
+ if (!fs.existsSync(legacy)) {
125
+ throw new Error(
126
+ `[legacy-contracts] artifact ${path.basename(legacy)} not present in legacy cache @${version}; ` +
127
+ `the contract may have been added after that release. Pin a newer CONTRACT_ARTIFACTS_VERSION or skip this test.`,
128
+ );
129
+ }
130
+ if (!seen.has(resolved)) {
131
+ seen.add(resolved);
132
+ process.stderr.write(`[legacy-contracts][jest] redirected ${path.basename(legacy)} -> ${legacy}\n`);
133
+ }
134
+ return legacy;
135
+ };
@@ -178,4 +178,3 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
178
178
  }
179
179
  }
180
180
  }
181
- // docs:end:cross_chain_test_harness
@@ -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.
@@ -94,7 +94,9 @@ export class LendingSimulator {
94
94
 
95
95
  async prepare() {
96
96
  this.accumulator = BASE;
97
- const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.timestamp()) + BigInt(this.ethereumSlotDuration));
97
+ const slot = await this.rollup.getSlotAt(
98
+ BigInt(await this.cc.eth.lastBlockTimestamp()) + BigInt(this.ethereumSlotDuration),
99
+ );
98
100
  this.time = Number(await this.rollup.getTimestampForSlot(slot));
99
101
  }
100
102
 
@@ -103,7 +105,7 @@ export class LendingSimulator {
103
105
  return;
104
106
  }
105
107
 
106
- const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.timestamp()));
108
+ const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.lastBlockTimestamp()));
107
109
  const targetSlot = SlotNumber(slot + diff);
108
110
  const ts = Number(await this.rollup.getTimestampForSlot(targetSlot));
109
111
  const timeDiff = ts - this.time;