@aztec/end-to-end 0.0.1-commit.2d9cb6034 → 0.0.1-commit.2e20a94

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 (56) hide show
  1. package/README.md +27 -0
  2. package/dest/bench/client_flows/client_flows_benchmark.js +1 -1
  3. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +3 -2
  4. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  5. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +1 -1
  6. package/dest/e2e_epochs/epochs_test.js +3 -3
  7. package/dest/e2e_fees/fees_test.js +1 -1
  8. package/dest/e2e_p2p/inactivity_slash_test.js +2 -2
  9. package/dest/e2e_p2p/p2p_network.d.ts +5 -7
  10. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  11. package/dest/e2e_p2p/p2p_network.js +14 -13
  12. package/dest/e2e_p2p/reqresp/utils.js +1 -1
  13. package/dest/e2e_p2p/shared.d.ts +5 -7
  14. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  15. package/dest/e2e_p2p/shared.js +16 -42
  16. package/dest/fixtures/authwit_proxy.d.ts +1 -1
  17. package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
  18. package/dest/fixtures/authwit_proxy.js +4 -0
  19. package/dest/fixtures/e2e_prover_test.d.ts +1 -1
  20. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  21. package/dest/fixtures/e2e_prover_test.js +2 -2
  22. package/dest/fixtures/setup.d.ts +11 -8
  23. package/dest/fixtures/setup.d.ts.map +1 -1
  24. package/dest/fixtures/setup.js +11 -9
  25. package/dest/fixtures/setup_p2p_test.d.ts +6 -6
  26. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  27. package/dest/fixtures/setup_p2p_test.js +8 -8
  28. package/dest/legacy-jest-resolver.d.cts +3 -0
  29. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  30. package/dest/spartan/setup_test_wallets.d.ts +1 -1
  31. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  32. package/dest/spartan/setup_test_wallets.js +7 -39
  33. package/dest/test-wallet/test_wallet.d.ts +16 -8
  34. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  35. package/dest/test-wallet/test_wallet.js +82 -46
  36. package/dest/test-wallet/worker_wallet.d.ts +4 -4
  37. package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
  38. package/dest/test-wallet/worker_wallet_schema.d.ts +7 -2
  39. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
  40. package/package.json +40 -39
  41. package/src/bench/client_flows/client_flows_benchmark.ts +1 -1
  42. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +3 -6
  43. package/src/e2e_epochs/epochs_test.ts +3 -3
  44. package/src/e2e_fees/fees_test.ts +1 -1
  45. package/src/e2e_p2p/inactivity_slash_test.ts +2 -2
  46. package/src/e2e_p2p/p2p_network.ts +22 -27
  47. package/src/e2e_p2p/reqresp/utils.ts +1 -1
  48. package/src/e2e_p2p/shared.ts +16 -57
  49. package/src/fixtures/authwit_proxy.ts +4 -0
  50. package/src/fixtures/e2e_prover_test.ts +5 -2
  51. package/src/fixtures/setup.ts +21 -17
  52. package/src/fixtures/setup_p2p_test.ts +9 -9
  53. package/src/legacy-jest-resolver.cjs +135 -0
  54. package/src/spartan/setup_test_wallets.ts +5 -31
  55. package/src/test-wallet/test_wallet.ts +100 -50
  56. package/src/test-wallet/worker_wallet.ts +3 -2
