@aztec/end-to-end 0.0.1-commit.d1cd2107c → 0.0.1-commit.d1da697d6

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 (76) 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 +13 -28
  5. package/dest/e2e_epochs/epochs_test.d.ts +3 -1
  6. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  7. package/dest/e2e_epochs/epochs_test.js +5 -2
  8. package/dest/e2e_fees/fees_test.js +1 -1
  9. package/dest/e2e_p2p/inactivity_slash_test.js +1 -1
  10. package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
  11. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  12. package/dest/e2e_p2p/reqresp/utils.js +15 -2
  13. package/dest/e2e_p2p/shared.d.ts +12 -6
  14. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  15. package/dest/e2e_p2p/shared.js +17 -9
  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 +4 -3
  20. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  21. package/dest/fixtures/e2e_prover_test.js +5 -10
  22. package/dest/fixtures/get_bb_config.d.ts +1 -1
  23. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  24. package/dest/fixtures/get_bb_config.js +5 -5
  25. package/dest/fixtures/setup.d.ts +6 -1
  26. package/dest/fixtures/setup.d.ts.map +1 -1
  27. package/dest/fixtures/setup.js +13 -9
  28. package/dest/fixtures/token_utils.d.ts +1 -1
  29. package/dest/fixtures/token_utils.d.ts.map +1 -1
  30. package/dest/fixtures/token_utils.js +2 -5
  31. package/dest/legacy-jest-resolver.d.cts +3 -0
  32. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  33. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  34. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  35. package/dest/shared/uniswap_l1_l2.js +9 -12
  36. package/dest/simulators/lending_simulator.d.ts +1 -1
  37. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  38. package/dest/simulators/lending_simulator.js +2 -2
  39. package/dest/simulators/token_simulator.js +1 -1
  40. package/dest/spartan/setup_test_wallets.d.ts +4 -2
  41. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  42. package/dest/spartan/setup_test_wallets.js +77 -16
  43. package/dest/spartan/utils/config.d.ts +4 -1
  44. package/dest/spartan/utils/config.d.ts.map +1 -1
  45. package/dest/spartan/utils/config.js +1 -0
  46. package/dest/spartan/utils/index.d.ts +2 -1
  47. package/dest/spartan/utils/index.d.ts.map +1 -1
  48. package/dest/spartan/utils/index.js +2 -0
  49. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  50. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  51. package/dest/spartan/utils/pod_logs.js +74 -0
  52. package/dest/test-wallet/test_wallet.d.ts +15 -23
  53. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  54. package/dest/test-wallet/test_wallet.js +72 -64
  55. package/dest/test-wallet/worker_wallet_schema.d.ts +2 -2
  56. package/package.json +40 -40
  57. package/src/bench/client_flows/client_flows_benchmark.ts +31 -22
  58. package/src/e2e_epochs/epochs_test.ts +14 -2
  59. package/src/e2e_fees/fees_test.ts +1 -1
  60. package/src/e2e_p2p/inactivity_slash_test.ts +1 -1
  61. package/src/e2e_p2p/reqresp/utils.ts +23 -2
  62. package/src/e2e_p2p/shared.ts +20 -10
  63. package/src/fixtures/authwit_proxy.ts +4 -0
  64. package/src/fixtures/e2e_prover_test.ts +7 -15
  65. package/src/fixtures/get_bb_config.ts +7 -6
  66. package/src/fixtures/setup.ts +17 -8
  67. package/src/fixtures/token_utils.ts +1 -4
  68. package/src/legacy-jest-resolver.cjs +135 -0
  69. package/src/shared/uniswap_l1_l2.ts +29 -24
  70. package/src/simulators/lending_simulator.ts +4 -2
  71. package/src/simulators/token_simulator.ts +1 -1
  72. package/src/spartan/setup_test_wallets.ts +102 -14
  73. package/src/spartan/utils/config.ts +1 -0
  74. package/src/spartan/utils/index.ts +3 -0
  75. package/src/spartan/utils/pod_logs.ts +99 -0
  76. package/src/test-wallet/test_wallet.ts +99 -79
@@ -1,3 +1,4 @@
1
+ import { NO_FROM } from '@aztec/aztec.js/account';
1
2
  import { AztecAddress } from '@aztec/aztec.js/addresses';
2
3
  import { FeeJuicePaymentMethodWithClaim } from '@aztec/aztec.js/fee';
