@aztec/end-to-end 0.0.1-commit.0c875d939 → 0.0.1-commit.0dc957cde

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 (165) 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 +21 -28
  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 +26 -7
  12. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  13. package/dest/e2e_epochs/epochs_test.js +113 -43
  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 +16 -9
  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 +13 -11
  22. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  23. package/dest/e2e_p2p/p2p_network.js +70 -34
  24. package/dest/e2e_p2p/reqresp/utils.d.ts +3 -3
  25. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  26. package/dest/e2e_p2p/reqresp/utils.js +46 -9
  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 +69 -49
  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 +6 -5
  37. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  38. package/dest/fixtures/e2e_prover_test.js +37 -49
  39. package/dest/fixtures/elu_monitor.d.ts +21 -0
  40. package/dest/fixtures/elu_monitor.d.ts.map +1 -0
  41. package/dest/fixtures/elu_monitor.js +102 -0
  42. package/dest/fixtures/fixtures.d.ts +16 -1
  43. package/dest/fixtures/fixtures.d.ts.map +1 -1
  44. package/dest/fixtures/fixtures.js +16 -0
  45. package/dest/fixtures/get_bb_config.d.ts +1 -1
  46. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  47. package/dest/fixtures/get_bb_config.js +5 -5
  48. package/dest/fixtures/ha_setup.d.ts +2 -2
  49. package/dest/fixtures/ha_setup.d.ts.map +1 -1
  50. package/dest/fixtures/ha_setup.js +1 -1
  51. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
  52. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
  53. package/dest/fixtures/schnorr_hardcoded_account_contract.js +39 -0
  54. package/dest/fixtures/setup.d.ts +45 -17
  55. package/dest/fixtures/setup.d.ts.map +1 -1
  56. package/dest/fixtures/setup.js +88 -99
  57. package/dest/fixtures/setup_p2p_test.d.ts +10 -7
  58. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  59. package/dest/fixtures/setup_p2p_test.js +18 -15
  60. package/dest/fixtures/token_utils.d.ts +2 -2
  61. package/dest/fixtures/token_utils.d.ts.map +1 -1
  62. package/dest/fixtures/token_utils.js +5 -7
  63. package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
  64. package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
  65. package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
  66. package/dest/forward-compatibility/wallet_service.d.ts +3 -0
  67. package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
  68. package/dest/forward-compatibility/wallet_service.js +109 -0
  69. package/dest/legacy-jest-resolver.d.cts +3 -0
  70. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  71. package/dest/shared/cross_chain_test_harness.d.ts +1 -1
  72. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  73. package/dest/shared/cross_chain_test_harness.js +13 -13
  74. package/dest/shared/gas_portal_test_harness.js +3 -3
  75. package/dest/shared/jest_setup.js +41 -1
  76. package/dest/shared/submit-transactions.js +1 -1
  77. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  78. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  79. package/dest/shared/uniswap_l1_l2.js +14 -21
  80. package/dest/simulators/lending_simulator.d.ts +1 -1
  81. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  82. package/dest/simulators/lending_simulator.js +4 -4
  83. package/dest/simulators/token_simulator.d.ts +1 -1
  84. package/dest/simulators/token_simulator.d.ts.map +1 -1
  85. package/dest/simulators/token_simulator.js +2 -2
  86. package/dest/spartan/setup_test_wallets.d.ts +11 -2
  87. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  88. package/dest/spartan/setup_test_wallets.js +97 -38
  89. package/dest/spartan/tx_metrics.js +1 -1
  90. package/dest/spartan/utils/bot.d.ts +3 -2
  91. package/dest/spartan/utils/bot.d.ts.map +1 -1
  92. package/dest/spartan/utils/bot.js +2 -1
  93. package/dest/spartan/utils/config.d.ts +7 -1
  94. package/dest/spartan/utils/config.d.ts.map +1 -1
  95. package/dest/spartan/utils/config.js +3 -1
  96. package/dest/spartan/utils/index.d.ts +4 -2
  97. package/dest/spartan/utils/index.d.ts.map +1 -1
  98. package/dest/spartan/utils/index.js +5 -1
  99. package/dest/spartan/utils/k8s.d.ts +3 -1
  100. package/dest/spartan/utils/k8s.d.ts.map +1 -1
  101. package/dest/spartan/utils/k8s.js +6 -0
  102. package/dest/spartan/utils/nodes.d.ts +4 -5
  103. package/dest/spartan/utils/nodes.d.ts.map +1 -1
  104. package/dest/spartan/utils/nodes.js +9 -9
  105. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  106. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  107. package/dest/spartan/utils/pod_logs.js +74 -0
  108. package/dest/test-wallet/test_wallet.d.ts +24 -23
  109. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  110. package/dest/test-wallet/test_wallet.js +119 -82
  111. package/dest/test-wallet/wallet_worker_script.d.ts +2 -0
  112. package/dest/test-wallet/wallet_worker_script.d.ts.map +1 -0
  113. package/dest/test-wallet/wallet_worker_script.js +48 -0
  114. package/dest/test-wallet/worker_wallet.d.ts +52 -0
  115. package/dest/test-wallet/worker_wallet.d.ts.map +1 -0
  116. package/dest/test-wallet/worker_wallet.js +151 -0
  117. package/dest/test-wallet/worker_wallet_schema.d.ts +279 -0
  118. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -0
  119. package/dest/test-wallet/worker_wallet_schema.js +10 -0
  120. package/package.json +43 -44
  121. package/src/bench/client_flows/client_flows_benchmark.ts +29 -12
  122. package/src/bench/utils.ts +7 -2
  123. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +21 -20
  124. package/src/e2e_epochs/epochs_test.ts +131 -70
  125. package/src/e2e_fees/fees_test.ts +17 -8
  126. package/src/e2e_nested_contract/nested_contract_test.ts +6 -4
  127. package/src/e2e_p2p/inactivity_slash_test.ts +3 -3
  128. package/src/e2e_p2p/p2p_network.ts +88 -44
  129. package/src/e2e_p2p/reqresp/utils.ts +58 -9
  130. package/src/e2e_p2p/shared.ts +88 -63
  131. package/src/e2e_token_contract/token_contract_test.ts +16 -8
  132. package/src/fixtures/authwit_proxy.ts +4 -0
  133. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  134. package/src/fixtures/e2e_prover_test.ts +43 -52
  135. package/src/fixtures/elu_monitor.ts +126 -0
  136. package/src/fixtures/fixtures.ts +32 -0
  137. package/src/fixtures/get_bb_config.ts +7 -6
  138. package/src/fixtures/ha_setup.ts +4 -2
  139. package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
  140. package/src/fixtures/setup.ts +125 -132
  141. package/src/fixtures/setup_p2p_test.ts +17 -25
  142. package/src/fixtures/token_utils.ts +3 -3
  143. package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
  144. package/src/forward-compatibility/wallet_service.ts +104 -0
  145. package/src/guides/up_quick_start.sh +0 -2
  146. package/src/legacy-jest-resolver.cjs +135 -0
  147. package/src/shared/cross_chain_test_harness.ts +13 -9
  148. package/src/shared/gas_portal_test_harness.ts +1 -2
  149. package/src/shared/jest_setup.ts +51 -1
  150. package/src/shared/submit-transactions.ts +1 -1
  151. package/src/shared/uniswap_l1_l2.ts +35 -32
  152. package/src/simulators/lending_simulator.ts +8 -4
  153. package/src/simulators/token_simulator.ts +6 -2
  154. package/src/spartan/setup_test_wallets.ts +138 -31
  155. package/src/spartan/tx_metrics.ts +1 -1
  156. package/src/spartan/utils/bot.ts +3 -0
  157. package/src/spartan/utils/config.ts +2 -0
  158. package/src/spartan/utils/index.ts +7 -0
  159. package/src/spartan/utils/k8s.ts +8 -0
  160. package/src/spartan/utils/nodes.ts +15 -10
  161. package/src/spartan/utils/pod_logs.ts +99 -0
  162. package/src/test-wallet/test_wallet.ts +148 -101
  163. package/src/test-wallet/wallet_worker_script.ts +60 -0
  164. package/src/test-wallet/worker_wallet.ts +214 -0
  165. package/src/test-wallet/worker_wallet_schema.ts +13 -0