@@ -3,12 +3,7 @@ import type { AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
3
3
  import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
4
4
  import { Fr } from '@aztec/aztec.js/fields';
5
5
  import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
6
- import {
7
- type EmpireSlashingProposerContract,
8
- GSEContract,
9
- RollupContract,
10
- type TallySlashingProposerContract,
11
- } from '@aztec/ethereum/contracts';
6
+ import { GSEContract, RollupContract, type SlashingProposerContract } from '@aztec/ethereum/contracts';
12
7
  import type { Operator } from '@aztec/ethereum/deploy-aztec-l1-contracts';
13
8
  import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract';
14
9
  import { MultiAdderArtifact } from '@aztec/ethereum/l1-artifacts';
@@ -24,9 +19,9 @@ import { SpamContract } from '@aztec/noir-test-contracts.js/Spam';
24
19
  import type { BootstrapNode } from '@aztec/p2p/bootstrap';
25
20
  import { createBootstrapNodeFromPrivateKey, getBootstrapNodeEnr } from '@aztec/p2p/test-helpers';
26
21
  import { tryStop } from '@aztec/stdlib/interfaces/server';
27
- import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
28
22
  import { TopicType } from '@aztec/stdlib/p2p';
29
- import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
23
+ import { TxStatus } from '@aztec/stdlib/tx';
24
+ import type { GenesisData } from '@aztec/stdlib/world-state';
30
25
  import { ZkPassportProofParams } from '@aztec/stdlib/zkpassport';
31
26
  import { getGenesisValues } from '@aztec/world-state/testing';
32
27
 
@@ -77,7 +72,7 @@ export class P2PNetworkTest {
77
72
  public validators: Operator[] = [];
78
73
 
79
74
  public deployedAccounts: InitialAccountData[] = [];
80
- public prefilledPublicData: PublicDataTreeLeaf[] = [];
75
+ public genesis: GenesisData | undefined;
81
76
 
82
77
  // The re-execution test needs a wallet and a spam contract
83
78
  public wallet?: TestWallet;
@@ -124,7 +119,7 @@ export class P2PNetworkTest {
124
119
  initialValidatorConfig.aztecProofSubmissionEpochs ?? l1ContractsConfig.aztecProofSubmissionEpochs,
125
120
  slashingRoundSizeInEpochs:
126
121
  initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs,
127
- slasherFlavor: initialValidatorConfig.slasherFlavor ?? 'tally',
122
+ slasherEnabled: initialValidatorConfig.slasherEnabled ?? true,
128
123
  aztecTargetCommitteeSize: numberOfValidators,
129
124
  metricsPort: metricsPort,
130
125
  numberOfInitialFundedAccounts: 2,
@@ -137,7 +132,7 @@ export class P2PNetworkTest {
137
132
  aztecEpochDuration: initialValidatorConfig.aztecEpochDuration ?? l1ContractsConfig.aztecEpochDuration,
138
133
  slashingRoundSizeInEpochs:
139
134
  initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs,
140
- slasherFlavor: initialValidatorConfig.slasherFlavor ?? 'tally',
135
+ slasherEnabled: initialValidatorConfig.slasherEnabled ?? true,
141
136
 
142
137
  ethereumSlotDuration: initialValidatorConfig.ethereumSlotDuration ?? l1ContractsConfig.ethereumSlotDuration,
143
138
  aztecSlotDuration: initialValidatorConfig.aztecSlotDuration ?? l1ContractsConfig.aztecSlotDuration,
@@ -305,10 +300,11 @@ export class P2PNetworkTest {
305
300
 
306
301
  async setupAccount() {
307
302
  this.logger.info('Setting up account');
308
- const { deployedAccounts } = await deployAccounts(
309
- 1,
310
- this.logger,
311
- )({
303
+ const { deployedAccounts } = await deployAccounts(1, this.logger, {
304
+ wait: {
305
+ waitForStatus: TxStatus.CHECKPOINTED,
306
+ },
307
+ })({
312
308
  wallet: this.context.wallet,
313
309
  initialFundedAccounts: this.context.initialFundedAccounts,
314
310
  });
@@ -360,7 +356,7 @@ export class P2PNetworkTest {
360
356
  ...this.setupOptions,
361
357
  fundSponsoredFPC: true,
362
358
  skipAccountDeployment: true,
363
- slasherFlavor: this.setupOptions.slasherFlavor ?? this.deployL1ContractsArgs.slasherFlavor ?? 'none',
359
+ slasherEnabled: this.setupOptions.slasherEnabled ?? this.deployL1ContractsArgs.slasherEnabled ?? false,
364
360
  aztecTargetCommitteeSize: 0,
365
361
  l1ContractsArgs: this.deployL1ContractsArgs,
366
362
  },
@@ -372,8 +368,13 @@ export class P2PNetworkTest {
372
368
  const sponsoredFPCAddress = await getSponsoredFPCAddress();
373
369
  const initialFundedAccounts = [...this.context.initialFundedAccounts.map(a => a.address), sponsoredFPCAddress];
374
370
 
375
- const { prefilledPublicData } = await getGenesisValues(initialFundedAccounts);
376
- this.prefilledPublicData = prefilledPublicData;
371
+ const { genesis } = await getGenesisValues(
372
+ initialFundedAccounts,
373
+ undefined,
374
+ undefined,
375
+ this.context.genesis!.genesisTimestamp,
376
+ );
377
+ this.genesis = genesis;
377
378
 
378
379
  const rollupContract = RollupContract.getFromL1ContractsValues(this.context.deployL1ContractsValues);
379
380
  this.monitor = new ChainMonitor(rollupContract, this.context.dateProvider).start();
@@ -468,8 +469,7 @@ export class P2PNetworkTest {
468
469
  async getContracts(): Promise<{
469
470
  rollup: RollupContract;
470
471
  slasherContract: GetContractReturnType<typeof SlasherAbi, ViemClient>;
471
- slashingProposer: EmpireSlashingProposerContract | TallySlashingProposerContract | undefined;
472
- slashFactory: SlashFactoryContract;
472
+ slashingProposer: SlashingProposerContract | undefined;
473
473
  }> {
474
474
  if (!this.ctx.deployL1ContractsValues) {
475
475
  throw new Error('DeployAztecL1ContractsValues not set');
@@ -486,14 +486,9 @@ export class P2PNetworkTest {
486
486
  client: this.ctx.deployL1ContractsValues.l1Client,
487
487
  });
488
488
 
489
- // Get the actual slashing proposer from rollup (which handles both empire and tally)
489
+ // Get the actual slashing proposer from rollup
490
490
  const slashingProposer = await rollup.getSlashingProposer();
491
491
 
492
- const slashFactory = new SlashFactoryContract(
493
- this.ctx.deployL1ContractsValues.l1Client,
494
- getAddress(this.ctx.deployL1ContractsValues.l1ContractAddresses.slashFactoryAddress!.toString()),
495
- );
496
-
497
- return { rollup, slasherContract, slashingProposer, slashFactory };
492
+ return { rollup, slasherContract, slashingProposer };
498
493
  }
499
494
  }
@@ -91,7 +91,7 @@ export async function runReqrespTxTest(params: {
91
91
  t.bootstrapNodeEnr,
92
92
  NUM_VALIDATORS,
93
93
  BOOT_NODE_UDP_PORT,
94
- t.prefilledPublicData,
94
+ t.genesis,
95
95
  dataDir,
96
96
  shouldCollectMetrics(),
97
97
  );
@@ -7,11 +7,7 @@ import type { Logger } from '@aztec/aztec.js/log';
7
7
  import { TxHash } from '@aztec/aztec.js/tx';
8
8
  import type { RollupCheatCodes } from '@aztec/aztec/testing';
9
9
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
10
- import type {
11
- EmpireSlashingProposerContract,
12
- RollupContract,
13
- TallySlashingProposerContract,
14
- } from '@aztec/ethereum/contracts';
10
+ import type { RollupContract, SlashingProposerContract } from '@aztec/ethereum/contracts';
15
11
  import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
16
12
  import { timesAsync, unique } from '@aztec/foundation/collection';
17
13
  import { EthAddress } from '@aztec/foundation/eth-address';
@@ -22,7 +18,6 @@ import { TestContract, TestContractArtifact } from '@aztec/noir-test-contracts.j
22
18
  import { getPXEConfig, getPXEConfig as getRpcConfig } from '@aztec/pxe/server';
23
19
  import { getRoundForOffense } from '@aztec/slasher';
24
20
  import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
25
- import type { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
26
21
 
27
22
  import { submitTxsTo } from '../shared/submit-transactions.js';
28
23
  import { TestWallet } from '../test-wallet/test_wallet.js';
@@ -99,7 +94,7 @@ export async function prepareTransactions(
99
94
  }
100
95
 
101
96
  export function awaitProposalExecution(
102
- slashingProposer: EmpireSlashingProposerContract | TallySlashingProposerContract,
97
+ slashingProposer: SlashingProposerContract,
103
98
  timeoutSeconds: number,
104
99
  logger: Logger,
105
100
  ): Promise<bigint> {
@@ -109,24 +104,12 @@ export function awaitProposalExecution(
109
104
  reject(new Error(`Timeout waiting for proposal execution after ${timeoutSeconds}s`));
110
105
  }, timeoutSeconds * 1000);
111
106
 
112
- if (slashingProposer.type === 'empire') {
113
- const unwatch = slashingProposer.listenToPayloadSubmitted(args => {
114
- logger.warn(`Proposal ${args.payload} from round ${args.round} executed`);
115
- clearTimeout(timeout);
116
- unwatch();
117
- resolve(args.round);
118
- });
119
- } else if (slashingProposer.type === 'tally') {
120
- const unwatch = slashingProposer.listenToRoundExecuted(args => {
121
- logger.warn(`Slash from round ${args.round} executed`);
122
- clearTimeout(timeout);
123
- unwatch();
124
- resolve(args.round);
125
- });
126
- } else {
107
+ const unwatch = slashingProposer.listenToRoundExecuted(args => {
108
+ logger.warn(`Slash from round ${args.round} executed`);
127
109
  clearTimeout(timeout);
128
- reject(new Error(`Unknown slashing proposer type: ${(slashingProposer as any).type}`));
129
- }
110
+ unwatch();
111
+ resolve(args.round);
112
+ });
130
113
  });
131
114
  }
132
115
 
@@ -245,7 +228,6 @@ export async function awaitCommitteeKicked({
245
228
  rollup,
246
229
  cheatCodes,
247
230
  committee,
248
- slashFactory,
249
231
  slashingProposer,
250
232
  slashingRoundSize,
251
233
  aztecSlotDuration,
@@ -256,8 +238,7 @@ export async function awaitCommitteeKicked({
256
238
  rollup: RollupContract;
257
239
  cheatCodes: RollupCheatCodes;
258
240
  committee: readonly `0x${string}`[];
259
- slashFactory: SlashFactoryContract;
260
- slashingProposer: EmpireSlashingProposerContract | TallySlashingProposerContract | undefined;
241
+ slashingProposer: SlashingProposerContract | undefined;
261
242
  slashingRoundSize: number;
262
243
  aztecSlotDuration: number;
263
244
  aztecEpochDuration: number;
@@ -270,36 +251,14 @@ export async function awaitCommitteeKicked({
270
251
 
271
252
  await cheatCodes.debugRollup();
272
253
 
273
- if (slashingProposer.type === 'empire') {
274
- // Await for the slash payload to be created if empire (no payload is created on tally until execution time)
275
- const targetEpoch = EpochNumber((await cheatCodes.getEpoch()) + (await rollup.getLagInEpochsForValidatorSet()) + 1);
276
- logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
277
- await cheatCodes.advanceToEpoch(targetEpoch);
278
-
279
- const slashPayloadEvents = await retryUntil(
280
- async () => {
281
- const events = await slashFactory.getSlashPayloadCreatedEvents();
282
- return events.length > 0 ? events : undefined;
283
- },
284
- 'slash payload created',
285
- 120,
286
- 1,
287
- );
288
- expect(slashPayloadEvents.length).toBe(1);
289
- // The uniqueness check is needed since a validator may be slashed more than once on the same round (eg because they let two epochs be pruned)
290
- expect(unique(slashPayloadEvents[0].slashes.map(slash => slash.validator.toString()))).toHaveLength(
291
- committee.length,
292
- );
293
- } else {
294
- // Use the slash offset to ensure we are in the right epoch for tally
295
- const slashOffsetInRounds = await slashingProposer.getSlashOffsetInRounds();
296
- const slashingRoundSizeInEpochs = slashingRoundSize / aztecEpochDuration;
297
- const slashingOffsetInEpochs = Number(slashOffsetInRounds) * slashingRoundSizeInEpochs;
298
- const firstEpochInOffenseRound = offenseEpoch - (offenseEpoch % slashingRoundSizeInEpochs);
299
- const targetEpoch = firstEpochInOffenseRound + slashingOffsetInEpochs;
300
- logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
301
- await cheatCodes.advanceToEpoch(EpochNumber(targetEpoch), { offset: -aztecSlotDuration / 2 });
302
- }
254
+ // Use the slash offset to ensure we are in the right epoch for tally
255
+ const slashOffsetInRounds = await slashingProposer.getSlashOffsetInRounds();
256
+ const slashingRoundSizeInEpochs = slashingRoundSize / aztecEpochDuration;
257
+ const slashingOffsetInEpochs = Number(slashOffsetInRounds) * slashingRoundSizeInEpochs;
258
+ const firstEpochInOffenseRound = offenseEpoch - (offenseEpoch % slashingRoundSizeInEpochs);
259
+ const targetEpoch = firstEpochInOffenseRound + slashingOffsetInEpochs;
260
+ logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
261
+ await cheatCodes.advanceToEpoch(EpochNumber(targetEpoch), { offset: -aztecSlotDuration / 2 });
303
262
 
304
263
  const attestersPre = await rollup.getAttesters();
305
264
  expect(attestersPre.length).toBe(committee.length);
@@ -17,6 +17,10 @@ async function buildProxyCall(proxy: GenericProxyContract, action: ContractFunct
17
17
  return proxy.methods.forward_private_3(call.to, call.selector, call.args);
18
18
  } else if (argCount === 4) {
19
19
  return proxy.methods.forward_private_4(call.to, call.selector, call.args);
20
+ } else if (argCount === 5) {
21
+ return proxy.methods.forward_private_5(call.to, call.selector, call.args);
22
+ } else if (argCount === 6) {
23
+ return proxy.methods.forward_private_6(call.to, call.selector, call.args);
20
24
  }
21
25
  throw new Error(`No forward_private_${argCount} method on proxy`);
22
26
  }
@@ -223,8 +223,11 @@ export class FullProverTest {
223
223
 
224
224
  this.logger.verbose('Starting prover node');
225
225
  const sponsoredFPCAddress = await getSponsoredFPCAddress();
226
- const { prefilledPublicData } = await getGenesisValues(
226
+ const { genesis } = await getGenesisValues(
227
227
  this.context.initialFundedAccounts.map(a => a.address).concat(sponsoredFPCAddress),
228
+ undefined,
229
+ undefined,
230
+ this.context.genesis!.genesisTimestamp,
228
231
  );
229
232
 
230
233
  const proverNodeConfig: Parameters<typeof AztecNodeService.createAndSync>[0] = {
@@ -252,7 +255,7 @@ export class FullProverTest {
252
255
  this.proverAztecNode = await AztecNodeService.createAndSync(
253
256
  proverNodeConfig,
254
257
  { dateProvider: this.context.dateProvider, p2pClientDeps: { rpcTxProviders: [this.aztecNode] } },
255
- { prefilledPublicData },
258
+ { genesis },
256
259
  );
257
260
  this.logger.warn(`Proofs are now enabled`, { realProofs: this.realProofs });
258
261
  return this;
@@ -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';
@@ -49,9 +51,10 @@ import type { ProverNodeConfig } from '@aztec/prover-node';
49
51
  import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
50
52
  import type { SequencerClient } from '@aztec/sequencer-client';
51
53
  import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
52
- import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
54
+ import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
53
55
  import { tryStop } from '@aztec/stdlib/interfaces/server';
54
56
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
57
+ import type { GenesisData } from '@aztec/stdlib/world-state';
55
58
  import {
56
59
  type TelemetryClient,
57
60
  type TelemetryClientConfig,
@@ -178,6 +181,8 @@ export type SetupOptions = {
178
181
  proverNodeConfig?: Partial<ProverNodeConfig>;
179
182
  /** Whether to use a mock gossip sub network for p2p clients. */
180
183
  mockGossipSubNetwork?: boolean;
184
+ /** Whether to add simulated latency to the mock gossipsub network (in ms) */
185
+ mockGossipSubNetworkLatency?: number;
181
186
  /** Whether to disable the anvil test watcher (can still be manually started) */
182
187
  disableAnvilTestWatcher?: boolean;
183
188
  /** Whether to enable anvil automine during deployment of L1 contracts (consider defaulting this to true). */
@@ -210,7 +215,7 @@ export type EndToEndContext = {
210
215
  /** The Anvil instance (only set if anvil was started locally). */
211
216
  anvil: Anvil | undefined;
212
217
  /** The Aztec Node service or client a connected to it. */
213
- aztecNode: AztecNode;
218
+ aztecNode: AztecNode & AztecNodeDebug;
214
219
  /** The Aztec Node as a service. */
215
220
  aztecNodeService: AztecNodeService;
216
221
  /** Client to the Aztec Node admin interface. */
@@ -249,8 +254,8 @@ export type EndToEndContext = {
249
254
  sequencerDelayer: Delayer | undefined;
250
255
  /** Delayer for prover node L1 txs (only when enableDelayer and startProverNode are true). */
251
256
  proverDelayer: Delayer | undefined;
252
- /** Prefilled public data used for setting up nodes. */
253
- prefilledPublicData: PublicDataTreeLeaf[] | undefined;
257
+ /** Genesis data used for setting up nodes. */
258
+ genesis: GenesisData | undefined;
254
259
  /** ACVM config (only set if running locally). */
255
260
  acvmConfig: Awaited<ReturnType<typeof getACVMConfig>>;
256
261
  /** BB config (only set if running locally). */
@@ -276,7 +281,7 @@ export async function setup(
276
281
  let anvil: Anvil | undefined;
277
282
  try {
278
283
  opts.aztecTargetCommitteeSize ??= 0;
279
- opts.slasherFlavor ??= 'none';
284
+ opts.slasherEnabled ??= false;
280
285
 
281
286
  const config: AztecNodeConfig & SetupOptions = { ...getConfigEnvVars(), ...opts };
282
287
  // use initialValidators for the node config
@@ -375,10 +380,12 @@ export async function setup(
375
380
  addressesToFund.push(sponsoredFPCAddress);
376
381
  }
377
382
 
378
- const { genesisArchiveRoot, prefilledPublicData, fundingNeeded } = await getGenesisValues(
383
+ const genesisTimestamp = BigInt(Math.floor(Date.now() / 1000));
384
+ const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(
379
385
  addressesToFund,
380
386
  opts.initialAccountFeeJuice,
381
387
  opts.genesisPublicData,
388
+ genesisTimestamp,
382
389
  );
383
390
 
384
391
  const wasAutomining = await ethCheatCodes.isAutoMining();
@@ -467,7 +474,7 @@ export async function setup(
467
474
  let p2pClientDeps: P2PClientDeps | undefined = undefined;
468
475
 
469
476
  if (opts.mockGossipSubNetwork) {
470
- mockGossipSubNetwork = new MockGossipSubNetwork();
477
+ mockGossipSubNetwork = new MockGossipSubNetwork(opts.mockGossipSubNetworkLatency);
471
478
  p2pClientDeps = { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) };
472
479
  }
473
480
 
@@ -496,11 +503,7 @@ export async function setup(
496
503
  }
497
504
 
498
505
  const aztecNodeService = await withLoggerBindings({ actor: 'node-0' }, () =>
499
- AztecNodeService.createAndSync(
500
- config,
501
- { dateProvider, telemetry: telemetryClient, p2pClientDeps },
502
- { prefilledPublicData },
503
- ),
506
+ AztecNodeService.createAndSync(config, { dateProvider, telemetry: telemetryClient, p2pClientDeps }, { genesis }),
504
507
  );
505
508
  const sequencerClient = aztecNodeService.getSequencer();
506
509
 
@@ -524,7 +527,7 @@ export async function setup(
524
527
  dataDirectory: proverNodeDataDirectory,
525
528
  },
526
529
  { dateProvider, p2pClientDeps, telemetry: telemetryClient },
527
- { prefilledPublicData },
530
+ { genesis },
528
531
  ));
529
532
  }
530
533
 
@@ -629,7 +632,7 @@ export async function setup(
629
632
  initialFundedAccounts,
630
633
  logger,
631
634
  mockGossipSubNetwork,
632
- prefilledPublicData,
635
+ genesis,
633
636
  proverNode,
634
637
  sequencerDelayer,
635
638
  proverDelayer,
@@ -729,7 +732,7 @@ export function createAndSyncProverNode(
729
732
  dateProvider: DateProvider;
730
733
  p2pClientDeps?: P2PClientDeps;
731
734
  },
732
- options: { prefilledPublicData: PublicDataTreeLeaf[]; dontStart?: boolean },
735
+ options: { genesis?: GenesisData; dontStart?: boolean },
733
736
  ): Promise<{ proverNode: AztecNodeService }> {
734
737
  return withLoggerBindings({ actor: 'prover-0' }, async () => {
735
738
  const proverNode = await AztecNodeService.createAndSync(
@@ -742,7 +745,7 @@ export function createAndSyncProverNode(
742
745
  proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
743
746
  },
744
747
  deps,
745
- { ...options, dontStartProverNode: options.dontStart },
748
+ { genesis: options.genesis, dontStartProverNode: options.dontStart },
746
749
  );
747
750
 
748
751
  if (!proverNode.getProverNode()) {
@@ -833,7 +836,7 @@ export async function ensureAccountContractsPublished(wallet: Wallet, accountsTo
833
836
  * Returns deployed account data that can be used by tests.
834
837
  */
835
838
  export const deployAccounts =
836
- (numberOfAccounts: number, logger: Logger) =>
839
+ (numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<DeployInteractionWaitOptions>>) =>
837
840
  async ({ wallet, initialFundedAccounts }: { wallet: TestWallet; initialFundedAccounts: InitialAccountData[] }) => {
838
841
  if (initialFundedAccounts.length < numberOfAccounts) {
839
842
  throw new Error(`Cannot deploy more than ${initialFundedAccounts.length} initial accounts.`);
@@ -852,6 +855,7 @@ export const deployAccounts =
852
855
  await deployMethod.send({
853
856
  from: NO_FROM,
854
857
  skipClassPublication: i !== 0, // Publish the contract class at most once.
858
+ ...deployOptions,
855
859
  });
856
860
  }
857
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
  }
@@ -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
+ };