@aztec/end-to-end 0.0.1-commit.ec5f612 → 0.0.1-commit.ec7ac5448

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 (121) 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 +19 -26
  5. package/dest/bench/utils.d.ts +1 -1
  6. package/dest/bench/utils.d.ts.map +1 -1
  7. package/dest/bench/utils.js +6 -3
  8. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +3 -2
  9. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  10. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +15 -15
  11. package/dest/e2e_epochs/epochs_test.d.ts +3 -1
  12. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  13. package/dest/e2e_epochs/epochs_test.js +8 -5
  14. package/dest/e2e_fees/fees_test.d.ts +1 -1
  15. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  16. package/dest/e2e_fees/fees_test.js +13 -6
  17. package/dest/e2e_nested_contract/nested_contract_test.d.ts +1 -1
  18. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  19. package/dest/e2e_nested_contract/nested_contract_test.js +4 -6
  20. package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
  21. package/dest/e2e_p2p/p2p_network.d.ts +8 -9
  22. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  23. package/dest/e2e_p2p/p2p_network.js +33 -29
  24. package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
  25. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  26. package/dest/e2e_p2p/reqresp/utils.js +16 -3
  27. package/dest/e2e_p2p/shared.d.ts +25 -7
  28. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  29. package/dest/e2e_p2p/shared.js +49 -44
  30. package/dest/e2e_token_contract/token_contract_test.d.ts +1 -1
  31. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  32. package/dest/e2e_token_contract/token_contract_test.js +11 -11
  33. package/dest/fixtures/authwit_proxy.d.ts +3 -3
  34. package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
  35. package/dest/fixtures/authwit_proxy.js +4 -0
  36. package/dest/fixtures/e2e_prover_test.d.ts +4 -3
  37. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  38. package/dest/fixtures/e2e_prover_test.js +11 -16
  39. package/dest/fixtures/get_bb_config.d.ts +1 -1
  40. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  41. package/dest/fixtures/get_bb_config.js +5 -5
  42. package/dest/fixtures/setup.d.ts +17 -9
  43. package/dest/fixtures/setup.d.ts.map +1 -1
  44. package/dest/fixtures/setup.js +27 -21
  45. package/dest/fixtures/setup_p2p_test.d.ts +6 -6
  46. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  47. package/dest/fixtures/setup_p2p_test.js +8 -8
  48. package/dest/fixtures/token_utils.d.ts +1 -1
  49. package/dest/fixtures/token_utils.d.ts.map +1 -1
  50. package/dest/fixtures/token_utils.js +2 -5
  51. package/dest/legacy-jest-resolver.d.cts +3 -0
  52. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  53. package/dest/shared/cross_chain_test_harness.d.ts +1 -1
  54. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  55. package/dest/shared/cross_chain_test_harness.js +13 -13
  56. package/dest/shared/gas_portal_test_harness.js +2 -2
  57. package/dest/shared/jest_setup.js +32 -1
  58. package/dest/shared/submit-transactions.d.ts +1 -1
  59. package/dest/shared/submit-transactions.d.ts.map +1 -1
  60. package/dest/shared/submit-transactions.js +1 -1
  61. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  62. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  63. package/dest/shared/uniswap_l1_l2.js +14 -17
  64. package/dest/simulators/lending_simulator.d.ts +1 -1
  65. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  66. package/dest/simulators/lending_simulator.js +4 -4
  67. package/dest/simulators/token_simulator.d.ts +1 -1
  68. package/dest/simulators/token_simulator.d.ts.map +1 -1
  69. package/dest/simulators/token_simulator.js +2 -2
  70. package/dest/spartan/setup_test_wallets.d.ts +4 -2
  71. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  72. package/dest/spartan/setup_test_wallets.js +69 -38
  73. package/dest/spartan/tx_metrics.js +1 -1
  74. package/dest/spartan/utils/config.d.ts +4 -1
  75. package/dest/spartan/utils/config.d.ts.map +1 -1
  76. package/dest/spartan/utils/config.js +1 -0
  77. package/dest/spartan/utils/index.d.ts +2 -1
  78. package/dest/spartan/utils/index.d.ts.map +1 -1
  79. package/dest/spartan/utils/index.js +2 -0
  80. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  81. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  82. package/dest/spartan/utils/pod_logs.js +74 -0
  83. package/dest/test-wallet/test_wallet.d.ts +24 -23
  84. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  85. package/dest/test-wallet/test_wallet.js +115 -80
  86. package/dest/test-wallet/worker_wallet.d.ts +4 -4
  87. package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
  88. package/dest/test-wallet/worker_wallet_schema.d.ts +4 -4
  89. package/package.json +43 -44
  90. package/src/bench/client_flows/client_flows_benchmark.ts +27 -10
  91. package/src/bench/utils.ts +7 -2
  92. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +21 -20
  93. package/src/e2e_epochs/epochs_test.ts +17 -5
  94. package/src/e2e_fees/fees_test.ts +13 -6
  95. package/src/e2e_nested_contract/nested_contract_test.ts +6 -4
  96. package/src/e2e_p2p/inactivity_slash_test.ts +3 -3
  97. package/src/e2e_p2p/p2p_network.ts +47 -48
  98. package/src/e2e_p2p/reqresp/utils.ts +24 -3
  99. package/src/e2e_p2p/shared.ts +71 -59
  100. package/src/e2e_token_contract/token_contract_test.ts +16 -8
  101. package/src/fixtures/authwit_proxy.ts +4 -0
  102. package/src/fixtures/e2e_prover_test.ts +19 -18
  103. package/src/fixtures/get_bb_config.ts +7 -6
  104. package/src/fixtures/setup.ts +43 -28
  105. package/src/fixtures/setup_p2p_test.ts +9 -9
  106. package/src/fixtures/token_utils.ts +1 -2
  107. package/src/legacy-jest-resolver.cjs +135 -0
  108. package/src/shared/cross_chain_test_harness.ts +13 -9
  109. package/src/shared/gas_portal_test_harness.ts +1 -1
  110. package/src/shared/jest_setup.ts +36 -1
  111. package/src/shared/submit-transactions.ts +1 -4
  112. package/src/shared/uniswap_l1_l2.ts +35 -28
  113. package/src/simulators/lending_simulator.ts +8 -4
  114. package/src/simulators/token_simulator.ts +6 -2
  115. package/src/spartan/setup_test_wallets.ts +90 -35
  116. package/src/spartan/tx_metrics.ts +1 -1
  117. package/src/spartan/utils/config.ts +1 -0
  118. package/src/spartan/utils/index.ts +3 -0
  119. package/src/spartan/utils/pod_logs.ts +99 -0
  120. package/src/test-wallet/test_wallet.ts +144 -99
  121. package/src/test-wallet/worker_wallet.ts +3 -2