@@ -1,10 +1,11 @@
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';
4
5
  import { type Logger, createLogger } from '@aztec/aztec.js/log';
5
6
  import type { AztecNode } from '@aztec/aztec.js/node';
6
7
  import type { Wallet } from '@aztec/aztec.js/wallet';
7
- import { CheatCodes } from '@aztec/aztec/testing';
8
+ import { CheatCodes, getTokenAllowedSetupFunctions } from '@aztec/aztec/testing';
8
9
  import { createExtendedL1Client } from '@aztec/ethereum/client';
9
10
  import { RollupContract } from '@aztec/ethereum/contracts';
10
11
  import type { DeployAztecL1ContractsArgs } from '@aztec/ethereum/deploy-aztec-l1-contracts';
@@ -27,7 +28,7 @@ import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
27
28
  import { GasSettings } from '@aztec/stdlib/gas';
28
29
  import { deriveSigningKey } from '@aztec/stdlib/keys';
29
30
 
30
- import { MNEMONIC } from '../../fixtures/fixtures.js';
31
+ import { MNEMONIC, getPaddedMaxFeesPerGas } from '../../fixtures/fixtures.js';
31
32
  import { type EndToEndContext, type SetupOptions, deployAccounts, setup, teardown } from '../../fixtures/setup.js';
32
33
  import { mintTokensToPrivate } from '../../fixtures/token_utils.js';
33
34
  import { setupSponsoredFPC } from '../../fixtures/utils.js';
