@aztec/end-to-end 0.86.0 → 0.87.0-nightly.20250521

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 (94) hide show
  1. package/dest/bench/client_flows/client_flows_benchmark.js +1 -1
  2. package/dest/bench/client_flows/config.d.ts +1 -1
  3. package/dest/bench/client_flows/config.d.ts.map +1 -1
  4. package/dest/bench/client_flows/config.js +22 -3
  5. package/dest/bench/client_flows/data_extractor.d.ts.map +1 -1
  6. package/dest/bench/client_flows/data_extractor.js +23 -12
  7. package/dest/bench/utils.d.ts +1 -1
  8. package/dest/bench/utils.d.ts.map +1 -1
  9. package/dest/bench/utils.js +9 -5
  10. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +1 -1
  11. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  12. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +1 -1
  13. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +5 -2
  14. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  15. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +8 -4
  16. package/dest/e2e_deploy_contract/deploy_test.d.ts +1 -1
  17. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  18. package/dest/e2e_epochs/epochs_test.d.ts +13 -5
  19. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  20. package/dest/e2e_epochs/epochs_test.js +41 -16
  21. package/dest/e2e_fees/bridging_race.notest.d.ts +2 -0
  22. package/dest/e2e_fees/bridging_race.notest.d.ts.map +1 -0
  23. package/dest/e2e_fees/bridging_race.notest.js +60 -0
  24. package/dest/e2e_fees/fees_test.d.ts +1 -1
  25. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  26. package/dest/e2e_fees/fees_test.js +15 -9
  27. package/dest/e2e_nested_contract/nested_contract_test.d.ts +2 -2
  28. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  29. package/dest/e2e_nested_contract/nested_contract_test.js +2 -2
  30. package/dest/e2e_p2p/p2p_network.d.ts +10 -214
  31. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  32. package/dest/e2e_p2p/p2p_network.js +20 -23
  33. package/dest/e2e_p2p/shared.d.ts +1 -1
  34. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  35. package/dest/e2e_p2p/shared.js +3 -7
  36. package/dest/e2e_prover/e2e_prover_test.d.ts.map +1 -1
  37. package/dest/e2e_prover/e2e_prover_test.js +2 -1
  38. package/dest/e2e_token_contract/token_contract_test.d.ts +1 -1
  39. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  40. package/dest/e2e_token_contract/token_contract_test.js +1 -1
  41. package/dest/fixtures/fixtures.d.ts +4 -6
  42. package/dest/fixtures/fixtures.d.ts.map +1 -1
  43. package/dest/fixtures/fixtures.js +2 -2
  44. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  45. package/dest/fixtures/l1_to_l2_messaging.d.ts +5 -1
  46. package/dest/fixtures/l1_to_l2_messaging.d.ts.map +1 -1
  47. package/dest/fixtures/l1_to_l2_messaging.js +5 -4
  48. package/dest/fixtures/setup_l1_contracts.d.ts +1 -1
  49. package/dest/fixtures/setup_l1_contracts.d.ts.map +1 -1
  50. package/dest/fixtures/setup_p2p_test.d.ts +1 -2
  51. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  52. package/dest/fixtures/setup_p2p_test.js +3 -3
  53. package/dest/fixtures/snapshot_manager.d.ts.map +1 -1
  54. package/dest/fixtures/snapshot_manager.js +6 -2
  55. package/dest/fixtures/utils.d.ts +6 -6
  56. package/dest/fixtures/utils.d.ts.map +1 -1
  57. package/dest/fixtures/utils.js +64 -63
  58. package/dest/shared/capture_private_execution_steps.d.ts.map +1 -1
  59. package/dest/shared/capture_private_execution_steps.js +8 -4
  60. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  61. package/dest/shared/submit-transactions.d.ts.map +1 -1
  62. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  63. package/dest/shared/uniswap_l1_l2.js +1 -1
  64. package/dest/simulators/token_simulator.d.ts.map +1 -1
  65. package/dest/simulators/token_simulator.js +1 -1
  66. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  67. package/dest/spartan/utils.d.ts +0 -1
  68. package/dest/spartan/utils.d.ts.map +1 -1
  69. package/package.json +38 -37
  70. package/src/bench/client_flows/client_flows_benchmark.ts +1 -1
  71. package/src/bench/client_flows/config.ts +12 -4
  72. package/src/bench/client_flows/data_extractor.ts +40 -20
  73. package/src/bench/utils.ts +7 -3
  74. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +1 -1
  75. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +16 -5
  76. package/src/e2e_deploy_contract/deploy_test.ts +1 -1
  77. package/src/e2e_epochs/epochs_test.ts +51 -18
  78. package/src/e2e_fees/bridging_race.notest.ts +74 -0
  79. package/src/e2e_fees/fees_test.ts +24 -9
  80. package/src/e2e_nested_contract/nested_contract_test.ts +6 -3
  81. package/src/e2e_p2p/p2p_network.ts +27 -21
  82. package/src/e2e_p2p/shared.ts +4 -6
  83. package/src/e2e_prover/e2e_prover_test.ts +1 -0
  84. package/src/e2e_token_contract/token_contract_test.ts +1 -1
  85. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  86. package/src/fixtures/fixtures.ts +2 -2
  87. package/src/fixtures/l1_to_l2_messaging.ts +1 -1
  88. package/src/fixtures/setup_p2p_test.ts +3 -3
  89. package/src/fixtures/snapshot_manager.ts +2 -2
  90. package/src/fixtures/utils.ts +57 -66
  91. package/src/shared/capture_private_execution_steps.ts +9 -2
  92. package/src/shared/uniswap_l1_l2.ts +1 -1
  93. package/src/simulators/token_simulator.ts +0 -1
  94. package/src/spartan/setup_test_wallets.ts +6 -3