@@ -6,12 +6,9 @@ import { Fr } from '@aztec/aztec.js/fields';
6
6
  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
- import type {
10
- EmpireSlashingProposerContract,
11
- RollupContract,
12
- TallySlashingProposerContract,
13
- } from '@aztec/ethereum/contracts';
14
- import { EpochNumber } from '@aztec/foundation/branded-types';
9
+ import type { EpochCacheInterface } from '@aztec/epoch-cache';
10
+ import type { RollupContract, SlashingProposerContract } from '@aztec/ethereum/contracts';
11
+ import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
15
12
  import { timesAsync, unique } from '@aztec/foundation/collection';
16
13
  import { EthAddress } from '@aztec/foundation/eth-address';
17
14
  import { retryUntil } from '@aztec/foundation/retry';
@@ -21,7 +18,6 @@ import { TestContract, TestContractArtifact } from '@aztec/noir-test-contracts.j
21
18
  import { getPXEConfig, getPXEConfig as getRpcConfig } from '@aztec/pxe/server';
22
19
  import { getRoundForOffense } from '@aztec/slasher';
23
20
  import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
24
- import type { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
25
21
 
26
22
  import { submitTxsTo } from '../shared/submit-transactions.js';
27
23
  import { TestWallet } from '../test-wallet/test_wallet.js';
@@ -41,7 +37,7 @@ export const submitComplexTxsTo = async (
41
37
  const spamCount = 15;
42
38
  for (let i = 0; i < numTxs; i++) {
43
39
  const method = spamContract.methods.spam(seed + BigInt(i * spamCount), spamCount, !!opts.callPublic);
44
- const txHash = await method.send({ from, wait: NO_WAIT });
40
+ const { txHash } = await method.send({ from, wait: NO_WAIT });
45
41
  logger.info(`Tx sent with hash ${txHash.toString()}`);
46
42
  txs.push(txHash);
47
43
  }
@@ -98,7 +94,7 @@ export async function prepareTransactions(
98
94
  }
99
95
 
100
96
  export function awaitProposalExecution(
101
- slashingProposer: EmpireSlashingProposerContract | TallySlashingProposerContract,
97
+ slashingProposer: SlashingProposerContract,
102
98
  timeoutSeconds: number,
103
99
  logger: Logger,
104
100
  ): Promise<bigint> {
@@ -108,24 +104,12 @@ export function awaitProposalExecution(
108
104
  reject(new Error(`Timeout waiting for proposal execution after ${timeoutSeconds}s`));
109
105
  }, timeoutSeconds * 1000);
110
106
 
111
- if (slashingProposer.type === 'empire') {
112
- const unwatch = slashingProposer.listenToPayloadSubmitted(args => {
113
- logger.warn(`Proposal ${args.payload} from round ${args.round} executed`);
114
- clearTimeout(timeout);
115
- unwatch();
116
- resolve(args.round);
117
- });
118
- } else if (slashingProposer.type === 'tally') {
119
- const unwatch = slashingProposer.listenToRoundExecuted(args => {
120
- logger.warn(`Slash from round ${args.round} executed`);
121
- clearTimeout(timeout);
122
- unwatch();
123
- resolve(args.round);
124
- });
125
- } else {
107
+ const unwatch = slashingProposer.listenToRoundExecuted(args => {
108
+ logger.warn(`Slash from round ${args.round} executed`);
126
109
  clearTimeout(timeout);
127
- reject(new Error(`Unknown slashing proposer type: ${(slashingProposer as any).type}`));
128
- }
110
+ unwatch();
111
+ resolve(args.round);
112
+ });
129
113
  });