@@ -130,11 +131,14 @@ export class ClientFlowsBenchmark {
130
131
 
131
132
  async setup() {
132
133
  this.logger.info('Setting up subsystems from fresh');
134
+ // Token allowlist entries are test-only: FPC-based fee payment with custom tokens won't work on mainnet alpha.
135
+ const tokenAllowList = await getTokenAllowedSetupFunctions();
133
136
  this.context = await setup(0, {
134
137
  ...this.setupOptions,
135
138
  fundSponsoredFPC: true,
136
139
  skipAccountDeployment: true,
137
140
  l1ContractsArgs: this.setupOptions,
141
+ txPublicSetupAllowListExtend: [...(this.setupOptions.txPublicSetupAllowListExtend ?? []), ...tokenAllowList],
138
142
  });
139
143
  await this.applyBaseSetup();
140
144
 
@@ -148,6 +152,7 @@ export class ClientFlowsBenchmark {
148
152
 
149
153
  async teardown() {
150
154
  await this.chainMonitor.stop();
155
+ await this.userWallet?.stop();
151
156
  await teardown(this.context);
152
157
  }
153
158
 
@@ -161,11 +166,15 @@ export class ClientFlowsBenchmark {
161
166
 
162
167
  /** Admin mints bananaCoin tokens privately to the target address and redeems them. */
163
168
  async mintPrivateBananas(amount: bigint, address: AztecAddress) {
164
- const balanceBefore = await this.bananaCoin.methods.balance_of_private(address).simulate({ from: address });
169
+ const { result: balanceBefore } = await this.bananaCoin.methods
170
+ .balance_of_private(address)
171
+ .simulate({ from: address });
165
172
 
166
173
  await mintTokensToPrivate(this.bananaCoin, this.adminAddress, address, amount);
167
174
 
168
- const balanceAfter = await this.bananaCoin.methods.balance_of_private(address).simulate({ from: address });
175
+ const { result: balanceAfter } = await this.bananaCoin.methods
176
+ .balance_of_private(address)
177
+ .simulate({ from: address });
169
178
  expect(balanceAfter).toEqual(balanceBefore + amount);
170
179
  }
171
180
 
@@ -247,7 +256,9 @@ export class ClientFlowsBenchmark {
247
256
  'BC',
248
257
  'BC',
249
258
  18n,
250
- ).send({ from: this.adminAddress, wait: { returnReceipt: true } });
259
+ ).send({
260
+ from: this.adminAddress,
261
+ });
251
262
  this.logger.info(`BananaCoin deployed at ${bananaCoin.address}`);
252
263
  this.bananaCoin = bananaCoin;
253
264
  this.bananaCoinInstance = bananaCoinInstance;
@@ -261,7 +272,9 @@ export class ClientFlowsBenchmark {
261
272
  'CBC',
262
273
  'CBC',
263
274
  18n,
264
- ).send({ from: this.adminAddress, wait: { returnReceipt: true } });
275
+ ).send({
276
+ from: this.adminAddress,
277
+ });
265
278
  this.logger.info(`CandyBarCoin deployed at ${candyBarCoin.address}`);
266
279
  this.candyBarCoin = candyBarCoin;
267
280
  this.candyBarCoinInstance = candyBarCoinInstance;
@@ -277,7 +290,9 @@ export class ClientFlowsBenchmark {
277
290
  this.adminWallet,
278
291
  bananaCoin.address,
279
292
  this.adminAddress,
280
- ).send({ from: this.adminAddress, wait: { returnReceipt: true } });
293
+ ).send({
294
+ from: this.adminAddress,
295
+ });
281
296
 
282
297
  this.logger.info(`BananaPay deployed at ${bananaFPC.address}`);
283
298
 
@@ -326,7 +341,7 @@ export class ClientFlowsBenchmark {
326
341
  const claim = await this.feeJuiceBridgeTestHarness.prepareTokensOnL1(benchysAddress);
327
342
  const behchysDeployMethod = await benchysAccountManager.getDeployMethod();
328
343
  await behchysDeployMethod.send({
329
- from: AztecAddress.ZERO,
344
+ from: NO_FROM,
330
345
  fee: { paymentMethod: new FeeJuicePaymentMethodWithClaim(benchysAddress, claim) },
331
346
  });
332
347
  // Register benchy on the user's Wallet, where we're going to be interacting from
@@ -346,13 +361,15 @@ export class ClientFlowsBenchmark {
346
361
  'LPT',
347
362
  'LPT',
348
363
  18n,
349
- ).send({ from: this.adminAddress, wait: { returnReceipt: true } });
364
+ ).send({
365
+ from: this.adminAddress,
366
+ });
350
367
  const { contract: amm, instance: ammInstance } = await AMMContract.deploy(
351
368
  this.adminWallet,
352
369
  this.bananaCoin.address,
353
370
  this.candyBarCoin.address,
354
371
  liquidityToken.address,
355
- ).send({ from: this.adminAddress, wait: { returnReceipt: true } });
372
+ ).send({ from: this.adminAddress });
356
373
  this.logger.info(`AMM deployed at ${amm.address}`);
357
374
  await liquidityToken.methods.set_minter(amm.address, true).send({ from: this.adminAddress });
358
375
  this.liquidityToken = liquidityToken;