@@ -6,13 +6,17 @@ export type ClientFlowConfig = {
6
6
  recursions?: number[];
7
7
  };
8
8
 
9
- type ClientFlows = 'deployments' | 'transfers' | 'bridging' | 'amm';
9
+ type ClientFlows = 'accountDeployments' | 'deployments' | 'transfers' | 'bridging' | 'amm';
10
10
 
11
11
  export type ClientFlowsConfig = {
12
12
  [key in ClientFlows]: ClientFlowConfig;
13
13
  };
14
14
 
15
15
  export const KEY_FLOWS_CONFIG: ClientFlowsConfig = {
16
+ accountDeployments: {
17
+ accounts: ['ecdsar1', 'schnorr'],
18
+ feePaymentMethods: ['sponsored_fpc'],
19
+ },
16
20
  deployments: {
17
21
  accounts: ['ecdsar1', 'schnorr'],
18
22
  feePaymentMethods: ['sponsored_fpc'],
@@ -26,13 +30,17 @@ export const KEY_FLOWS_CONFIG: ClientFlowsConfig = {
26
30
  feePaymentMethods: ['sponsored_fpc'],
27
31
  },
28
32
  transfers: {
29
- accounts: ['ecdsar1', 'schnorr'],
30
- feePaymentMethods: ['sponsored_fpc', 'fee_juice'],
31
- recursions: [1],
33
+ accounts: ['ecdsar1'],
34
+ feePaymentMethods: ['sponsored_fpc', 'private_fpc'],
35
+ recursions: [0, 1],
32
36
  },
33
37
  };
34
38
 
35
39
  export const FULL_FLOWS_CONFIG: ClientFlowsConfig = {
40
+ accountDeployments: {
41
+ accounts: ['ecdsar1', 'schnorr'],
42
+ feePaymentMethods: ['bridged_fee_juice', 'sponsored_fpc'],
43
+ },
36
44
  deployments: {
37
45
  accounts: ['ecdsar1', 'schnorr'],
38
46
  feePaymentMethods: ['bridged_fee_juice', 'sponsored_fpc'],
@@ -2,6 +2,7 @@ import type { Logger } from '@aztec/aztec.js';
2
2
  import { BBNativePrivateKernelProver } from '@aztec/bb-prover/client/native';
3
3
  import { BBWASMBundlePrivateKernelProver } from '@aztec/bb-prover/client/wasm/bundle';
4
4
  import { createLogger, logger } from '@aztec/foundation/log';
5
+ import { Timer } from '@aztec/foundation/timer';
5
6
  import { WASMSimulator } from '@aztec/simulator/client';
6
7
  import type { PrivateExecutionStep } from '@aztec/stdlib/kernel';
7
8
 
@@ -18,7 +19,7 @@ type Log = {
18
19
  timestamp: number;
19
20
  prefix: string;
20
21
  message: string;
21
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+
22
23
  data: any;
23
24
  };
24
25
 
@@ -105,18 +106,18 @@ async function createProver(config: NativeProverConfig = {}, log: Logger) {
105
106
  }
106
107
  }
107
108
 
108
- function getMinimumTrace(logs: Log[], proverType: ProverType): StructuredTrace {
109
- const minimumMessage = 'Minimum required block sizes for structured trace:';
109
+ function getMinimumTrace(logs: Log[]): StructuredTrace {
110
+ const minimumMessage = 'Trace details:';
110
111
  const minimumMessageIndex = logs.findIndex(log => log.message.includes(minimumMessage));
111
112
  const candidateLogs = logs.slice(minimumMessageIndex - GATE_TYPES.length, minimumMessageIndex);
112
- const traceLogs =
113
- proverType === 'wasm'
114
- ? candidateLogs.map(log => log.message)
115
- : logs
116
- .slice(minimumMessageIndex - GATE_TYPES.length, minimumMessageIndex)
117
- .filter(log => GATE_TYPES.some(type => log.message.includes(`bb - ${type}`)))
118
- .map(log => log.message.split('\n'))
119
- .flat();
113
+
114
+ const traceLogs = candidateLogs
115
+ .filter(log => GATE_TYPES.some(type => log.message.includes(type)))
116
+ .map(log => log.message.split(/\t|\n/))
117
+ .flat()
118
+ .map(log => log.replace(/\(mem: .*\)/, '').trim())
119
+ .filter(Boolean);
120
+
120
121
  const traceSizes = traceLogs.map(log => {
121
122
  const [gateType, gateSizeStr] = log
122
123
  .replace(/\n.*\)$/, '')
@@ -127,6 +128,7 @@ function getMinimumTrace(logs: Log[], proverType: ProverType): StructuredTrace {
127
128
  assert(GATE_TYPES.includes(gateType as GateType), `Gate type ${gateType} is not recognized`);
128
129
  return { [gateType]: gateSize };
129
130
  });
131
+
130
132
  assert(traceSizes.length === GATE_TYPES.length, 'Decoded trace sizes do not match expected amount of gate types');
131
133
  return traceSizes.reduce((acc, curr) => ({ ...acc, ...curr }), {}) as StructuredTrace;
132
134
  }
@@ -156,23 +158,36 @@ async function main() {
156
158
  const witnessStack = JSON.parse(witnesses.toString()).map((witnessMap: Record<string, string>) => {
157
159
  return new Map<number, string>(Object.entries(witnessMap).map(([k, v]) => [Number(k), v]));
158
160
  });
159
- const stepsFile = await readFile(join(ivcFolder, flow, 'steps.json'));
160
- const executionSteps = JSON.parse(stepsFile.toString()) as { fnName: string; gateCount: number }[];
161
- const privateExecutionSteps: PrivateExecutionStep[] = executionSteps.map((step, i) => ({
161
+ const profileFile = await readFile(join(ivcFolder, flow, 'profile.json'));
162
+ const profile = JSON.parse(profileFile.toString()) as {
163
+ syncTime: number;
164
+ steps: {
165
+ fnName: string;
166
+ gateCount: number;
167
+ timings: { witgen: number; gateCount: number };
168
+ }[];
169
+ };
170
+ const privateExecutionSteps: PrivateExecutionStep[] = profile.steps.map((step, i) => ({
162
171
  functionName: step.fnName,
163
172
  gateCount: step.gateCount,
164
173
  bytecode: stepsFromFile[i].bytecode,
165
174
  // TODO(AD) do we still want to take this from witness.json?
166
175
  witness: witnessStack[i],
167
- // This can be left empty. If so, the prover will generate a vk on the fly (~25% slower).
168
- vk: Buffer.from([]),
176
+ vk: stepsFromFile[i].vk,
177
+ timings: {
178
+ witgen: step.timings.witgen,
179
+ gateCount: step.timings.witgen,
180
+ },
169
181
  }));
170
182
  let stats: { duration: number; eventName: string; proofSize: number } | undefined;
171
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
- let error: any | undefined;
183
+
184
+ let error: any;
173
185
  let currentLogs: Log[] = [];
186
+ let provingTime;
174
187
  try {
188
+ const provingTimer = new Timer();
175
189
  await prover.createClientIvcProof(privateExecutionSteps);
190
+ provingTime = provingTimer.ms();
176
191
  } catch (e) {
177
192
  userLog.error(`Failed to generate client ivc proof for ${flow}`, e);
178
193
  error = (e as Error).message;
@@ -185,9 +200,9 @@ async function main() {
185
200
  stats = currentLogs[0].data as { duration: number; eventName: string; proofSize: number };
186
201
  }
187
202
 
188
- const minimumTrace = getMinimumTrace(currentLogs, proverType);
203
+ const minimumTrace = getMinimumTrace(currentLogs);
189
204
 
190
- const steps = executionSteps.reduce<Step[]>((acc, step, i) => {
205
+ const steps = profile.steps.reduce<Step[]>((acc, step, i) => {
191
206
  const previousAccGateCount = i === 0 ? 0 : acc[i - 1].accGateCount!;
192
207
  return [
193
208
  ...acc,
@@ -195,11 +210,16 @@ async function main() {
195
210
  fnName: step.fnName,
196
211
  gateCount: step.gateCount,
197
212
  accGateCount: previousAccGateCount + step.gateCount,
213
+ timings: {
214
+ witgen: step.timings.witgen,
215
+ },
198
216
  },
199
217
  ];
200
218
  }, []);
201
219
  const totalGateCount = steps[steps.length - 1].accGateCount;
202
220
  const benchmark = {
221
+ syncTime: profile.syncTime,
222
+ provingTime,
203
223
  proverType,
204
224
  minimumTrace: minimumTrace,
205
225
  totalGateCount,
@@ -1,12 +1,13 @@
1
1
  import type { AztecNodeService } from '@aztec/aztec-node';
2
2
  import { type AztecNode, BatchCall, type SentTx, type WaitOpts } from '@aztec/aztec.js';
3
3
  import { mean, stdDev, times } from '@aztec/foundation/collection';
4
- import { BenchmarkingContract } from '@aztec/noir-contracts.js/Benchmarking';
4
+ import { BenchmarkingContract } from '@aztec/noir-test-contracts.js/Benchmarking';
5
5
  import { type PXEService, type PXEServiceConfig, createPXEService } from '@aztec/pxe/server';
6
6
  import type { MetricsType } from '@aztec/telemetry-client';
7
7
  import type { BenchmarkDataPoint, BenchmarkMetricsType, BenchmarkTelemetryClient } from '@aztec/telemetry-client/bench';
8
8
 
9
- import { writeFileSync } from 'fs';
9
+ import { mkdirSync, writeFileSync } from 'fs';
10
+ import path from 'path';
10
11
 
11
12
  import { type EndToEndContext, type SetupOptions, setup } from '../fixtures/utils.js';
12
13
 
@@ -36,6 +37,7 @@ export async function benchmarkSetup(
36
37
  throw new Error(`No benchmark data generated. Please review your test setup.`);
37
38
  }
38
39
  const benchOutput = opts.benchOutput ?? process.env.BENCH_OUTPUT ?? 'bench.json';
40
+ mkdirSync(path.dirname(benchOutput), { recursive: true });
39
41
  writeFileSync(benchOutput, JSON.stringify(formatted));
40
42
  context.logger.info(`Wrote ${data.length} metrics to ${benchOutput}`);
41
43
  await origTeardown();
@@ -136,7 +138,7 @@ export async function sendTxs(
136
138
  ): Promise<SentTx[]> {
137
139
  const calls = times(txCount, index => makeCall(index, context, contract, heavyPublicCompute));
138
140
  context.logger.info(`Creating ${txCount} txs`);
139
- const provenTxs = await Promise.all(calls.map(call => call.prove({ skipPublicSimulation: true })));
141
+ const provenTxs = await Promise.all(calls.map(call => call.prove()));
140
142
  context.logger.info(`Sending ${txCount} txs`);
141
143
  return provenTxs.map(tx => tx.send());
142
144
  }
@@ -166,7 +168,9 @@ export async function createNewPXE(node: AztecNode, contract: BenchmarkingContra
166
168
  l1ChainId,
167
169
  rollupVersion,
168
170
  } as PXEServiceConfig;
171
+ // docs:start:PXEcreate
169
172
  const pxe = await createPXEService(node, pxeConfig);
173
+ // docs:end:PXEcreate
170
174
  await pxe.registerContract(contract);
171
175
  return pxe;
172
176
  }
@@ -11,9 +11,9 @@ import {
11
11
  createLogger,
12
12
  } from '@aztec/aztec.js';
13
13
  import { MAX_NOTE_HASHES_PER_TX } from '@aztec/constants';
14
- import { InvalidAccountContract } from '@aztec/noir-contracts.js/InvalidAccount';
15
14
  import type { TokenContract } from '@aztec/noir-contracts.js/Token';
16
15
  import { TokenBlacklistContract } from '@aztec/noir-contracts.js/TokenBlacklist';
16
+ import { InvalidAccountContract } from '@aztec/noir-test-contracts.js/InvalidAccount';
17
17
 
18
18
  import { jest } from '@jest/globals';
19
19
 
@@ -11,10 +11,16 @@ import {
11
11
  createLogger,
12
12
  } from '@aztec/aztec.js';
13
13
  import { CheatCodes } from '@aztec/aztec.js/testing';
14
- import { type ExtendedViemWalletClient, createExtendedL1Client, deployL1Contract } from '@aztec/ethereum';
14
+ import {
15
+ type DeployL1ContractsReturnType,
16
+ type ExtendedViemWalletClient,
17
+ createExtendedL1Client,
18
+ deployL1Contract,
19
+ } from '@aztec/ethereum';
15
20
  import { InboxAbi, OutboxAbi, TestERC20Abi, TestERC20Bytecode } from '@aztec/l1-artifacts';
16
21
  import { TokenContract } from '@aztec/noir-contracts.js/Token';
17
22
  import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge';
23
+ import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
18
24
 
19
25
  import { getContract } from 'viem';
20
26
 
@@ -38,6 +44,7 @@ export class CrossChainMessagingTest {
38
44
  aztecNode!: AztecNode;
39
45
  pxe!: PXE;
40
46
  aztecNodeConfig!: AztecNodeConfig;
47
+ aztecNodeAdmin!: AztecNodeAdmin;
41
48
 
42
49
  l1Client!: ExtendedViemWalletClient | undefined;
43
50
 
@@ -51,7 +58,9 @@ export class CrossChainMessagingTest {
51
58
 
52
59
  inbox!: any; // GetContractReturnType<typeof InboxAbi> | undefined;
53
60
  outbox!: any; // GetContractReturnType<typeof OutboxAbi> | undefined;
54
- cheatcodes!: CheatCodes;
61
+ cheatCodes!: CheatCodes;
62
+
63
+ deployL1ContractsValues!: DeployL1ContractsReturnType;
55
64
 
56
65
  constructor(testName: string) {
57
66
  this.logger = createLogger(`e2e:e2e_cross_chain_messaging:${testName}`);
@@ -59,15 +68,17 @@ export class CrossChainMessagingTest {
59
68
  }
60
69
 
61
70
  async assumeProven() {
62
- await this.cheatcodes.rollup.markAsProven();
71
+ await this.cheatCodes.rollup.markAsProven();
63
72
  }
64
73
 
65
74
  async setup() {
66
- const { aztecNode, pxe, aztecNodeConfig } = await this.snapshotManager.setup();
75
+ const { aztecNode, pxe, aztecNodeConfig, deployL1ContractsValues } = await this.snapshotManager.setup();
67
76
  this.aztecNode = aztecNode;
68
77
  this.pxe = pxe;
69
78
  this.aztecNodeConfig = aztecNodeConfig;
70
- this.cheatcodes = await CheatCodes.create(this.aztecNodeConfig.l1RpcUrls, this.pxe);
79
+ this.cheatCodes = await CheatCodes.create(this.aztecNodeConfig.l1RpcUrls, this.pxe);
80
+ this.deployL1ContractsValues = deployL1ContractsValues;
81
+ this.aztecNodeAdmin = aztecNode;
71
82
  }
72
83
 
73
84
  snapshot = <T>(
@@ -13,7 +13,7 @@ import {
13
13
  createLogger,
14
14
  getContractInstanceFromDeployParams,
15
15
  } from '@aztec/aztec.js';
16
- import type { StatefulTestContract } from '@aztec/noir-contracts.js/StatefulTest';
16
+ import type { StatefulTestContract } from '@aztec/noir-test-contracts.js/StatefulTest';
17
17
  import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
18
18
 
19
19
  import { type ISnapshotManager, createSnapshotManager, deployAccounts } from '../fixtures/snapshot_manager.js';
@@ -10,7 +10,7 @@ import type { TestProverNode } from '@aztec/prover-node/test';
10
10
  import type { SequencerPublisher } from '@aztec/sequencer-client';
11
11
  import type { TestSequencerClient } from '@aztec/sequencer-client/test';
12
12
  import type { L2BlockNumber } from '@aztec/stdlib/block';
13
- import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
13
+ import { type L1RollupConstants, getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
14
14
 
15
15
  import { join } from 'path';
16
16
  import type { Hex } from 'viem';
@@ -23,15 +23,23 @@ import {
23
23
  setup,
24
24
  } from '../fixtures/utils.js';
25
25
 
26
- // This can be lowered to as much as 2s in non-CI
27
- export const L1_BLOCK_TIME_IN_S = process.env.L1_BLOCK_TIME ? parseInt(process.env.L1_BLOCK_TIME) : 8;
28
- export const L2_SLOT_DURATION_IN_L1_SLOTS = 2;
29
26
  export const WORLD_STATE_BLOCK_HISTORY = 2;
30
27
  export const WORLD_STATE_BLOCK_CHECK_INTERVAL = 50;
31
28
  export const ARCHIVER_POLL_INTERVAL = 50;
32
29
 
33
30
  export type EpochsTestOpts = Partial<
34
- Pick<SetupOptions, 'startProverNode' | 'aztecProofSubmissionWindow' | 'aztecEpochDuration' | 'proverTestDelayMs'>
31
+ Pick<
32
+ SetupOptions,
33
+ | 'startProverNode'
34
+ | 'aztecProofSubmissionWindow'
35
+ | 'aztecEpochDuration'
36
+ | 'proverTestDelayMs'
37
+ | 'l1PublishRetryIntervalMS'
38
+ | 'txPropagationMaxQueryAttempts'
39
+ | 'proverNodeConfig'
40
+ | 'ethereumSlotDuration'
41
+ | 'aztecSlotDuration'
42
+ >
35
43
  >;
36
44
 
37
45
  /**
@@ -54,17 +62,33 @@ export class EpochsTestContext {
54
62
 
55
63
  public epochDuration!: number;
56
64
 
65
+ public L1_BLOCK_TIME_IN_S!: number;
66
+ public L2_SLOT_DURATION_IN_S!: number;
67
+
57
68
  public static async setup(opts: EpochsTestOpts = {}) {
58
69
  const test = new EpochsTestContext();
59
70
  await test.setup(opts);
60
71
  return test;
61
72
  }
62
73
 
74
+ public static getSlotDurations(opts: EpochsTestOpts = {}) {
75
+ const envEthereumSlotDuration = process.env.L1_BLOCK_TIME ? parseInt(process.env.L1_BLOCK_TIME) : 8;
76
+ const ethereumSlotDuration = opts.ethereumSlotDuration ?? envEthereumSlotDuration;
77
+ const aztecSlotDuration = opts.aztecSlotDuration ?? ethereumSlotDuration * 2;
78
+ const aztecEpochDuration = opts.aztecEpochDuration ?? 4;
79
+ const aztecProofSubmissionWindow = opts.aztecProofSubmissionWindow ?? aztecEpochDuration * 2 - 1;
80
+ return { ethereumSlotDuration, aztecSlotDuration, aztecEpochDuration, aztecProofSubmissionWindow };
81
+ }
82
+
63
83
  public async setup(opts: EpochsTestOpts = {}) {
84
+ const { ethereumSlotDuration, aztecSlotDuration, aztecEpochDuration, aztecProofSubmissionWindow } =
85
+ EpochsTestContext.getSlotDurations(opts);
86
+
87
+ this.L1_BLOCK_TIME_IN_S = ethereumSlotDuration;
88
+ this.L2_SLOT_DURATION_IN_S = aztecSlotDuration;
89
+
64
90
  // Set up system without any account nor protocol contracts
65
91
  // and with faster block times and shorter epochs.
66
- const aztecEpochDuration = opts.aztecEpochDuration ?? 4;
67
- const proofSubmissionWindow = opts.aztecProofSubmissionWindow ?? aztecEpochDuration * 2 - 1;
68
92
  const context = await setup(0, {
69
93
  checkIntervalMs: 50,
70
94
  archiverPollingIntervalMS: ARCHIVER_POLL_INTERVAL,
@@ -72,9 +96,9 @@ export class EpochsTestContext {
72
96
  skipProtocolContracts: true,
73
97
  salt: 1,
74
98
  aztecEpochDuration,
75
- aztecSlotDuration: L1_BLOCK_TIME_IN_S * L2_SLOT_DURATION_IN_L1_SLOTS,
76
- ethereumSlotDuration: L1_BLOCK_TIME_IN_S,
77
- aztecProofSubmissionWindow: proofSubmissionWindow,
99
+ aztecSlotDuration,
100
+ ethereumSlotDuration,
101
+ aztecProofSubmissionWindow,
78
102
  minTxsPerBlock: 0,
79
103
  realProofs: false,
80
104
  startProverNode: true,
@@ -84,7 +108,7 @@ export class EpochsTestContext {
84
108
  proverId: Fr.fromString('1'),
85
109
  // This must be enough so that the tx from the prover is delayed properly,
86
110
  // but not so much to hang the sequencer and timeout the teardown
87
- txPropagationMaxQueryAttempts: 12,
111
+ txPropagationMaxQueryAttempts: opts.txPropagationMaxQueryAttempts ?? 12,
88
112
  worldStateBlockHistory: WORLD_STATE_BLOCK_HISTORY,
89
113
  ...opts,
90
114
  });
@@ -116,11 +140,11 @@ export class EpochsTestContext {
116
140
  this.epochDuration = aztecEpochDuration;
117
141
  this.constants = {
118
142
  epochDuration: aztecEpochDuration,
119
- slotDuration: L1_BLOCK_TIME_IN_S * L2_SLOT_DURATION_IN_L1_SLOTS,
143
+ slotDuration: aztecSlotDuration,
120
144
  l1StartBlock: await this.rollup.getL1StartBlock(),
121
145
  l1GenesisTime: await this.rollup.getL1GenesisTime(),
122
- ethereumSlotDuration: L1_BLOCK_TIME_IN_S,
123
- proofSubmissionWindow,
146
+ ethereumSlotDuration,
147
+ proofSubmissionWindow: aztecProofSubmissionWindow,
124
148
  };
125
149
 
126
150
  this.logger.info(
@@ -143,8 +167,8 @@ export class EpochsTestContext {
143
167
  createAndSyncProverNode(
144
168
  proverNodePrivateKey,
145
169
  { ...this.context.config, proverId: Fr.fromString(suffix) },
170
+ { dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')) },
146
171
  this.context.aztecNode,
147
- join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
148
172
  ),
149
173
  );
150
174
  this.proverNodes.push(proverNode);
@@ -174,14 +198,14 @@ export class EpochsTestContext {
174
198
  public async waitUntilEpochStarts(epoch: number) {
175
199
  const [start] = getTimestampRangeForEpoch(BigInt(epoch), this.constants);
176
200
  this.logger.info(`Waiting until L1 timestamp ${start} is reached as the start of epoch ${epoch}`);
177
- await waitUntilL1Timestamp(this.l1Client, start - BigInt(L1_BLOCK_TIME_IN_S));
201
+ await waitUntilL1Timestamp(this.l1Client, start - BigInt(this.L1_BLOCK_TIME_IN_S));
178
202
  return start;
179
203
  }
180
204
 
181
205
  /** Waits until the given L2 block number is mined. */
182
206
  public async waitUntilL2BlockNumber(target: number, timeout = 60) {
183
207
  await retryUntil(
184
- () => Promise.resolve(target === this.monitor.l2BlockNumber),
208
+ () => Promise.resolve(target <= this.monitor.l2BlockNumber),
185
209
  `Wait until L2 block ${target}`,
186
210
  timeout,
187
211
  0.1,
@@ -191,11 +215,20 @@ export class EpochsTestContext {
191
215
  /** Waits until the given L2 block number is marked as proven. */
192
216
  public async waitUntilProvenL2BlockNumber(t: number, timeout = 60) {
193
217
  await retryUntil(
194
- () => Promise.resolve(t === this.monitor.l2ProvenBlockNumber),
218
+ () => Promise.resolve(t <= this.monitor.l2ProvenBlockNumber),
195
219
  `Wait proven L2 block ${t}`,
196
220
  timeout,
197
221
  0.1,
198
222
  );
223
+ return this.monitor.l2ProvenBlockNumber;
224
+ }
225
+
226
+ /** Waits until the end of the proof submission window for a given epoch. */
227
+ public async waitUntilEndOfProofSubmissionWindow(epochNumber: number | bigint) {
228
+ const deadline = getProofSubmissionDeadlineTimestamp(BigInt(epochNumber), this.constants);
229
+ const date = new Date(Number(deadline) * 1000);
230
+ this.logger.info(`Waiting until end of submission window for epoch ${epochNumber} at ${date}`, { deadline });
231
+ await waitUntilL1Timestamp(this.l1Client, deadline);
199
232
  }
200
233
 
201
234
  /** Waits for the aztec node to sync to the target block number. */
@@ -0,0 +1,74 @@
1
+ import { getSchnorrAccount } from '@aztec/accounts/schnorr';
2
+ import { Fr, type Logger, type PXE, sleep } from '@aztec/aztec.js';
3
+ import { FEE_FUNDING_FOR_TESTER_ACCOUNT } from '@aztec/constants';
4
+ import { Fq } from '@aztec/foundation/fields';
5
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
6
+
7
+ import { jest } from '@jest/globals';
8
+ import type { Hex } from 'viem';
9
+
10
+ import { FeesTest } from './fees_test.js';
11
+
12
+ jest.setTimeout(300_000);
13
+
14
+ // Regression for https://github.com/AztecProtocol/aztec-packages/issues/12366
15
+ // Similar to e2e_fees/account_init but with no automine
16
+ describe('e2e_fees bridging_race', () => {
17
+ const ETHEREUM_SLOT_DURATION = 4;
18
+ const AZTEC_SLOT_DURATION = ETHEREUM_SLOT_DURATION * 2;
19
+
20
+ const t = new FeesTest('bridging_race', 1, {
21
+ ethereumSlotDuration: ETHEREUM_SLOT_DURATION,
22
+ aztecSlotDuration: AZTEC_SLOT_DURATION,
23
+ minTxsPerBlock: 0,
24
+ });
25
+
26
+ beforeAll(async () => {
27
+ await t.applyInitialAccountsSnapshot();
28
+ await t.applyPublicDeployAccountsSnapshot();
29
+ await t.applySetupFeeJuiceSnapshot();
30
+
31
+ ({ pxe, logger } = await t.setup());
32
+ });
33
+
34
+ afterAll(async () => {
35
+ await t.teardown();
36
+ });
37
+
38
+ let logger: Logger;
39
+ let pxe: PXE;
40
+ let bobsAddress: AztecAddress;
41
+
42
+ beforeEach(async () => {
43
+ const bobsSecretKey = Fr.random();
44
+ const bobsPrivateSigningKey = Fq.random();
45
+ const bobsAccountManager = await getSchnorrAccount(pxe, bobsSecretKey, bobsPrivateSigningKey, Fr.random());
46
+ const bobsCompleteAddress = await bobsAccountManager.getCompleteAddress();
47
+ bobsAddress = bobsCompleteAddress.address;
48
+ await bobsAccountManager.getWallet();
49
+ await bobsAccountManager.register();
50
+ });
51
+
52
+ it('Alice bridges funds to Bob', async () => {
53
+ // Tweak the token manager so the bridging happens immediately before the end of the current L2 slot
54
+ // This caused the message to be "not in state" when tried to be used
55
+ const l1TokenManager = t.feeJuiceBridgeTestHarness.l1TokenManager;
56
+ const origApprove = l1TokenManager.approve.bind(l1TokenManager);
57
+ l1TokenManager.approve = async (amount: bigint, address: Hex, addressName = '') => {
58
+ await origApprove(amount, address, addressName);
59
+ const sleepTime = (Number(t.chainMonitor.l2BlockTimestamp) + AZTEC_SLOT_DURATION) * 1000 - Date.now() - 500;
60
+ logger.info(`Sleeping for ${sleepTime}ms until near end of L2 slot before sending L1 fee juice to L2 inbox`);
61
+ await sleep(sleepTime);
62
+ };
63
+
64
+ // Waiting for the archiver to sync the message _before_ waiting for the mandatory 2 L2 blocks to pass fixed it
65
+ // This was added everywhere we wait for two blocks, which is spread across three different places in the codebase
66
+ // Yes, we need to REFACTOR it at some point
67
+ const amount = FEE_FUNDING_FOR_TESTER_ACCOUNT;
68
+ const claim = await t.feeJuiceBridgeTestHarness.prepareTokensOnL1(amount, bobsAddress);
69
+ const { claimSecret: secret, messageLeafIndex: index } = claim;
70
+ await t.feeJuiceContract.methods.claim(bobsAddress, amount, secret, index).send().wait();
71
+ const [balance] = await t.getGasBalanceFn(bobsAddress);
72
+ expect(balance).toEqual(amount);
73
+ });
74
+ });
@@ -21,11 +21,11 @@ import { ChainMonitor } from '@aztec/ethereum/test';
21
21
  import { EthAddress } from '@aztec/foundation/eth-address';
22
22
  import { TestERC20Abi } from '@aztec/l1-artifacts';
23
23
  import { AppSubscriptionContract } from '@aztec/noir-contracts.js/AppSubscription';
24
- import { CounterContract } from '@aztec/noir-contracts.js/Counter';
25
24
  import { FPCContract } from '@aztec/noir-contracts.js/FPC';
26
25
  import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice';
27
26
  import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC';
28
27
  import { TokenContract as BananaCoin } from '@aztec/noir-contracts.js/Token';
28
+ import { CounterContract } from '@aztec/noir-test-contracts.js/Counter';
29
29
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
30
30
  import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice';
31
31
  import { GasSettings } from '@aztec/stdlib/gas';
@@ -310,17 +310,33 @@ export class FeesTest {
310
310
  };
311
311
 
312
312
  this.getProverFee = async (blockNumber: number) => {
313
+ const block = await this.pxe.getBlock(blockNumber);
314
+
313
315
  const publicClient = getPublicClient({
314
316
  l1RpcUrls: context.aztecNodeConfig.l1RpcUrls,
315
317
  l1ChainId: context.aztecNodeConfig.l1ChainId,
316
318
  });
317
319
  const rollup = new RollupContract(publicClient, data.rollupAddress);
318
320
 
319
- const provingCostPerMana = await rollup.getProvingCostPerManaInFeeAsset();
321
+ // @todo @lherskind As we deal with #13601
322
+ // Right now the value is from `FeeLib.sol`
323
+ const L1_GAS_PER_EPOCH_VERIFIED = 1000000n;
324
+
325
+ // We round up
326
+ const mulDiv = (a: bigint, b: bigint, c: bigint) => (a * b) / c + ((a * b) % c > 0n ? 1n : 0n);
327
+
328
+ const { baseFee } = await rollup.getL1FeesAt(block!.header.globalVariables.timestamp.toBigInt());
329
+ const proverCost =
330
+ mulDiv(
331
+ mulDiv(L1_GAS_PER_EPOCH_VERIFIED, baseFee, await rollup.getEpochDuration()),
332
+ 1n,
333
+ await rollup.getManaTarget(),
334
+ ) + (await rollup.getProvingCostPerMana());
335
+
336
+ const price = await rollup.getFeeAssetPerEth();
320
337
 
321
- const block = await this.pxe.getBlock(blockNumber);
322
338
  const mana = block!.header.totalManaUsed.toBigInt();
323
- return mana * provingCostPerMana;
339
+ return mulDiv(mana * proverCost, price, 10n ** 9n);
324
340
  };
325
341
  },
326
342
  );
@@ -333,16 +349,15 @@ export class FeesTest {
333
349
  const feeJuiceContract = this.feeJuiceBridgeTestHarness.feeJuice;
334
350
  expect((await context.pxe.getContractMetadata(feeJuiceContract.address)).isContractPubliclyDeployed).toBe(true);
335
351
 
336
- this.sponsoredFPC = await setupSponsoredFPC(context.pxe);
337
- this.logger.info(`SponsoredFPC deployed at ${this.sponsoredFPC.address}`);
352
+ const sponsoredFPC = await setupSponsoredFPC(context.pxe);
353
+ this.logger.info(`SponsoredFPC at ${sponsoredFPC.address}`);
338
354
 
339
355
  return {
340
- sponsoredFPCAddress: this.sponsoredFPC.address,
356
+ sponsoredFPCAddress: sponsoredFPC.address,
341
357
  };
342
358
  },
343
359
  async data => {
344
- const sponsoredFPC = await SponsoredFPCContract.at(data.sponsoredFPCAddress, this.aliceWallet);
345
- this.sponsoredFPC = sponsoredFPC;
360
+ this.sponsoredFPC = await SponsoredFPCContract.at(data.sponsoredFPCAddress, this.aliceWallet);
346
361
  },
347
362
  );
348
363
  }
@@ -1,7 +1,7 @@
1
1
  import { getSchnorrWallet } from '@aztec/accounts/schnorr';
2
2
  import { type AccountWallet, type CompleteAddress, type Logger, type PXE, createLogger } from '@aztec/aztec.js';
3
- import { ChildContract } from '@aztec/noir-contracts.js/Child';
4
- import { ParentContract } from '@aztec/noir-contracts.js/Parent';
3
+ import { ChildContract } from '@aztec/noir-test-contracts.js/Child';
4
+ import { ParentContract } from '@aztec/noir-test-contracts.js/Parent';
5
5
 
6
6
  import {
7
7
  type ISnapshotManager,
@@ -23,7 +23,10 @@ export class NestedContractTest {
23
23
  parentContract!: ParentContract;
24
24
  childContract!: ChildContract;
25
25
 
26
- constructor(testName: string, private numberOfAccounts = 1) {
26
+ constructor(
27
+ testName: string,
28
+ private numberOfAccounts = 1,
29
+ ) {
27
30
  this.logger = createLogger(`e2e:e2e_nested_contract:${testName}`);
28
31
  this.snapshotManager = createSnapshotManager(`e2e_nested_contract/${testName}-${numberOfAccounts}`, dataPath);
29
32
  }