130
114
  }
131
115
 
@@ -150,6 +134,58 @@ export async function awaitCommitteeExists({
150
134
  return committee!.map(c => c.toString() as `0x${string}`);
151
135
  }
152
136
 
137
+ /**
138
+ * Advance epochs until we find one where the target proposer is selected for at least one slot,
139
+ * then stop one epoch before it. This leaves time for the caller to start sequencers before
140
+ * warping to the target epoch, avoiding the race where the target epoch passes before sequencers
141
+ * are ready.
142
+ *
143
+ * Returns the target epoch number so the caller can warp to it after starting sequencers.
144
+ */
145
+ export async function advanceToEpochBeforeProposer({
146
+ epochCache,
147
+ cheatCodes,
148
+ targetProposer,
149
+ logger,
150
+ maxAttempts = 20,
151
+ }: {
152
+ epochCache: EpochCacheInterface;
153
+ cheatCodes: RollupCheatCodes;
154
+ targetProposer: EthAddress;
155
+ logger: Logger;
156
+ maxAttempts?: number;
157
+ }): Promise<{ targetEpoch: EpochNumber }> {
158
+ const { epochDuration } = await cheatCodes.getConfig();
159
+
160
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
161
+ const currentEpoch = await cheatCodes.getEpoch();
162
+ // Check the NEXT epoch's slots so we stay one epoch before the target,
163
+ // giving the caller time to start sequencers before the target epoch arrives.
164
+ const nextEpoch = Number(currentEpoch) + 1;
165
+ const startSlot = nextEpoch * Number(epochDuration);
166
+ const endSlot = startSlot + Number(epochDuration);
167
+
168
+ logger.info(
169
+ `Checking next epoch ${nextEpoch} (slots ${startSlot}-${endSlot - 1}) for proposer ${targetProposer} (current epoch: ${currentEpoch})`,
170
+ );
171
+
172
+ for (let s = startSlot; s < endSlot; s++) {
173
+ const proposer = await epochCache.getProposerAttesterAddressInSlot(SlotNumber(s));
174
+ if (proposer && proposer.equals(targetProposer)) {
175
+ logger.warn(
176
+ `Found target proposer ${targetProposer} in slot ${s} of epoch ${nextEpoch}. Staying at epoch ${currentEpoch} to allow sequencer startup.`,
177
+ );
178
+ return { targetEpoch: EpochNumber(nextEpoch) };
179
+ }
180
+ }
181
+
182
+ logger.info(`Target proposer not found in epoch ${nextEpoch}, advancing to next epoch`);
183
+ await cheatCodes.advanceToNextEpoch();
184
+ }
185
+
186
+ throw new Error(`Target proposer ${targetProposer} not found in any slot after ${maxAttempts} epoch attempts`);
187
+ }
188
+
153
189
  export async function awaitOffenseDetected({
154
190
  logger,
155
191
  nodeAdmin,
@@ -192,7 +228,6 @@ export async function awaitCommitteeKicked({
192
228
  rollup,
193
229
  cheatCodes,
194
230
  committee,
195
- slashFactory,
196
231
  slashingProposer,
197
232
  slashingRoundSize,
198
233
  aztecSlotDuration,
@@ -203,8 +238,7 @@ export async function awaitCommitteeKicked({
203
238
  rollup: RollupContract;
204
239
  cheatCodes: RollupCheatCodes;
205
240
  committee: readonly `0x${string}`[];
206
- slashFactory: SlashFactoryContract;
207
- slashingProposer: EmpireSlashingProposerContract | TallySlashingProposerContract | undefined;
241
+ slashingProposer: SlashingProposerContract | undefined;
208
242
  slashingRoundSize: number;
209
243
  aztecSlotDuration: number;
210
244
  aztecEpochDuration: number;
@@ -217,36 +251,14 @@ export async function awaitCommitteeKicked({
217
251
 
218
252
  await cheatCodes.debugRollup();
219
253
 
220
- if (slashingProposer.type === 'empire') {
221
- // Await for the slash payload to be created if empire (no payload is created on tally until execution time)
222
- const targetEpoch = EpochNumber((await cheatCodes.getEpoch()) + (await rollup.getLagInEpochsForValidatorSet()) + 1);
223
- logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
224
- await cheatCodes.advanceToEpoch(targetEpoch);
225
-
226
- const slashPayloadEvents = await retryUntil(
227
- async () => {
228
- const events = await slashFactory.getSlashPayloadCreatedEvents();
229
- return events.length > 0 ? events : undefined;
230
- },
231
- 'slash payload created',
232
- 120,
233
- 1,
234
- );
235
- expect(slashPayloadEvents.length).toBe(1);
236
- // 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)
237
- expect(unique(slashPayloadEvents[0].slashes.map(slash => slash.validator.toString()))).toHaveLength(
238
- committee.length,
239
- );
240
- } else {
241
- // Use the slash offset to ensure we are in the right epoch for tally
242
- const slashOffsetInRounds = await slashingProposer.getSlashOffsetInRounds();
243
- const slashingRoundSizeInEpochs = slashingRoundSize / aztecEpochDuration;
244
- const slashingOffsetInEpochs = Number(slashOffsetInRounds) * slashingRoundSizeInEpochs;
245
- const firstEpochInOffenseRound = offenseEpoch - (offenseEpoch % slashingRoundSizeInEpochs);
246
- const targetEpoch = firstEpochInOffenseRound + slashingOffsetInEpochs;
247
- logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
248
- await cheatCodes.advanceToEpoch(EpochNumber(targetEpoch), { offset: -aztecSlotDuration / 2 });
249
- }
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 });
250
262
 
251
263
  const attestersPre = await rollup.getAttesters();
252
264
  expect(attestersPre.length).toBe(committee.length);
@@ -81,24 +81,28 @@ export class TokenContractTest {
81
81
  await publicDeployAccounts(this.wallet, [this.adminAddress, this.account1Address]);
82
82
 
83
83
  this.logger.verbose(`Deploying TokenContract...`);
84
- this.asset = await TokenContract.deploy(
84
+ ({ contract: this.asset } = await TokenContract.deploy(
85
85
  this.wallet,
86
86
  this.adminAddress,
87
87
  TokenContractTest.TOKEN_NAME,
88
88
  TokenContractTest.TOKEN_SYMBOL,
89
89
  TokenContractTest.TOKEN_DECIMALS,
90
- ).send({ from: this.adminAddress });
90
+ ).send({ from: this.adminAddress }));
91
91
  this.logger.verbose(`Token deployed to ${this.asset.address}`);
92
92
 
93
93
  this.logger.verbose(`Deploying bad account...`);
94
- this.badAccount = await InvalidAccountContract.deploy(this.wallet).send({ from: this.adminAddress });
94
+ ({ contract: this.badAccount } = await InvalidAccountContract.deploy(this.wallet).send({
95
+ from: this.adminAddress,
96
+ }));
95
97
  this.logger.verbose(`Deployed to ${this.badAccount.address}.`);
96
98
 
97
99
  // Deploy a proxy contract for "on behalf of other" tests. The note owner must be the tx sender
98
100
  // (so their notes are in scope), but msg_sender in the target must differ from the note owner
99
101
  // to trigger authwit validation. The proxy forwards calls so that msg_sender != tx sender.
100
102
  this.logger.verbose(`Deploying generic proxy...`);
101
- this.authwitProxy = await GenericProxyContract.deploy(this.wallet).send({ from: this.adminAddress });
103
+ ({ contract: this.authwitProxy } = await GenericProxyContract.deploy(this.wallet).send({
104
+ from: this.adminAddress,
105
+ }));
102
106
  this.logger.verbose(`Deployed to ${this.authwitProxy.address}.`);
103
107
 
104
108
  this.tokenSim = new TokenSimulator(this.asset, this.wallet, this.adminAddress, this.logger, [
@@ -106,7 +110,7 @@ export class TokenContractTest {
106
110
  this.account1Address,
107
111
  ]);
108
112
 
109
- expect(await this.asset.methods.get_admin().simulate({ from: this.adminAddress })).toBe(
113
+ expect((await this.asset.methods.get_admin().simulate({ from: this.adminAddress })).result).toBe(
110
114
  this.adminAddress.toBigInt(),
111
115
  );
112
116
  }
@@ -140,7 +144,9 @@ export class TokenContractTest {
140
144
  await asset.methods.mint_to_public(adminAddress, amount).send({ from: adminAddress });
141
145
  tokenSim.mintPublic(adminAddress, amount);
142
146
 
143
- const publicBalance = await asset.methods.balance_of_public(adminAddress).simulate({ from: adminAddress });
147
+ const { result: publicBalance } = await asset.methods
148
+ .balance_of_public(adminAddress)
149
+ .simulate({ from: adminAddress });
144
150
  this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`);
145
151
  expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(adminAddress));
146
152
 
@@ -148,11 +154,13 @@ export class TokenContractTest {
148
154
  await mintTokensToPrivate(asset, adminAddress, adminAddress, amount);
149
155
  tokenSim.mintPrivate(adminAddress, amount);
150
156
 
151
- const privateBalance = await asset.methods.balance_of_private(adminAddress).simulate({ from: adminAddress });
157
+ const { result: privateBalance } = await asset.methods
158
+ .balance_of_private(adminAddress)
159
+ .simulate({ from: adminAddress });
152
160
  this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`);
153
161
  expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(adminAddress));
154
162
 
155
- const totalSupply = await asset.methods.total_supply().simulate({ from: adminAddress });
163
+ const { result: totalSupply } = await asset.methods.total_supply().simulate({ from: adminAddress });
156
164
  this.logger.verbose(`Total supply: ${totalSupply}`);
157
165
  expect(totalSupply).toEqual(tokenSim.totalSupply);
158
166
 
@@ -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;
@@ -112,7 +110,7 @@ export class FullProverTest {
112
110
  FullProverTest.TOKEN_NAME,
113
111
  FullProverTest.TOKEN_SYMBOL,
114
112
  FullProverTest.TOKEN_DECIMALS,
115
- ).send({ from: this.accounts[0], wait: { returnReceipt: true } });
113
+ ).send({ from: this.accounts[0] });
116
114
  this.logger.verbose(`Token deployed to ${asset.address}`);
117
115
 
118
116
  this.fakeProofsAsset = asset;
@@ -121,7 +119,7 @@ export class FullProverTest {
121
119
 
122
120
  this.tokenSim = new TokenSimulator(this.fakeProofsAsset, this.wallet, this.accounts[0], this.logger, this.accounts);
123
121
 
124
- expect(await this.fakeProofsAsset.methods.get_admin().simulate({ from: this.accounts[0] })).toBe(
122
+ expect((await this.fakeProofsAsset.methods.get_admin().simulate({ from: this.accounts[0] })).result).toBe(
125
123
  this.accounts[0].toBigInt(),
126
124
  );
127
125
  }
@@ -168,9 +166,6 @@ export class FullProverTest {
168
166
 
169
167
  await Barretenberg.initSingleton({ backend: BackendType.NativeUnixSocket });
170
168
 
171
- const verifier = await BBCircuitVerifier.new(bbConfig);
172
- this.circuitProofVerifier = new QueuedIVCVerifier(bbConfig, verifier);
173
-
174
169
  this.logger.debug(`Configuring the node for real proofs...`);
175
170
  await this.aztecNodeAdmin.setConfig({
176
171
  realProofs: true,
@@ -178,7 +173,6 @@ export class FullProverTest {
178
173
  });
179
174
  } else {
180
175
  this.logger.debug(`Configuring the node min txs per block ${this.minNumberOfTxsPerBlock}...`);
181
- this.circuitProofVerifier = new TestCircuitVerifier();
182
176
  await this.aztecNodeAdmin.setConfig({
183
177
  minTxsPerBlock: this.minNumberOfTxsPerBlock,
184
178
  });
@@ -229,8 +223,11 @@ export class FullProverTest {
229
223
 
230
224
  this.logger.verbose('Starting prover node');
231
225
  const sponsoredFPCAddress = await getSponsoredFPCAddress();
232
- const { prefilledPublicData } = await getGenesisValues(
226
+ const { genesis } = await getGenesisValues(
233
227
  this.context.initialFundedAccounts.map(a => a.address).concat(sponsoredFPCAddress),
228
+ undefined,
229
+ undefined,
230
+ this.context.genesis!.genesisTimestamp,
234
231
  );
235
232
 
236
233
  const proverNodeConfig: Parameters<typeof AztecNodeService.createAndSync>[0] = {
@@ -258,7 +255,7 @@ export class FullProverTest {
258
255
  this.proverAztecNode = await AztecNodeService.createAndSync(
259
256
  proverNodeConfig,
260
257
  { dateProvider: this.context.dateProvider, p2pClientDeps: { rpcTxProviders: [this.aztecNode] } },
261
- { prefilledPublicData },
258
+ { genesis },
262
259
  );
263
260
  this.logger.warn(`Proofs are now enabled`, { realProofs: this.realProofs });
264
261
  return this;
@@ -310,16 +307,20 @@ export class FullProverTest {
310
307
  } = this;
311
308
  tokenSim.mintPublic(address, publicAmount);
312
309
 
313
- const publicBalance = await fakeProofsAsset.methods.balance_of_public(address).simulate({ from: address });
310
+ const { result: publicBalance } = await fakeProofsAsset.methods
311
+ .balance_of_public(address)
312
+ .simulate({ from: address });
314
313
  this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`);
315
314
  expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(address));
316
315
 
317
316
  tokenSim.mintPrivate(address, publicAmount);
318
- const privateBalance = await fakeProofsAsset.methods.balance_of_private(address).simulate({ from: address });
317
+ const { result: privateBalance } = await fakeProofsAsset.methods
318
+ .balance_of_private(address)
319
+ .simulate({ from: address });
319
320
  this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`);
320
321
  expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(address));
321
322
 
322
- const totalSupply = await fakeProofsAsset.methods.total_supply().simulate({ from: address });
323
+ const { result: totalSupply } = await fakeProofsAsset.methods.total_supply().simulate({ from: address });
323
324
  this.logger.verbose(`Total supply: ${totalSupply}`);
324
325
  expect(totalSupply).toEqual(tokenSim.totalSupply);
325
326
  }
@@ -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,11 +1,14 @@
1
1
  import { SchnorrAccountContractArtifact } from '@aztec/accounts/schnorr';
2
2
  import { type InitialAccountData, generateSchnorrAccounts } from '@aztec/accounts/testing';
3
3
  import { type AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node';
4
+ import { NO_FROM } from '@aztec/aztec.js/account';
4
5
  import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
5
6
  import {
6
7
  BatchCall,
7
8
  type ContractFunctionInteraction,
8
9
  type ContractMethod,
10
+ type DeployInteractionWaitOptions,
11
+ type DeployOptions,
9
12
  getContractClassFromArtifact,
10
13
  waitForProven,
11
14
  } from '@aztec/aztec.js/contracts';
@@ -30,6 +33,7 @@ import {
30
33
  } from '@aztec/ethereum/deploy-aztec-l1-contracts';
31
34
  import type { Delayer } from '@aztec/ethereum/l1-tx-utils';
32
35
  import { EthCheatCodes, EthCheatCodesWithState, startAnvil } from '@aztec/ethereum/test';
36
+ import type { Anvil } from '@aztec/ethereum/test';
33
37
  import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
34
38
  import { SecretValue } from '@aztec/foundation/config';
35
39
  import { randomBytes } from '@aztec/foundation/crypto/random';
@@ -47,9 +51,10 @@ import type { ProverNodeConfig } from '@aztec/prover-node';
47
51
  import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
48
52
  import type { SequencerClient } from '@aztec/sequencer-client';
49
53
  import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
50
- import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
54
+ import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
51
55
  import { tryStop } from '@aztec/stdlib/interfaces/server';
52
56
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
57
+ import type { GenesisData } from '@aztec/stdlib/world-state';
53
58
  import {
54
59
  type TelemetryClient,
55
60
  type TelemetryClientConfig,
@@ -60,7 +65,6 @@ import { BenchmarkTelemetryClient } from '@aztec/telemetry-client/bench';
60
65
  import { deployFundedSchnorrAccounts } from '@aztec/wallets/testing';
61
66
  import { getGenesisValues } from '@aztec/world-state/testing';
62
67
 
63
- import type { Anvil } from '@viem/anvil';
64
68
  import fs from 'fs/promises';
65
69
  import { tmpdir } from 'os';
66
70
  import path from 'path';
@@ -177,6 +181,8 @@ export type SetupOptions = {
177
181
  proverNodeConfig?: Partial<ProverNodeConfig>;
178
182
  /** Whether to use a mock gossip sub network for p2p clients. */
179
183
  mockGossipSubNetwork?: boolean;
184
+ /** Whether to add simulated latency to the mock gossipsub network (in ms) */
185
+ mockGossipSubNetworkLatency?: number;
180
186
  /** Whether to disable the anvil test watcher (can still be manually started) */
181
187
  disableAnvilTestWatcher?: boolean;
182
188
  /** Whether to enable anvil automine during deployment of L1 contracts (consider defaulting this to true). */
@@ -185,6 +191,11 @@ export type SetupOptions = {
185
191
  anvilAccounts?: number;
186
192
  /** Port to start anvil (defaults to 8545) */
187
193
  anvilPort?: number;
194
+ /**
195
+ * Number of slots per epoch for Anvil's finality simulation.
196
+ * Anvil reports `finalized = latest - slotsInAnEpoch * 2`.
197
+ */
198
+ anvilSlotsInAnEpoch?: number;
188
199
  /** Key to use for publishing L1 contracts */
189
200
  l1PublisherKey?: SecretValue<`0x${string}`>;
190
201
  /** ZkPassport configuration (domain, scope, mock verifier) */
@@ -204,7 +215,7 @@ export type EndToEndContext = {
204
215
  /** The Anvil instance (only set if anvil was started locally). */
205
216
  anvil: Anvil | undefined;
206
217
  /** The Aztec Node service or client a connected to it. */
207
- aztecNode: AztecNode;
218
+ aztecNode: AztecNode & AztecNodeDebug;
208
219
  /** The Aztec Node as a service. */
209
220
  aztecNodeService: AztecNodeService;
210
221
  /** Client to the Aztec Node admin interface. */
@@ -243,8 +254,8 @@ export type EndToEndContext = {
243
254
  sequencerDelayer: Delayer | undefined;
244
255
  /** Delayer for prover node L1 txs (only when enableDelayer and startProverNode are true). */
245
256
  proverDelayer: Delayer | undefined;
246
- /** Prefilled public data used for setting up nodes. */
247
- prefilledPublicData: PublicDataTreeLeaf[] | undefined;
257
+ /** Genesis data used for setting up nodes. */
258
+ genesis: GenesisData | undefined;
248
259
  /** ACVM config (only set if running locally). */
249
260
  acvmConfig: Awaited<ReturnType<typeof getACVMConfig>>;
250
261
  /** BB config (only set if running locally). */
@@ -270,7 +281,7 @@ export async function setup(
270
281
  let anvil: Anvil | undefined;
271
282
  try {
272
283
  opts.aztecTargetCommitteeSize ??= 0;
273
- opts.slasherFlavor ??= 'none';
284
+ opts.slasherEnabled ??= false;
274
285
 
275
286
  const config: AztecNodeConfig & SetupOptions = { ...getConfigEnvVars(), ...opts };
276
287
  // use initialValidators for the node config
@@ -297,6 +308,8 @@ export async function setup(
297
308
  config.dataDirectory = directoryToCleanup;
298
309
  }
299
310
 
311
+ const dateProvider = new TestDateProvider();
312
+
300
313
  if (!config.l1RpcUrls?.length) {
301
314
  if (!isAnvilTestChain(chain.id)) {
302
315
  throw new Error(`No ETHEREUM_HOSTS set but non anvil chain requested`);
@@ -305,6 +318,8 @@ export async function setup(
305
318
  l1BlockTime: opts.ethereumSlotDuration,
306
319
  accounts: opts.anvilAccounts,
307
320
  port: opts.anvilPort ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : undefined),
321
+ slotsInAnEpoch: opts.anvilSlotsInAnEpoch,
322
+ dateProvider,
308
323
  });
309
324
  anvil = res.anvil;
310
325
  config.l1RpcUrls = [res.rpcUrl];
@@ -316,8 +331,6 @@ export async function setup(
316
331
  logger.info(`Logging metrics to ${filename}`);
317
332
  setupMetricsLogger(filename);
318
333
  }
319
-
320
- const dateProvider = new TestDateProvider();
321
334
  const ethCheatCodes = new EthCheatCodesWithState(config.l1RpcUrls, dateProvider);
322
335
 
323
336
  if (opts.stateLoad) {
@@ -367,10 +380,12 @@ export async function setup(
367
380
  addressesToFund.push(sponsoredFPCAddress);
368
381
  }
369
382
 
370
- const { genesisArchiveRoot, prefilledPublicData, fundingNeeded } = await getGenesisValues(
383
+ const genesisTimestamp = BigInt(Math.floor(Date.now() / 1000));
384
+ const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(
371
385
  addressesToFund,
372
386
  opts.initialAccountFeeJuice,
373
387
  opts.genesisPublicData,
388
+ genesisTimestamp,
374
389
  );
375
390
 
376
391
  const wasAutomining = await ethCheatCodes.isAutoMining();
@@ -413,11 +428,12 @@ export async function setup(
413
428
  await ethCheatCodes.setIntervalMining(config.ethereumSlotDuration);
414
429
  }
415
430
 
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);
431
+ // In compose mode (no local anvil), sync dateProvider to L1 time since it may have drifted
432
+ // ahead of system time due to the local-network watcher warping time forward on each filled slot.
433
+ // When running with a local anvil, the dateProvider is kept in sync via the stdout listener.
434
+ if (!anvil) {
435
+ dateProvider.setTime((await ethCheatCodes.lastBlockTimestamp()) * 1000);
436
+ }
421
437
 
422
438
  if (opts.l2StartTime) {
423
439
  await ethCheatCodes.warp(opts.l2StartTime, { resetBlockInterval: true });
@@ -458,7 +474,7 @@ export async function setup(
458
474
  let p2pClientDeps: P2PClientDeps | undefined = undefined;
459
475
 
460
476
  if (opts.mockGossipSubNetwork) {
461
- mockGossipSubNetwork = new MockGossipSubNetwork();
477
+ mockGossipSubNetwork = new MockGossipSubNetwork(opts.mockGossipSubNetworkLatency);
462
478
  p2pClientDeps = { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) };
463
479
  }
464
480
 
@@ -487,11 +503,7 @@ export async function setup(
487
503
  }
488
504
 
489
505
  const aztecNodeService = await withLoggerBindings({ actor: 'node-0' }, () =>
490
- AztecNodeService.createAndSync(
491
- config,
492
- { dateProvider, telemetry: telemetryClient, p2pClientDeps },
493
- { prefilledPublicData },
494
- ),
506
+ AztecNodeService.createAndSync(config, { dateProvider, telemetry: telemetryClient, p2pClientDeps }, { genesis }),
495
507
  );
496
508
  const sequencerClient = aztecNodeService.getSequencer();
497
509
 
@@ -515,7 +527,7 @@ export async function setup(
515
527
  dataDirectory: proverNodeDataDirectory,
516
528
  },
517
529
  { dateProvider, p2pClientDeps, telemetry: telemetryClient },
518
- { prefilledPublicData },
530
+ { genesis },
519
531
  ));
520
532
  }
521
533
 
@@ -620,7 +632,7 @@ export async function setup(
620
632
  initialFundedAccounts,
621
633
  logger,
622
634
  mockGossipSubNetwork,
623
- prefilledPublicData,
635
+ genesis,
624
636
  proverNode,
625
637
  sequencerDelayer,
626
638
  proverDelayer,
@@ -720,7 +732,7 @@ export function createAndSyncProverNode(
720
732
  dateProvider: DateProvider;
721
733
  p2pClientDeps?: P2PClientDeps;
722
734
  },
723
- options: { prefilledPublicData: PublicDataTreeLeaf[]; dontStart?: boolean },
735
+ options: { genesis?: GenesisData; dontStart?: boolean },
724
736
  ): Promise<{ proverNode: AztecNodeService }> {
725
737
  return withLoggerBindings({ actor: 'prover-0' }, async () => {
726
738
  const proverNode = await AztecNodeService.createAndSync(
@@ -733,7 +745,7 @@ export function createAndSyncProverNode(
733
745
  proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
734
746
  },
735
747
  deps,
736
- { ...options, dontStartProverNode: options.dontStart },
748
+ { genesis: options.genesis, dontStartProverNode: options.dontStart },
737
749
  );
738
750
 
739
751
  if (!proverNode.getProverNode()) {
@@ -753,7 +765,9 @@ export function getBalancesFn(
753
765
  ): (...addresses: (AztecAddress | { address: AztecAddress })[]) => Promise<bigint[]> {
754
766
  const balances = async (...addressLikes: (AztecAddress | { address: AztecAddress })[]) => {
755
767
  const addresses = addressLikes.map(addressLike => ('address' in addressLike ? addressLike.address : addressLike));
756
- const b = await Promise.all(addresses.map(address => method(address).simulate({ from: address })));
768
+ const b = await Promise.all(
769
+ addresses.map(async address => (await method(address).simulate({ from: address })).result),
770
+ );
757
771
  const debugString = `${symbol} balances: ${addresses.map((address, i) => `${address}: ${b[i]}`).join(', ')}`;
758
772
  logger.verbose(debugString);
759
773
  return b;
@@ -822,7 +836,7 @@ export async function ensureAccountContractsPublished(wallet: Wallet, accountsTo
822
836
  * Returns deployed account data that can be used by tests.
823
837
  */
824
838
  export const deployAccounts =
825
- (numberOfAccounts: number, logger: Logger) =>
839
+ (numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<DeployInteractionWaitOptions>>) =>
826
840
  async ({ wallet, initialFundedAccounts }: { wallet: TestWallet; initialFundedAccounts: InitialAccountData[] }) => {
827
841
  if (initialFundedAccounts.length < numberOfAccounts) {
828
842
  throw new Error(`Cannot deploy more than ${initialFundedAccounts.length} initial accounts.`);
@@ -839,8 +853,9 @@ export const deployAccounts =
839
853
  );
840
854
  const deployMethod = await accountManager.getDeployMethod();
841
855
  await deployMethod.send({
842
- from: AztecAddress.ZERO,
856
+ from: NO_FROM,
843
857
  skipClassPublication: i !== 0, // Publish the contract class at most once.
858
+ ...deployOptions,
844
859
  });
845
860
  }
846
861
 
@@ -871,7 +886,7 @@ export async function publicDeployAccounts(
871
886
 
872
887
  const batch = new BatchCall(wallet, calls);
873
888
 
874
- const txReceipt = await batch.send({ from: accountsToDeploy[0] });
889
+ const { receipt: txReceipt } = await batch.send({ from: accountsToDeploy[0] });
875
890
  if (waitUntilProven) {
876
891
  if (!node) {
877
892
  throw new Error('Need to provide an AztecNode to wait for proven.');