@@ -369,8 +386,8 @@ export class ClientFlowsBenchmark {
369
386
  public async getPrivateFPCPaymentMethodForWallet(wallet: Wallet, sender: AztecAddress) {
370
387
  // The private fee paying method assembled on the app side requires knowledge of the maximum
371
388
  // fee the user is willing to pay
372
- const maxFeesPerGas = (await this.aztecNode.getCurrentMinFees()).mul(1.5);
373
- const gasSettings = GasSettings.default({ maxFeesPerGas });
389
+ const maxFeesPerGas = await getPaddedMaxFeesPerGas(this.aztecNode);
390
+ const gasSettings = GasSettings.fallback({ maxFeesPerGas });
374
391
  return new PrivateFeePaymentMethod(this.bananaFPC.address, sender, wallet, gasSettings);
375
392
  }
376
393
 
@@ -25,7 +25,7 @@ export async function benchmarkSetup(
25
25
  ) {
26
26
  const context = await setup(1, { ...opts, telemetryConfig: { benchmark: true } });
27
27
  const defaultAccountAddress = context.accounts[0];
28
- const contract = await BenchmarkingContract.deploy(context.wallet).send({ from: defaultAccountAddress });
28
+ const { contract } = await BenchmarkingContract.deploy(context.wallet).send({ from: defaultAccountAddress });
29
29
  context.logger.info(`Deployed benchmarking contract at ${contract.address}`);
30
30
  const sequencer = (context.aztecNode as AztecNodeService).getSequencer()!;
31
31
  const telemetry = context.telemetryClient as BenchmarkTelemetryClient;
@@ -149,7 +149,12 @@ export async function sendTxs(
149
149
  context.logger.info(`Creating ${txCount} txs`);
150
150
  const [from] = context.accounts;
151
151
  context.logger.info(`Sending ${txCount} txs`);
152
- return Promise.all(calls.map(call => call.send({ from, wait: NO_WAIT })));
152
+ return Promise.all(
153
+ calls.map(async call => {
154
+ const { txHash } = await call.send({ from, wait: NO_WAIT });
155
+ return txHash;
156
+ }),
157
+ );
153
158
  }
154
159
 
155
160
  export async function waitTxs(txs: TxHash[], context: EndToEndContext, txWaitOpts?: WaitOpts) {
@@ -10,6 +10,7 @@ import { TokenBlacklistContract } from '@aztec/noir-contracts.js/TokenBlacklist'
10
10
  import { GenericProxyContract } from '@aztec/noir-test-contracts.js/GenericProxy';
11
11
  import { InvalidAccountContract } from '@aztec/noir-test-contracts.js/InvalidAccount';
12
12
  import type { SequencerClient } from '@aztec/sequencer-client';
13
+ import type { AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
13
14
 
14
15
  import { jest } from '@jest/globals';
15
16
 
@@ -57,7 +58,7 @@ export class BlacklistTokenContractTest {
57
58
  authwitProxy!: GenericProxyContract;
58
59
  cheatCodes!: CheatCodes;
59
60
  sequencer!: SequencerClient;
60
- aztecNode!: AztecNode;
61
+ aztecNode!: AztecNode & AztecNodeDebug;
61
62
 
62
63
  adminAddress!: AztecAddress;
63
64
  otherAddress!: AztecAddress;
@@ -68,11 +69,7 @@ export class BlacklistTokenContractTest {
68
69
  }
69
70
 
70
71
  async crossTimestampOfChange() {
71
- await this.cheatCodes.warpL2TimeAtLeastBy(
72
- this.sequencer,
73
- this.aztecNode,
74
- BlacklistTokenContractTest.CHANGE_ROLES_DELAY,
75
- );
72
+ await this.cheatCodes.warpL2TimeAtLeastBy(this.aztecNode, BlacklistTokenContractTest.CHANGE_ROLES_DELAY);
76
73
  }
77
74
 
78
75
  /**
@@ -107,20 +104,24 @@ export class BlacklistTokenContractTest {
107
104
  await publicDeployAccounts(this.wallet, [this.adminAddress, this.otherAddress, this.blacklistedAddress]);
108
105
 
109
106
  this.logger.verbose(`Deploying TokenContract...`);
110
- this.asset = await TokenBlacklistContract.deploy(this.wallet, this.adminAddress).send({
107
+ ({ contract: this.asset } = await TokenBlacklistContract.deploy(this.wallet, this.adminAddress).send({
111
108
  from: this.adminAddress,
112
- });
109
+ }));
113
110
  this.logger.verbose(`Token deployed to ${this.asset.address}`);
114
111
 
115
112
  this.logger.verbose(`Deploying bad account...`);
116
- this.badAccount = await InvalidAccountContract.deploy(this.wallet).send({ from: this.adminAddress });
113
+ ({ contract: this.badAccount } = await InvalidAccountContract.deploy(this.wallet).send({
114
+ from: this.adminAddress,
115
+ }));
117
116
  this.logger.verbose(`Deployed to ${this.badAccount.address}.`);
118
117
 
119
118
  // Deploy a proxy contract for "on behalf of other" tests. The note owner must be the tx sender
120
119
  // (so their notes are in scope), but msg_sender in the target must differ from the note owner
121
120
  // to trigger authwit validation. The proxy forwards calls so that msg_sender != tx sender.
122
121
  this.logger.verbose(`Deploying generic proxy...`);
123
- this.authwitProxy = await GenericProxyContract.deploy(this.wallet).send({ from: this.adminAddress });
122
+ ({ contract: this.authwitProxy } = await GenericProxyContract.deploy(this.wallet).send({
123
+ from: this.adminAddress,
124
+ }));
124
125
  this.logger.verbose(`Deployed to ${this.authwitProxy.address}.`);
125
126
 
126
127
  await this.crossTimestampOfChange();
@@ -133,9 +134,9 @@ export class BlacklistTokenContractTest {
133
134
  [this.adminAddress, this.otherAddress, this.blacklistedAddress],
134
135
  );
135
136
 
136
- expect(await this.asset.methods.get_roles(this.adminAddress).simulate({ from: this.adminAddress })).toEqual(
137
- new Role().withAdmin().toNoirStruct(),
138
- );
137
+ expect(
138
+ (await this.asset.methods.get_roles(this.adminAddress).simulate({ from: this.adminAddress })).result,
139
+ ).toEqual(new Role().withAdmin().toNoirStruct());
139
140
  }
140
141
 
141
142
  async setup() {
@@ -189,9 +190,9 @@ export class BlacklistTokenContractTest {
189
190
 
190
191
  await this.crossTimestampOfChange();
191
192
 
192
- expect(await this.asset.methods.get_roles(this.adminAddress).simulate({ from: this.adminAddress })).toEqual(
193
- adminMinterRole.toNoirStruct(),
194
- );
193
+ expect(
194
+ (await this.asset.methods.get_roles(this.adminAddress).simulate({ from: this.adminAddress })).result,
195
+ ).toEqual(adminMinterRole.toNoirStruct());
195
196
 
196
197
  this.logger.verbose(`Minting ${amount} publicly...`);
197
198
  await asset.methods.mint_public(this.adminAddress, amount).send({ from: this.adminAddress });
@@ -199,7 +200,7 @@ export class BlacklistTokenContractTest {
199
200
  this.logger.verbose(`Minting ${amount} privately...`);
200
201
  const secret = Fr.random();
201
202
  const secretHash = await computeSecretHash(secret);
202
- const receipt = await asset.methods.mint_private(amount, secretHash).send({ from: this.adminAddress });
203
+ const { receipt } = await asset.methods.mint_private(amount, secretHash).send({ from: this.adminAddress });
203
204
 
204
205
  await this.addPendingShieldNoteToPXE(asset, this.adminAddress, amount, secretHash, receipt.txHash);
205
206
  await asset.methods.redeem_shield(this.adminAddress, amount, secret).send({ from: this.adminAddress });
@@ -207,20 +208,20 @@ export class BlacklistTokenContractTest {
207
208
 
208
209
  tokenSim.mintPublic(this.adminAddress, amount);
209
210
 
210
- const publicBalance = await asset.methods
211
+ const { result: publicBalance } = await asset.methods
211
212
  .balance_of_public(this.adminAddress)
212
213
  .simulate({ from: this.adminAddress });
213
214
  this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`);
214
215
  expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(this.adminAddress));
215
216
 
216
217
  tokenSim.mintPrivate(this.adminAddress, amount);
217
- const privateBalance = await asset.methods
218
+ const { result: privateBalance } = await asset.methods
218
219
  .balance_of_private(this.adminAddress)
219
220
  .simulate({ from: this.adminAddress });
220
221
  this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`);
221
222
  expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(this.adminAddress));
222
223
 
223
- const totalSupply = await asset.methods.total_supply().simulate({ from: this.adminAddress });
224
+ const { result: totalSupply } = await asset.methods.total_supply().simulate({ from: this.adminAddress });
224
225
  this.logger.verbose(`Total supply: ${totalSupply}`);
225
226
  expect(totalSupply).toEqual(tokenSim.totalSupply);
226
227
  }
@@ -1,4 +1,7 @@
1
+ import type { InitialAccountData } from '@aztec/accounts/testing';
2
+ import type { Archiver } from '@aztec/archiver';
1
3
  import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
4
+ import { getAccountContractAddress } from '@aztec/aztec.js/account';
2
5
  import { getTimestampRangeForEpoch } from '@aztec/aztec.js/block';
3
6
  import { getContractInstanceFromInstantiationParams } from '@aztec/aztec.js/contracts';
4
7
  import { Fr } from '@aztec/aztec.js/fields';
@@ -9,7 +12,8 @@ import { EpochCache } from '@aztec/epoch-cache';
9
12
  import { createExtendedL1Client } from '@aztec/ethereum/client';
10
13
  import { DefaultL1ContractsConfig } from '@aztec/ethereum/config';
11
14
  import { RollupContract } from '@aztec/ethereum/contracts';
12
- import { ChainMonitor, DelayedTxUtils, type Delayer, waitUntilL1Timestamp, withDelayer } from '@aztec/ethereum/test';
15
+ import { Delayer, createDelayer, waitUntilL1Timestamp, wrapClientWithDelayer } from '@aztec/ethereum/l1-tx-utils';
16
+ import { ChainMonitor } from '@aztec/ethereum/test';
13
17
  import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
14
18
  import { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
15
19
  import { SecretValue } from '@aztec/foundation/config';
@@ -20,24 +24,22 @@ import { sleep } from '@aztec/foundation/sleep';
20
24
  import { SpamContract } from '@aztec/noir-test-contracts.js/Spam';
21
25
  import { TestContract } from '@aztec/noir-test-contracts.js/Test';
22
26
  import { getMockPubSubP2PServiceFactory } from '@aztec/p2p/test-helpers';
23
- import { ProverNode, type ProverNodeConfig, ProverNodePublisher } from '@aztec/prover-node';
24
- import type { TestProverNode } from '@aztec/prover-node/test';
27
+ import type { ProverNodeConfig } from '@aztec/prover-node';
25
28
  import type { PXEConfig } from '@aztec/pxe/config';
26
- import {
27
- type SequencerClient,
28
- type SequencerEvents,
29
- type SequencerPublisher,
30
- SequencerState,
31
- } from '@aztec/sequencer-client';
32
- import type { TestSequencerClient } from '@aztec/sequencer-client/test';
29
+ import { type SequencerClient, type SequencerEvents, SequencerState } from '@aztec/sequencer-client';
33
30
  import { type BlockParameter, EthAddress } from '@aztec/stdlib/block';
34
31
  import { type L1RollupConstants, getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
35
32
  import { tryStop } from '@aztec/stdlib/interfaces/server';
33
+ import type { SlashingProtectionDatabase } from '@aztec/validator-ha-signer/types';
36
34
 
37
35
  import { join } from 'path';
38
36
  import type { Hex } from 'viem';
39
37
  import { privateKeyToAccount } from 'viem/accounts';
40
38
 
39
+ import {
40
+ SCHNORR_HARDCODED_PRIVATE_KEY,
41
+ SchnorrHardcodedKeyAccountContract,
42
+ } from '../fixtures/schnorr_hardcoded_account_contract.js';
41
43
  import {
42
44
  type EndToEndContext,
43
45
  type SetupOptions,
@@ -45,8 +47,9 @@ import {
45
47
  getPrivateKeyFromIndex,
46
48
  setup,
47
49
  } from '../fixtures/utils.js';
50
+ import type { TestWallet } from '../test-wallet/test_wallet.js';
48
51
 
49
- export const WORLD_STATE_BLOCK_HISTORY = 2;
52
+ export const WORLD_STATE_CHECKPOINT_HISTORY = 2;
50
53
  export const WORLD_STATE_BLOCK_CHECK_INTERVAL = 50;
51
54
  export const ARCHIVER_POLL_INTERVAL = 50;
52
55
  export const DEFAULT_L1_BLOCK_TIME = process.env.CI ? 12 : 8;
@@ -55,6 +58,8 @@ export type EpochsTestOpts = Partial<SetupOptions> & {
55
58
  numberOfAccounts?: number;
56
59
  pxeOpts?: Partial<PXEConfig>;
57
60
  aztecSlotDurationInL1Slots?: number;
61
+ /** Skip creating/registering the hardcoded account during setup (for tests that handle accounts themselves). */
62
+ skipHardcodedAccount?: boolean;
58
63
  };
59
64
 
60
65
  export type TrackedSequencerEvent = {
@@ -81,7 +86,7 @@ export class EpochsTestContext {
81
86
  public proverDelayer!: Delayer;
82
87
  public sequencerDelayer!: Delayer;
83
88
 
84
- public proverNodes: ProverNode[] = [];
89
+ public proverNodes: AztecNodeService[] = [];
85
90
  public nodes: AztecNodeService[] = [];
86
91
 
87
92
  public epochDuration!: number;
@@ -125,10 +130,18 @@ export class EpochsTestContext {
125
130
  this.L1_BLOCK_TIME_IN_S = ethereumSlotDuration;
126
131
  this.L2_SLOT_DURATION_IN_S = aztecSlotDuration;
127
132
 
133
+ // When skipInitialSequencer is set, auto-create a hardcoded account funded via genesis.
134
+ // This avoids needing to deploy accounts on-chain (which would require a running sequencer).
135
+ const useHardcodedAccount = opts.skipInitialSequencer && !opts.skipHardcodedAccount;
136
+ let hardcodedAccountData: InitialAccountData | undefined;
137
+ if (useHardcodedAccount) {
138
+ hardcodedAccountData = await EpochsTestContext.getHardcodedAccountData(Fr.random(), Fr.random());
139
+ }
140
+
128
141
  // Set up system without any account nor protocol contracts
129
142
  // and with faster block times and shorter epochs.
130
143
  const context = await setup(
131
- opts.numberOfAccounts ?? 0,
144
+ useHardcodedAccount ? 0 : (opts.numberOfAccounts ?? 0),
132
145
  {
133
146
  automineL1Setup: true,
134
147
  checkIntervalMs: 50,
@@ -143,15 +156,13 @@ export class EpochsTestContext {
143
156
  realProofs: false,
144
157
  startProverNode: true,
145
158
  proverTestDelayMs: opts.proverTestDelayMs ?? 0,
146
- // We use numeric incremental prover ids for simplicity, but we can switch to
147
- // using the prover's eth address if the proverId is used for something in the rollup contract
148
- // Use numeric EthAddress for deterministic prover id
149
159
  proverId: EthAddress.fromNumber(1),
150
- worldStateBlockHistory: WORLD_STATE_BLOCK_HISTORY,
160
+ worldStateCheckpointHistory: WORLD_STATE_CHECKPOINT_HISTORY,
151
161
  exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
152
- slasherFlavor: 'none',
162
+ slasherEnabled: false,
153
163
  l1PublishingTime,
154
164
  ...opts,
165
+ ...(hardcodedAccountData ? { initialFundedAccounts: [hardcodedAccountData], numberOfAccounts: 0 } : {}),
155
166
  },
156
167
  // Use checkpointed chain tip for PXE by default to avoid issues with blocks being dropped due to pruned anchor blocks.
157
168
  // Can be overridden via opts.pxeOpts.
@@ -159,6 +170,11 @@ export class EpochsTestContext {
159
170
  );
160
171
 
161
172
  this.context = context;
173
+
174
+ // Register the hardcoded account in PXE (local only, no on-chain deployment needed).
175
+ if (hardcodedAccountData) {
176
+ await this.registerHardcodedAccount(hardcodedAccountData);
177
+ }
162
178
  this.proverNodes = context.proverNode ? [context.proverNode] : [];
163
179
  this.nodes = context.aztecNode ? [context.aztecNode as AztecNodeService] : [];
164
180
  this.logger = context.logger;
@@ -169,17 +185,8 @@ export class EpochsTestContext {
169
185
  // Loop that tracks L1 and L2 block numbers and logs whenever there's a new one.
170
186
  this.monitor = new ChainMonitor(this.rollup, context.dateProvider, this.logger).start();
171
187
 
172
- // This is hideous.
173
- // We ought to have a definite reference to the l1TxUtils that we're using in both places, provided by the test context.
174
- this.proverDelayer = context.proverNode
175
- ? (((context.proverNode as TestProverNode).publisher as ProverNodePublisher).l1TxUtils as DelayedTxUtils).delayer!
176
- : undefined!;
177
- this.sequencerDelayer = context.sequencer
178
- ? (
179
- ((context.sequencer as TestSequencerClient).sequencer.publisher as SequencerPublisher)
180
- .l1TxUtils as DelayedTxUtils
181
- ).delayer!
182
- : undefined!;
188
+ this.proverDelayer = context.proverDelayer!;
189
+ this.sequencerDelayer = context.sequencerDelayer!;
183
190
 
184
191
  if ((context.proverNode && !this.proverDelayer) || (context.sequencer && !this.sequencerDelayer)) {
185
192
  throw new Error(`Could not find prover or sequencer delayer`);
@@ -195,6 +202,7 @@ export class EpochsTestContext {
195
202
  ethereumSlotDuration,
196
203
  proofSubmissionEpochs: Number(await this.rollup.getProofSubmissionEpochs()),
197
204
  targetCommitteeSize: await this.rollup.getTargetCommitteeSize(),
205
+ rollupManaLimit: Number(await this.rollup.getManaLimit()),
198
206
  };
199
207
 
200
208
  this.logger.info(
@@ -209,31 +217,63 @@ export class EpochsTestContext {
209
217
  await this.context.teardown();
210
218
  }
211
219
 
220
+ /**
221
+ * Computes InitialAccountData for a SchnorrHardcodedKeyAccountContract.
222
+ * This contract has a hardcoded signing key and no initializer, so it can be used without
223
+ * on-chain deployment. Pass the returned data in `initialFundedAccounts` so the address
224
+ * gets funded with fee juice in genesis.
225
+ */
226
+ public static async getHardcodedAccountData(secret: Fr, salt: Fr): Promise<InitialAccountData> {
227
+ const contract = new SchnorrHardcodedKeyAccountContract();
228
+ const address = await getAccountContractAddress(contract, secret, salt);
229
+ const signingKey = SCHNORR_HARDCODED_PRIVATE_KEY;
230
+ return { secret, salt, signingKey, address };
231
+ }
232
+
233
+ /**
234
+ * Registers a SchnorrHardcodedKeyAccountContract in PXE. The account must have been funded
235
+ * at genesis (via getHardcodedAccountData). No on-chain deployment or block mining needed.
236
+ */
237
+ public async registerHardcodedAccount(accountData: InitialAccountData) {
238
+ const contract = new SchnorrHardcodedKeyAccountContract();
239
+ const wallet = this.context.wallet;
240
+ const accountManager = await (wallet as TestWallet).createAccount({
241
+ secret: accountData.secret,
242
+ salt: accountData.salt,
243
+ contract,
244
+ });
245
+ this.context.accounts = [accountManager.address];
246
+ return accountManager.address;
247
+ }
248
+
212
249
  public async createProverNode(opts: { dontStart?: boolean } & Partial<ProverNodeConfig> = {}) {
213
250
  this.logger.warn('Creating and syncing a simulated prover node...');
214
251
  const proverNodePrivateKey = this.getNextPrivateKey();
215
252
  const proverIndex = this.proverNodes.length + 1;
216
253
  const { mockGossipSubNetwork } = this.context;
217
- const proverNode = await withLoggerBindings({ actor: `prover-${proverIndex}` }, () =>
254
+ const { proverNode } = await withLoggerBindings({ actor: `prover-${proverIndex}` }, () =>
218
255
  createAndSyncProverNode(
219
256
  proverNodePrivateKey,
220
257
  {
221
258
  ...this.context.config,
222
259
  p2pEnabled: this.context.config.p2pEnabled || mockGossipSubNetwork !== undefined,
223
- },
224
- {
225
- dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
226
260
  proverId: EthAddress.fromNumber(proverIndex),
227
261
  dontStart: opts.dontStart,
228
262
  ...opts,
229
263
  },
230
- this.context.aztecNode,
231
- this.context.prefilledPublicData ?? [],
264
+ {
265
+ dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
266
+ },
232
267
  {
233
268
  dateProvider: this.context.dateProvider,
234
- p2pClientDeps: mockGossipSubNetwork
235
- ? { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) }
236
- : undefined,
269
+ p2pClientDeps: {
270
+ p2pServiceFactory: mockGossipSubNetwork ? getMockPubSubP2PServiceFactory(mockGossipSubNetwork) : undefined,
271
+ rpcTxProviders: [this.context.aztecNode],
272
+ },
273
+ },
274
+ {
275
+ genesis: this.context.genesis,
276
+ dontStart: opts.dontStart,
237
277
  },
238
278
  ),
239
279
  );
@@ -248,14 +288,20 @@ export class EpochsTestContext {
248
288
 
249
289
  public createValidatorNode(
250
290
  privateKeys: `0x${string}`[],
251
- opts: Partial<AztecNodeConfig> & { txDelayerMaxInclusionTimeIntoSlot?: number; dontStartSequencer?: boolean } = {},
291
+ opts: Partial<AztecNodeConfig> & {
292
+ dontStartSequencer?: boolean;
293
+ slashingProtectionDb?: SlashingProtectionDatabase;
294
+ } = {},
252
295
  ) {
253
296
  this.logger.warn('Creating and syncing a validator node...');
254
297
  return this.createNode({ ...opts, disableValidator: false, validatorPrivateKeys: new SecretValue(privateKeys) });
255
298
  }
256
299
 
257
300
  private async createNode(
258
- opts: Partial<AztecNodeConfig> & { txDelayerMaxInclusionTimeIntoSlot?: number; dontStartSequencer?: boolean } = {},
301
+ opts: Partial<AztecNodeConfig> & {
302
+ dontStartSequencer?: boolean;
303
+ slashingProtectionDb?: SlashingProtectionDatabase;
304
+ } = {},
259
305
  ) {
260
306
  const nodeIndex = this.nodes.length + 1;
261
307
  const actorPrefix = opts.disableValidator ? 'node' : 'validator';
@@ -269,6 +315,7 @@ export class EpochsTestContext {
269
315
  ...resolvedConfig,
270
316
  dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
271
317
  validatorPrivateKeys: opts.validatorPrivateKeys ?? new SecretValue([]),
318
+ nodeId: resolvedConfig.nodeId || `${actorPrefix}-${nodeIndex}`,
272
319
  p2pEnabled,
273
320
  p2pIp,
274
321
  },
@@ -277,34 +324,15 @@ export class EpochsTestContext {
277
324
  p2pClientDeps: {
278
325
  p2pServiceFactory: mockGossipSubNetwork ? getMockPubSubP2PServiceFactory(mockGossipSubNetwork) : undefined,
279
326
  },
327
+ slashingProtectionDb: opts.slashingProtectionDb,
280
328
  },
281
329
  {
282
- prefilledPublicData: this.context.prefilledPublicData,
330
+ genesis: this.context.genesis,
283
331
  ...opts,
284
332
  },
285
333
  ),
286
334
  );
287
335
 
288
- // REFACTOR: We're getting too much into the internals of the sequencer here.
289
- // We should have a single method for constructing an aztec node that returns a TestAztecNodeService
290
- // which directly exposes the delayer and sets any test config.
291
- if (opts.txDelayerMaxInclusionTimeIntoSlot !== undefined) {
292
- this.logger.info(
293
- `Setting tx delayer max inclusion time into slot to ${opts.txDelayerMaxInclusionTimeIntoSlot} seconds`,
294
- );
295
- // Here we reach into the sequencer and hook in a tx delayer. The problem is that the sequencer's l1 utils only uses a public client, not a wallet.
296
- // The delayer needs a wallet (a client that can sign), so we have to create one here.
297
- const l1Client = createExtendedL1Client(
298
- resolvedConfig.l1RpcUrls!,
299
- resolvedConfig.publisherPrivateKeys![0]!.getValue(),
300
- );
301
- const sequencer = node.getSequencer() as TestSequencerClient;
302
- const publisher = sequencer.sequencer.publisher;
303
- const delayed = DelayedTxUtils.fromL1TxUtils(publisher.l1TxUtils, this.L1_BLOCK_TIME_IN_S, l1Client);
304
- delayed.delayer!.setMaxInclusionTimeIntoSlot(opts.txDelayerMaxInclusionTimeIntoSlot);
305
- publisher.l1TxUtils = delayed;
306
- }
307
-
308
336
  this.nodes.push(node);
309
337
  return node;
310
338
  }
@@ -356,7 +384,10 @@ export class EpochsTestContext {
356
384
  this.logger.info(`Waiting until last slot of submission window for epoch ${epochNumber} at ${date}`, {
357
385
  oneSlotBefore,
358
386
  });
359
- await waitUntilL1Timestamp(this.l1Client, oneSlotBefore);
387
+ // Use a timeout that accounts for the full proof submission window
388
+ const proofSubmissionWindowDuration =
389
+ this.constants.proofSubmissionEpochs * this.epochDuration * this.L2_SLOT_DURATION_IN_S;
390
+ await waitUntilL1Timestamp(this.l1Client, oneSlotBefore, undefined, proofSubmissionWindowDuration * 2);
360
391
  }
361
392
 
362
393
  /** Waits for the aztec node to sync to the target block number. */
@@ -408,15 +439,13 @@ export class EpochsTestContext {
408
439
 
409
440
  /** Creates an L1 client using a fresh account with funds from anvil, with a tx delayer already set up. */
410
441
  public async createL1Client() {
411
- const { client, delayer } = withDelayer(
412
- createExtendedL1Client(
413
- [...this.l1Client.chain.rpcUrls.default.http],
414
- privateKeyToAccount(this.getNextPrivateKey()),
415
- this.l1Client.chain,
416
- ),
417
- this.context.dateProvider,
418
- { ethereumSlotDuration: this.L1_BLOCK_TIME_IN_S },
442
+ const rawClient = createExtendedL1Client(
443
+ [...this.l1Client.chain.rpcUrls.default.http],
444
+ privateKeyToAccount(this.getNextPrivateKey()),
445
+ this.l1Client.chain,
419
446
  );
447
+ const delayer = createDelayer(this.context.dateProvider, { ethereumSlotDuration: this.L1_BLOCK_TIME_IN_S }, {});
448
+ const client = wrapClientWithDelayer(rawClient, delayer);
420
449
  expect(await client.getBalance({ address: client.account.address })).toBeGreaterThan(0n);
421
450
  return { client, delayer };
422
451
  }
@@ -433,6 +462,38 @@ export class EpochsTestContext {
433
462
  expect(result).toBe(expectedSuccess);
434
463
  }
435
464
 
465
+ /** Verifies at least one checkpoint has the target number of blocks (for MBPS validation). */
466
+ public async assertMultipleBlocksPerSlot(targetBlockCount: number) {
467
+ const archiver = (this.context.aztecNode as AztecNodeService).getBlockSource() as Archiver;
468
+ const checkpoints = await archiver.getCheckpoints(CheckpointNumber(1), 50);
469
+
470
+ this.logger.warn(`Retrieved ${checkpoints.length} checkpoints from archiver`, {
471
+ checkpoints: checkpoints.map(pc => pc.checkpoint.getStats()),
472
+ });
473
+
474
+ let expectedBlockNumber = checkpoints[0].checkpoint.blocks[0].number;
475
+ let targetFound = false;
476
+
477
+ for (const checkpoint of checkpoints) {
478
+ const blockCount = checkpoint.checkpoint.blocks.length;
479
+ targetFound = targetFound || blockCount >= targetBlockCount;
480
+
481
+ this.logger.verbose(`Checkpoint ${checkpoint.checkpoint.number} has ${blockCount} blocks`, {
482
+ checkpoint: checkpoint.checkpoint.getStats(),
483
+ });
484
+
485
+ for (let i = 0; i < blockCount; i++) {
486
+ const block = checkpoint.checkpoint.blocks[i];
487
+ expect(block.indexWithinCheckpoint).toBe(i);
488
+ expect(block.checkpointNumber).toBe(checkpoint.checkpoint.number);
489
+ expect(block.number).toBe(expectedBlockNumber);
490
+ expectedBlockNumber++;
491
+ }
492
+ }
493
+
494
+ expect(targetFound).toBe(true);
495
+ }
496
+
436
497
  public watchSequencerEvents(
437
498
  sequencers: SequencerClient[],
438
499
  getMetadata: (i: number) => Record<string, any> = () => ({}),