3
4
  import { type FeePaymentMethod, PrivateFeePaymentMethod, SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee';
@@ -249,11 +250,14 @@ export class ClientFlowsBenchmark {
249
250
 
250
251
  async applyDeployBananaToken() {
251
252
  this.logger.info('Applying banana token deployment');
252
- const {
253
- receipt: { contract: bananaCoin, instance: bananaCoinInstance },
254
- } = await BananaCoin.deploy(this.adminWallet, this.adminAddress, 'BC', 'BC', 18n).send({
253
+ const { contract: bananaCoin, instance: bananaCoinInstance } = await BananaCoin.deploy(
254
+ this.adminWallet,
255
+ this.adminAddress,
256
+ 'BC',
257
+ 'BC',
258
+ 18n,
259
+ ).send({
255
260
  from: this.adminAddress,
256
- wait: { returnReceipt: true },
257
261
  });
258
262
  this.logger.info(`BananaCoin deployed at ${bananaCoin.address}`);
259
263
  this.bananaCoin = bananaCoin;
@@ -262,11 +266,14 @@ export class ClientFlowsBenchmark {
262
266
 
263
267
  async applyDeployCandyBarToken() {
264
268
  this.logger.info('Applying candy bar token deployment');
265
- const {
266
- receipt: { contract: candyBarCoin, instance: candyBarCoinInstance },
267
- } = await TokenContract.deploy(this.adminWallet, this.adminAddress, 'CBC', 'CBC', 18n).send({
269
+ const { contract: candyBarCoin, instance: candyBarCoinInstance } = await TokenContract.deploy(
270
+ this.adminWallet,
271
+ this.adminAddress,
272
+ 'CBC',
273
+ 'CBC',
274
+ 18n,
275
+ ).send({
268
276
  from: this.adminAddress,
269
- wait: { returnReceipt: true },
270
277
  });
271
278
  this.logger.info(`CandyBarCoin deployed at ${candyBarCoin.address}`);
272
279
  this.candyBarCoin = candyBarCoin;
@@ -279,11 +286,12 @@ export class ClientFlowsBenchmark {
279
286
  expect((await this.context.wallet.getContractMetadata(feeJuiceContract.address)).isContractPublished).toBe(true);
280
287
 
281
288
  const bananaCoin = this.bananaCoin;
282
- const {
283
- receipt: { contract: bananaFPC, instance: bananaFPCInstance },
284
- } = await FPCContract.deploy(this.adminWallet, bananaCoin.address, this.adminAddress).send({
289
+ const { contract: bananaFPC, instance: bananaFPCInstance } = await FPCContract.deploy(
290
+ this.adminWallet,
291
+ bananaCoin.address,
292
+ this.adminAddress,
293
+ ).send({
285
294
  from: this.adminAddress,
286
- wait: { returnReceipt: true },
287
295
  });
288
296
 
289
297
  this.logger.info(`BananaPay deployed at ${bananaFPC.address}`);
@@ -333,7 +341,7 @@ export class ClientFlowsBenchmark {
333
341
  const claim = await this.feeJuiceBridgeTestHarness.prepareTokensOnL1(benchysAddress);
334
342
  const behchysDeployMethod = await benchysAccountManager.getDeployMethod();
335
343
  await behchysDeployMethod.send({
336
- from: AztecAddress.ZERO,
344
+ from: NO_FROM,
337
345
  fee: { paymentMethod: new FeeJuicePaymentMethodWithClaim(benchysAddress, claim) },
338
346
  });
339
347
  // Register benchy on the user's Wallet, where we're going to be interacting from
@@ -347,20 +355,21 @@ export class ClientFlowsBenchmark {
347
355
 
348
356
  public async applyDeployAmm() {
349
357
  this.logger.info('Applying AMM deployment');
350
- const {
351
- receipt: { contract: liquidityToken, instance: liquidityTokenInstance },
352
- } = await TokenContract.deploy(this.adminWallet, this.adminAddress, 'LPT', 'LPT', 18n).send({
358
+ const { contract: liquidityToken, instance: liquidityTokenInstance } = await TokenContract.deploy(
359
+ this.adminWallet,
360
+ this.adminAddress,
361
+ 'LPT',
362
+ 'LPT',
363
+ 18n,
364
+ ).send({
353
365
  from: this.adminAddress,
354
- wait: { returnReceipt: true },
355
366
  });
356
- const {
357
- receipt: { contract: amm, instance: ammInstance },
358
- } = await AMMContract.deploy(
367
+ const { contract: amm, instance: ammInstance } = await AMMContract.deploy(
359
368
  this.adminWallet,
360
369
  this.bananaCoin.address,
361
370
  this.candyBarCoin.address,
362
371
  liquidityToken.address,
363
- ).send({ from: this.adminAddress, wait: { returnReceipt: true } });
372
+ ).send({ from: this.adminAddress });
364
373
  this.logger.info(`AMM deployed at ${amm.address}`);
365
374
  await liquidityToken.methods.set_minter(amm.address, true).send({ from: this.adminAddress });
366
375
  this.liquidityToken = liquidityToken;
@@ -378,7 +387,7 @@ export class ClientFlowsBenchmark {
378
387
  // The private fee paying method assembled on the app side requires knowledge of the maximum
379
388
  // fee the user is willing to pay
380
389
  const maxFeesPerGas = (await this.aztecNode.getCurrentMinFees()).mul(1.5);
381
- const gasSettings = GasSettings.default({ maxFeesPerGas });
390
+ const gasSettings = GasSettings.fallback({ maxFeesPerGas });
382
391
  return new PrivateFeePaymentMethod(this.bananaFPC.address, sender, wallet, gasSettings);
383
392
  }
384
393
 
@@ -28,6 +28,7 @@ import { type SequencerClient, type SequencerEvents, SequencerState } from '@azt
28
28
  import { type BlockParameter, EthAddress } from '@aztec/stdlib/block';
29
29
  import { type L1RollupConstants, getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
30
30
  import { tryStop } from '@aztec/stdlib/interfaces/server';
31
+ import type { SlashingProtectionDatabase } from '@aztec/validator-ha-signer/types';
31
32
 
32
33
  import { join } from 'path';
33
34
  import type { Hex } from 'viem';
@@ -181,6 +182,7 @@ export class EpochsTestContext {
181
182
  ethereumSlotDuration,
182
183
  proofSubmissionEpochs: Number(await this.rollup.getProofSubmissionEpochs()),
183
184
  targetCommitteeSize: await this.rollup.getTargetCommitteeSize(),
185
+ rollupManaLimit: Number(await this.rollup.getManaLimit()),
184
186
  };
185
187
 
186
188
  this.logger.info(
@@ -237,13 +239,21 @@ export class EpochsTestContext {
237
239
 
238
240
  public createValidatorNode(
239
241
  privateKeys: `0x${string}`[],
240
- opts: Partial<AztecNodeConfig> & { dontStartSequencer?: boolean } = {},
242
+ opts: Partial<AztecNodeConfig> & {
243
+ dontStartSequencer?: boolean;
244
+ slashingProtectionDb?: SlashingProtectionDatabase;
245
+ } = {},
241
246
  ) {
242
247
  this.logger.warn('Creating and syncing a validator node...');
243
248
  return this.createNode({ ...opts, disableValidator: false, validatorPrivateKeys: new SecretValue(privateKeys) });
244
249
  }
245
250
 
246
- private async createNode(opts: Partial<AztecNodeConfig> & { dontStartSequencer?: boolean } = {}) {
251
+ private async createNode(
252
+ opts: Partial<AztecNodeConfig> & {
253
+ dontStartSequencer?: boolean;
254
+ slashingProtectionDb?: SlashingProtectionDatabase;
255
+ } = {},
256
+ ) {
247
257
  const nodeIndex = this.nodes.length + 1;
248
258
  const actorPrefix = opts.disableValidator ? 'node' : 'validator';
249
259
  const { mockGossipSubNetwork } = this.context;
@@ -256,6 +266,7 @@ export class EpochsTestContext {
256
266
  ...resolvedConfig,
257
267
  dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
258
268
  validatorPrivateKeys: opts.validatorPrivateKeys ?? new SecretValue([]),
269
+ nodeId: resolvedConfig.nodeId || `${actorPrefix}-${nodeIndex}`,
259
270
  p2pEnabled,
260
271
  p2pIp,
261
272
  },
@@ -264,6 +275,7 @@ export class EpochsTestContext {
264
275
  p2pClientDeps: {
265
276
  p2pServiceFactory: mockGossipSubNetwork ? getMockPubSubP2PServiceFactory(mockGossipSubNetwork) : undefined,
266
277
  },
278
+ slashingProtectionDb: opts.slashingProtectionDb,
267
279
  },
268
280
  {
269
281
  prefilledPublicData: this.context.prefilledPublicData,
@@ -193,7 +193,7 @@ export class FeesTest {
193
193
  this.wallet = this.context.wallet;
194
194
  this.aztecNode = this.context.aztecNodeService;
195
195
  this.aztecNodeAdmin = this.context.aztecNodeService;
196
- this.gasSettings = GasSettings.default({ maxFeesPerGas: (await this.aztecNode.getCurrentMinFees()).mul(2) });
196
+ this.gasSettings = GasSettings.fallback({ maxFeesPerGas: (await this.aztecNode.getCurrentMinFees()).mul(2) });
197
197
  this.cheatCodes = this.context.cheatCodes;
198
198
  this.accounts = deployedAccounts.map(a => a.address);
199
199
  this.accounts.forEach((a, i) => this.logger.verbose(`Account ${i} address: ${a}`));
@@ -58,6 +58,7 @@ export class P2PInactivityTest {
58
58
  basePort: BOOT_NODE_UDP_PORT,
59
59
  startProverNode: true,
60
60
  initialConfig: {
61
+ anvilSlotsInAnEpoch: 4,
61
62
  proverNodeConfig: { proverNodeEpochProvingDelayMs: AZTEC_SLOT_DURATION * 1000 },
62
63
  aztecTargetCommitteeSize: COMMITTEE_SIZE,
63
64
  aztecSlotDuration: AZTEC_SLOT_DURATION,
@@ -66,7 +67,6 @@ export class P2PInactivityTest {
66
67
  listenAddress: '127.0.0.1',
67
68
  minTxsPerBlock: 0,
68
69
  aztecEpochDuration: EPOCH_DURATION,
69
- validatorReexecute: false,
70
70
  sentinelEnabled: true,
71
71
  slashingQuorum: SLASHING_QUORUM,
72
72
  slashingRoundSizeInEpochs: SLASHING_ROUND_SIZE_IN_EPOCHS,
@@ -149,6 +149,13 @@ export async function runReqrespTxTest(params: {
149
149
  const submittedTxs = await Promise.all(
150
150
  txBatches.map(async (batch, batchIndex) => {
151
151
  const proposerNode = nodes[proposerIndexes[batchIndex]];
152
+ for (const tx of batch) {
153
+ t.logger.info(`Tx ${tx.getTxHash().toString()} base64: ${tx.toBuffer().toString('base64')}`);
154
+ }
155
+ const txHashes = batch.map(tx => tx.getTxHash().toString());
156
+ t.logger.info(
157
+ `Sending batch ${batchIndex} to proposer ${getNodePort(proposerIndexes[batchIndex])}: ${txHashes.join(', ')}`,
158
+ );
152
159
  await Promise.all(
153
160
  batch.map(async tx => {
154
161
  try {
@@ -163,6 +170,12 @@ export async function runReqrespTxTest(params: {
163
170
  }),
164
171
  );
165
172
 
173
+ // Log pool state per node after sending
174
+ for (let i = 0; i < NUM_VALIDATORS; i++) {
175
+ const count = await nodes[i].getPendingTxCount();
176
+ t.logger.info(`Node ${getNodePort(i)} pool has ${count} pending txs`);
177
+ }
178
+
166
179
  t.logger.info('Waiting for all transactions to be mined');
167
180
  await Promise.all(
168
181
  submittedTxs.flatMap((batch, batchIndex) =>
@@ -178,8 +191,16 @@ export async function runReqrespTxTest(params: {
178
191
 
179
192
  // Assert that multiple blocks were built for at least one slot
180
193
  t.logger.info('Verifying multiple blocks for at least one checkpoint');
181
- const checkpoints = await nodes[0].getCheckpoints(CheckpointNumber(1), 50);
182
- expect(checkpoints.length).toBeGreaterThan(0);
194
+ // Wait for L1 checkpoint sync, which may lag behind P2P block propagation.
195
+ const checkpoints = await retryUntil(
196
+ async () => {
197
+ const cps = await nodes[0].getCheckpoints(CheckpointNumber(1), 50);
198
+ return cps.length > 0 && cps.some(cp => cp.checkpoint.blocks.length >= 2) ? cps : undefined;
199
+ },
200
+ 'waiting for multi-block checkpoint to sync from L1',
201
+ 30,
202
+ 1,
203
+ );
183
204
 
184
205
  let mbpsFound = false;
185
206
  let expectedBlockNumber = checkpoints[0].checkpoint.blocks[0].number;
@@ -152,11 +152,14 @@ export async function awaitCommitteeExists({
152
152
  }
153
153
 
154
154
  /**
155
- * Advance epochs until we find one where the target proposer is selected for at least one slot.
156
- * With N validators and M slots per epoch, a specific proposer may not be selected in any given epoch.
157
- * For example, with 4 validators and 2 slots/epoch, there is about a 44% chance per epoch.
155
+ * Advance epochs until we find one where the target proposer is selected for at least one slot,
156
+ * then stop one epoch before it. This leaves time for the caller to start sequencers before
157
+ * warping to the target epoch, avoiding the race where the target epoch passes before sequencers
158
+ * are ready.
159
+ *
160
+ * Returns the target epoch number so the caller can warp to it after starting sequencers.
158
161
  */
159
- export async function awaitEpochWithProposer({
162
+ export async function advanceToEpochBeforeProposer({
160
163
  epochCache,
161
164
  cheatCodes,
162
165
  targetProposer,
@@ -168,25 +171,32 @@ export async function awaitEpochWithProposer({
168
171
  targetProposer: EthAddress;
169
172
  logger: Logger;
170
173
  maxAttempts?: number;
171
- }): Promise<void> {
174
+ }): Promise<{ targetEpoch: EpochNumber }> {
172
175
  const { epochDuration } = await cheatCodes.getConfig();
173
176
 
174
177
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
175
178
  const currentEpoch = await cheatCodes.getEpoch();
176
- const startSlot = Number(currentEpoch) * Number(epochDuration);
179
+ // Check the NEXT epoch's slots so we stay one epoch before the target,
180
+ // giving the caller time to start sequencers before the target epoch arrives.
181
+ const nextEpoch = Number(currentEpoch) + 1;
182
+ const startSlot = nextEpoch * Number(epochDuration);
177
183
  const endSlot = startSlot + Number(epochDuration);
178
184
 
179
- logger.info(`Checking epoch ${currentEpoch} (slots ${startSlot}-${endSlot - 1}) for proposer ${targetProposer}`);
185
+ logger.info(
186
+ `Checking next epoch ${nextEpoch} (slots ${startSlot}-${endSlot - 1}) for proposer ${targetProposer} (current epoch: ${currentEpoch})`,
187
+ );
180
188
 
181
189
  for (let s = startSlot; s < endSlot; s++) {
182
190
  const proposer = await epochCache.getProposerAttesterAddressInSlot(SlotNumber(s));
183
191
  if (proposer && proposer.equals(targetProposer)) {
184
- logger.warn(`Found target proposer ${targetProposer} in slot ${s} of epoch ${currentEpoch}`);
185
- return;
192
+ logger.warn(
193
+ `Found target proposer ${targetProposer} in slot ${s} of epoch ${nextEpoch}. Staying at epoch ${currentEpoch} to allow sequencer startup.`,
194
+ );
195
+ return { targetEpoch: EpochNumber(nextEpoch) };
186
196
  }
187
197
  }
188
198
 
189
- logger.info(`Target proposer not found in epoch ${currentEpoch}, advancing to next epoch`);
199
+ logger.info(`Target proposer not found in epoch ${nextEpoch}, advancing to next epoch`);
190
200
  await cheatCodes.advanceToNextEpoch();
191
201
  }
192
202
 
@@ -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
  }
@@ -4,12 +4,7 @@ import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
4
4
  import { type Logger, createLogger } from '@aztec/aztec.js/log';
5
5
  import type { AztecNode } from '@aztec/aztec.js/node';
6
6
  import { CheatCodes } from '@aztec/aztec/testing';
7
- import {
8
- BBCircuitVerifier,
9
- type ClientProtocolCircuitVerifier,
10
- QueuedIVCVerifier,
11
- TestCircuitVerifier,
12
- } from '@aztec/bb-prover';
7
+ import type { ClientProtocolCircuitVerifier } from '@aztec/bb-prover';
13
8
  import { BackendType, Barretenberg } from '@aztec/bb.js';
14
9
  import type { DeployAztecL1ContractsReturnType } from '@aztec/ethereum/deploy-aztec-l1-contracts';
15
10
  import { Buffer32 } from '@aztec/foundation/buffer';
@@ -68,7 +63,10 @@ export class FullProverTest {
68
63
  private provenComponents: ProvenSetup[] = [];
69
64
  private bbConfigCleanup?: () => Promise<void>;
70
65
  private acvmConfigCleanup?: () => Promise<void>;
71
- circuitProofVerifier?: ClientProtocolCircuitVerifier;
66
+ /** Returns the proof verifier from the prover node (for test assertions). */
67
+ get circuitProofVerifier(): ClientProtocolCircuitVerifier | undefined {
68
+ return this.proverAztecNode?.getProofVerifier();
69
+ }
72
70
  provenAsset!: TokenContract;
73
71
  context!: EndToEndContext;
74
72
  private proverAztecNode!: AztecNodeService;
@@ -106,15 +104,13 @@ export class FullProverTest {
106
104
  await publicDeployAccounts(this.wallet, this.accounts.slice(0, 2));
107
105
 
108
106
  this.logger.info('Applying base setup: deploying token contract');
109
- const {
110
- receipt: { contract: asset, instance },
111
- } = await TokenContract.deploy(
107
+ const { contract: asset, instance } = await TokenContract.deploy(
112
108
  this.wallet,
113
109
  this.accounts[0],
114
110
  FullProverTest.TOKEN_NAME,
115
111
  FullProverTest.TOKEN_SYMBOL,
116
112
  FullProverTest.TOKEN_DECIMALS,
117
- ).send({ from: this.accounts[0], wait: { returnReceipt: true } });
113
+ ).send({ from: this.accounts[0] });
118
114
  this.logger.verbose(`Token deployed to ${asset.address}`);
119
115
 
120
116
  this.fakeProofsAsset = asset;
@@ -170,9 +166,6 @@ export class FullProverTest {
170
166
 
171
167
  await Barretenberg.initSingleton({ backend: BackendType.NativeUnixSocket });
172
168
 
173
- const verifier = await BBCircuitVerifier.new(bbConfig);
174
- this.circuitProofVerifier = new QueuedIVCVerifier(bbConfig, verifier);
175
-
176
169
  this.logger.debug(`Configuring the node for real proofs...`);
177
170
  await this.aztecNodeAdmin.setConfig({
178
171
  realProofs: true,
@@ -180,7 +173,6 @@ export class FullProverTest {
180
173
  });
181
174
  } else {
182
175
  this.logger.debug(`Configuring the node min txs per block ${this.minNumberOfTxsPerBlock}...`);
183
- this.circuitProofVerifier = new TestCircuitVerifier();
184
176
  await this.aztecNodeAdmin.setConfig({
185
177
  minTxsPerBlock: this.minNumberOfTxsPerBlock,
186
178
  });
@@ -13,8 +13,10 @@ const {
13
13
  BB_SKIP_CLEANUP = '',
14
14
  TEMP_DIR = tmpdir(),
15
15
  BB_WORKING_DIRECTORY = '',
16
- BB_NUM_IVC_VERIFIERS = '1',
16
+ BB_NUM_IVC_VERIFIERS = '8',
17
17
  BB_IVC_CONCURRENCY = '1',
18
+ BB_CHONK_VERIFY_MAX_BATCH = '16',
19
+ BB_CHONK_VERIFY_BATCH_CONCURRENCY = '6',
18
20
  } = process.env;
19
21
 
20
22
  export const getBBConfig = async (
@@ -41,16 +43,15 @@ export const getBBConfig = async (
41
43
  const bbSkipCleanup = ['1', 'true'].includes(BB_SKIP_CLEANUP);
42
44
  const cleanup = bbSkipCleanup ? () => Promise.resolve() : () => tryRmDir(directoryToCleanup);
43
45
 
44
- const numIvcVerifiers = Number(BB_NUM_IVC_VERIFIERS);
45
- const ivcConcurrency = Number(BB_IVC_CONCURRENCY);
46
-
47
46
  return {
48
47
  bbSkipCleanup,
49
48
  bbBinaryPath,
50
49
  bbWorkingDirectory,
51
50
  cleanup,
52
- numConcurrentIVCVerifiers: numIvcVerifiers,
53
- bbIVCConcurrency: ivcConcurrency,
51
+ numConcurrentIVCVerifiers: Number(BB_NUM_IVC_VERIFIERS),
52
+ bbIVCConcurrency: Number(BB_IVC_CONCURRENCY),
53
+ bbChonkVerifyMaxBatch: Number(BB_CHONK_VERIFY_MAX_BATCH),
54
+ bbChonkVerifyConcurrency: Number(BB_CHONK_VERIFY_BATCH_CONCURRENCY),
54
55
  };
55
56
  } catch (err) {
56
57
  logger.error(`Native BB not available, error: ${err}`);
@@ -1,6 +1,7 @@
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,
@@ -185,6 +186,11 @@ export type SetupOptions = {
185
186
  anvilAccounts?: number;
186
187
  /** Port to start anvil (defaults to 8545) */
187
188
  anvilPort?: number;
189
+ /**
190
+ * Number of slots per epoch for Anvil's finality simulation.
191
+ * Anvil reports `finalized = latest - slotsInAnEpoch * 2`.
192
+ */
193
+ anvilSlotsInAnEpoch?: number;
188
194
  /** Key to use for publishing L1 contracts */
189
195
  l1PublisherKey?: SecretValue<`0x${string}`>;
190
196
  /** ZkPassport configuration (domain, scope, mock verifier) */
@@ -297,6 +303,8 @@ export async function setup(
297
303
  config.dataDirectory = directoryToCleanup;
298
304
  }
299
305
 
306
+ const dateProvider = new TestDateProvider();
307
+
300
308
  if (!config.l1RpcUrls?.length) {
301
309
  if (!isAnvilTestChain(chain.id)) {
302
310
  throw new Error(`No ETHEREUM_HOSTS set but non anvil chain requested`);
@@ -305,6 +313,8 @@ export async function setup(
305
313
  l1BlockTime: opts.ethereumSlotDuration,
306
314
  accounts: opts.anvilAccounts,
307
315
  port: opts.anvilPort ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : undefined),
316
+ slotsInAnEpoch: opts.anvilSlotsInAnEpoch,
317
+ dateProvider,
308
318
  });
309
319
  anvil = res.anvil;
310
320
  config.l1RpcUrls = [res.rpcUrl];
@@ -316,8 +326,6 @@ export async function setup(
316
326
  logger.info(`Logging metrics to ${filename}`);
317
327
  setupMetricsLogger(filename);
318
328
  }
319
-
320
- const dateProvider = new TestDateProvider();
321
329
  const ethCheatCodes = new EthCheatCodesWithState(config.l1RpcUrls, dateProvider);
322
330
 
323
331
  if (opts.stateLoad) {
@@ -413,11 +421,12 @@ export async function setup(
413
421
  await ethCheatCodes.setIntervalMining(config.ethereumSlotDuration);
414
422
  }
415
423
 
416
- // Always sync dateProvider to L1 time after deploying L1 contracts, regardless of mining mode.
417
- // In compose mode, L1 time may have drifted ahead of system time due to the local-network watcher
418
- // warping time forward on each filled slot. Without this sync, the sequencer computes the wrong
419
- // slot from its dateProvider and cannot propose blocks.
420
- dateProvider.setTime((await ethCheatCodes.timestamp()) * 1000);
424
+ // In compose mode (no local anvil), sync dateProvider to L1 time since it may have drifted
425
+ // ahead of system time due to the local-network watcher warping time forward on each filled slot.
426
+ // When running with a local anvil, the dateProvider is kept in sync via the stdout listener.
427
+ if (!anvil) {
428
+ dateProvider.setTime((await ethCheatCodes.lastBlockTimestamp()) * 1000);
429
+ }
421
430
 
422
431
  if (opts.l2StartTime) {
423
432
  await ethCheatCodes.warp(opts.l2StartTime, { resetBlockInterval: true });
@@ -841,7 +850,7 @@ export const deployAccounts =
841
850
  );
842
851
  const deployMethod = await accountManager.getDeployMethod();
843
852
  await deployMethod.send({
844
- from: AztecAddress.ZERO,
853
+ from: NO_FROM,
845
854
  skipClassPublication: i !== 0, // Publish the contract class at most once.
846
855
  });
847
856
  }
@@ -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,135 @@
1
+ // Custom Jest resolver. When CONTRACT_ARTIFACTS_VERSION is set, redirects *only* JSON artifact files under
2
+ // @aztec/noir-contracts.js/artifacts/ and @aztec/noir-test-contracts.js/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'];
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
+ };