@aztec/end-to-end 0.0.1-commit.e588bc7e5 → 0.0.1-commit.e5a3663dd

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 (95) hide show
  1. package/README.md +27 -0
  2. package/dest/bench/client_flows/client_flows_benchmark.js +3 -3
  3. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +3 -2
  4. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  5. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +1 -1
  6. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +1 -1
  7. package/dest/e2e_epochs/epochs_test.d.ts +16 -1
  8. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  9. package/dest/e2e_epochs/epochs_test.js +56 -8
  10. package/dest/e2e_fees/fees_test.d.ts +1 -1
  11. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  12. package/dest/e2e_fees/fees_test.js +4 -4
  13. package/dest/e2e_p2p/inactivity_slash_test.js +2 -2
  14. package/dest/e2e_p2p/p2p_network.d.ts +10 -9
  15. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  16. package/dest/e2e_p2p/p2p_network.js +46 -27
  17. package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
  18. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  19. package/dest/e2e_p2p/reqresp/utils.js +10 -7
  20. package/dest/e2e_p2p/shared.d.ts +5 -7
  21. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  22. package/dest/e2e_p2p/shared.js +36 -47
  23. package/dest/fixtures/authwit_proxy.d.ts +1 -1
  24. package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
  25. package/dest/fixtures/authwit_proxy.js +4 -0
  26. package/dest/fixtures/e2e_prover_test.d.ts +1 -1
  27. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  28. package/dest/fixtures/e2e_prover_test.js +2 -2
  29. package/dest/fixtures/fixtures.d.ts +12 -1
  30. package/dest/fixtures/fixtures.d.ts.map +1 -1
  31. package/dest/fixtures/fixtures.js +10 -0
  32. package/dest/fixtures/ha_setup.d.ts +2 -2
  33. package/dest/fixtures/ha_setup.d.ts.map +1 -1
  34. package/dest/fixtures/ha_setup.js +1 -1
  35. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
  36. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
  37. package/dest/fixtures/schnorr_hardcoded_account_contract.js +39 -0
  38. package/dest/fixtures/setup.d.ts +17 -10
  39. package/dest/fixtures/setup.d.ts.map +1 -1
  40. package/dest/fixtures/setup.js +29 -13
  41. package/dest/fixtures/setup_p2p_test.d.ts +6 -6
  42. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  43. package/dest/fixtures/setup_p2p_test.js +8 -8
  44. package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
  45. package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
  46. package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
  47. package/dest/forward-compatibility/wallet_service.d.ts +3 -0
  48. package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
  49. package/dest/forward-compatibility/wallet_service.js +109 -0
  50. package/dest/legacy-jest-resolver.d.cts +3 -0
  51. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  52. package/dest/shared/gas_portal_test_harness.js +1 -1
  53. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  54. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  55. package/dest/shared/uniswap_l1_l2.js +0 -4
  56. package/dest/spartan/setup_test_wallets.d.ts +1 -1
  57. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  58. package/dest/spartan/setup_test_wallets.js +6 -37
  59. package/dest/spartan/tx_metrics.d.ts +1 -1
  60. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  61. package/dest/spartan/tx_metrics.js +18 -2
  62. package/dest/test-wallet/test_wallet.d.ts +16 -8
  63. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  64. package/dest/test-wallet/test_wallet.js +91 -49
  65. package/dest/test-wallet/worker_wallet.d.ts +4 -4
  66. package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
  67. package/dest/test-wallet/worker_wallet_schema.d.ts +7 -2
  68. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
  69. package/package.json +40 -39
  70. package/src/bench/client_flows/client_flows_benchmark.ts +3 -3
  71. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +3 -6
  72. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +1 -1
  73. package/src/e2e_epochs/epochs_test.ts +56 -7
  74. package/src/e2e_fees/fees_test.ts +5 -3
  75. package/src/e2e_p2p/inactivity_slash_test.ts +2 -2
  76. package/src/e2e_p2p/p2p_network.ts +57 -39
  77. package/src/e2e_p2p/reqresp/utils.ts +8 -7
  78. package/src/e2e_p2p/shared.ts +33 -61
  79. package/src/fixtures/authwit_proxy.ts +4 -0
  80. package/src/fixtures/e2e_prover_test.ts +5 -2
  81. package/src/fixtures/fixtures.ts +22 -0
  82. package/src/fixtures/ha_setup.ts +4 -2
  83. package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
  84. package/src/fixtures/setup.ts +44 -18
  85. package/src/fixtures/setup_p2p_test.ts +9 -9
  86. package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
  87. package/src/forward-compatibility/wallet_service.ts +104 -0
  88. package/src/guides/up_quick_start.sh +0 -2
  89. package/src/legacy-jest-resolver.cjs +135 -0
  90. package/src/shared/gas_portal_test_harness.ts +0 -1
  91. package/src/shared/uniswap_l1_l2.ts +0 -4
  92. package/src/spartan/setup_test_wallets.ts +4 -30
  93. package/src/spartan/tx_metrics.ts +16 -4
  94. package/src/test-wallet/test_wallet.ts +108 -52
  95. package/src/test-wallet/worker_wallet.ts +3 -2
@@ -1,5 +1,7 @@
1
+ import type { InitialAccountData } from '@aztec/accounts/testing';
1
2
  import type { Archiver } from '@aztec/archiver';
2
3
  import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
4
+ import { getAccountContractAddress } from '@aztec/aztec.js/account';
3
5
  import { getTimestampRangeForEpoch } from '@aztec/aztec.js/block';
4
6
  import { getContractInstanceFromInstantiationParams } from '@aztec/aztec.js/contracts';
5
7
  import { Fr } from '@aztec/aztec.js/fields';
@@ -34,6 +36,10 @@ import { join } from 'path';
34
36
  import type { Hex } from 'viem';
35
37
  import { privateKeyToAccount } from 'viem/accounts';
36
38
 
39
+ import {
40
+ SCHNORR_HARDCODED_PRIVATE_KEY,
41
+ SchnorrHardcodedKeyAccountContract,
42
+ } from '../fixtures/schnorr_hardcoded_account_contract.js';
37
43
  import {
38
44
  type EndToEndContext,
39
45
  type SetupOptions,
@@ -41,6 +47,7 @@ import {
41
47
  getPrivateKeyFromIndex,
42
48
  setup,
43
49
  } from '../fixtures/utils.js';
50
+ import type { TestWallet } from '../test-wallet/test_wallet.js';
44
51
 
45
52
  export const WORLD_STATE_CHECKPOINT_HISTORY = 2;
46
53
  export const WORLD_STATE_BLOCK_CHECK_INTERVAL = 50;
@@ -51,6 +58,8 @@ export type EpochsTestOpts = Partial<SetupOptions> & {
51
58
  numberOfAccounts?: number;
52
59
  pxeOpts?: Partial<PXEConfig>;
53
60
  aztecSlotDurationInL1Slots?: number;
61
+ /** Skip creating/registering the hardcoded account during setup (for tests that handle accounts themselves). */
62
+ skipHardcodedAccount?: boolean;
54
63
  };
55
64
 
56
65
  export type TrackedSequencerEvent = {
@@ -121,10 +130,18 @@ export class EpochsTestContext {
121
130
  this.L1_BLOCK_TIME_IN_S = ethereumSlotDuration;
122
131
  this.L2_SLOT_DURATION_IN_S = aztecSlotDuration;
123
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
+
124
141
  // Set up system without any account nor protocol contracts
125
142
  // and with faster block times and shorter epochs.
126
143
  const context = await setup(
127
- opts.numberOfAccounts ?? 0,
144
+ useHardcodedAccount ? 0 : (opts.numberOfAccounts ?? 0),
128
145
  {
129
146
  automineL1Setup: true,
130
147
  checkIntervalMs: 50,
@@ -139,15 +156,13 @@ export class EpochsTestContext {
139
156
  realProofs: false,
140
157
  startProverNode: true,
141
158
  proverTestDelayMs: opts.proverTestDelayMs ?? 0,
142
- // We use numeric incremental prover ids for simplicity, but we can switch to
143
- // using the prover's eth address if the proverId is used for something in the rollup contract
144
- // Use numeric EthAddress for deterministic prover id
145
159
  proverId: EthAddress.fromNumber(1),
146
160
  worldStateCheckpointHistory: WORLD_STATE_CHECKPOINT_HISTORY,
147
161
  exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
148
- slasherFlavor: 'none',
162
+ slasherEnabled: false,
149
163
  l1PublishingTime,
150
164
  ...opts,
165
+ ...(hardcodedAccountData ? { initialFundedAccounts: [hardcodedAccountData], numberOfAccounts: 0 } : {}),
151
166
  },
152
167
  // Use checkpointed chain tip for PXE by default to avoid issues with blocks being dropped due to pruned anchor blocks.
153
168
  // Can be overridden via opts.pxeOpts.
@@ -155,6 +170,11 @@ export class EpochsTestContext {
155
170
  );
156
171
 
157
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
+ }
158
178
  this.proverNodes = context.proverNode ? [context.proverNode] : [];
159
179
  this.nodes = context.aztecNode ? [context.aztecNode as AztecNodeService] : [];
160
180
  this.logger = context.logger;
@@ -197,6 +217,35 @@ export class EpochsTestContext {
197
217
  await this.context.teardown();
198
218
  }
199
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
+
200
249
  public async createProverNode(opts: { dontStart?: boolean } & Partial<ProverNodeConfig> = {}) {
201
250
  this.logger.warn('Creating and syncing a simulated prover node...');
202
251
  const proverNodePrivateKey = this.getNextPrivateKey();
@@ -223,7 +272,7 @@ export class EpochsTestContext {
223
272
  },
224
273
  },
225
274
  {
226
- prefilledPublicData: this.context.prefilledPublicData ?? [],
275
+ genesis: this.context.genesis,
227
276
  dontStart: opts.dontStart,
228
277
  },
229
278
  ),
@@ -278,7 +327,7 @@ export class EpochsTestContext {
278
327
  slashingProtectionDb: opts.slashingProtectionDb,
279
328
  },
280
329
  {
281
- prefilledPublicData: this.context.prefilledPublicData,
330
+ genesis: this.context.genesis,
282
331
  ...opts,
283
332
  },
284
333
  ),
@@ -23,7 +23,7 @@ import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
23
23
 
24
24
  import { getContract } from 'viem';
25
25
 
26
- import { MNEMONIC } from '../fixtures/fixtures.js';
26
+ import { MNEMONIC, getPaddedMaxFeesPerGas } from '../fixtures/fixtures.js';
27
27
  import {
28
28
  type EndToEndContext,
29
29
  type SetupOptions,
@@ -134,7 +134,7 @@ export class FeesTest {
134
134
 
135
135
  async catchUpProvenChain() {
136
136
  const bn = await this.aztecNode.getBlockNumber();
137
- while ((await this.aztecNode.getProvenBlockNumber()) < bn) {
137
+ while ((await this.aztecNode.getBlockNumber('proven')) < bn) {
138
138
  await sleep(1000);
139
139
  }
140
140
  }
@@ -193,7 +193,9 @@ export class FeesTest {
193
193
  this.wallet = this.context.wallet;
194
194
  this.aztecNode = this.context.aztecNodeService;
195
195
  this.aztecNodeAdmin = this.context.aztecNodeService;
196
- this.gasSettings = GasSettings.default({ maxFeesPerGas: (await this.aztecNode.getCurrentMinFees()).mul(2) });
196
+ this.gasSettings = GasSettings.fallback({
197
+ maxFeesPerGas: await getPaddedMaxFeesPerGas(this.aztecNode),
198
+ });
197
199
  this.cheatCodes = this.context.cheatCodes;
198
200
  this.accounts = deployedAccounts.map(a => a.address);
199
201
  this.accounts.forEach((a, i) => this.logger.verbose(`Account ${i} address: ${a}`));
@@ -108,7 +108,7 @@ export class P2PInactivityTest {
108
108
  this.test.bootstrapNodeEnr,
109
109
  NUM_NODES - this.inactiveNodeCount - Number(this.keepInitialNode),
110
110
  BOOT_NODE_UDP_PORT,
111
- this.test.prefilledPublicData,
111
+ this.test.genesis,
112
112
  this.dataDir,
113
113
  undefined,
114
114
  Number(this.keepInitialNode),
@@ -122,7 +122,7 @@ export class P2PInactivityTest {
122
122
  this.test.bootstrapNodeEnr,
123
123
  this.inactiveNodeCount,
124
124
  BOOT_NODE_UDP_PORT,
125
- this.test.prefilledPublicData,
125
+ this.test.genesis,
126
126
  this.dataDir,
127
127
  undefined,
128
128
  NUM_NODES - this.inactiveNodeCount,
@@ -1,14 +1,10 @@
1
- import type { InitialAccountData } from '@aztec/accounts/testing';
1
+ import { type InitialAccountData, generateSchnorrAccounts } from '@aztec/accounts/testing';
2
2
  import type { AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
3
+ import { getAccountContractAddress } from '@aztec/aztec.js/account';
3
4
  import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
4
5
  import { Fr } from '@aztec/aztec.js/fields';
5
6
  import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
6
- import {
7
- type EmpireSlashingProposerContract,
8
- GSEContract,
9
- RollupContract,
10
- type TallySlashingProposerContract,
11
- } from '@aztec/ethereum/contracts';
7
+ import { GSEContract, RollupContract, type SlashingProposerContract } from '@aztec/ethereum/contracts';
12
8
  import type { Operator } from '@aztec/ethereum/deploy-aztec-l1-contracts';
13
9
  import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract';
14
10
  import { MultiAdderArtifact } from '@aztec/ethereum/l1-artifacts';
@@ -24,9 +20,8 @@ import { SpamContract } from '@aztec/noir-test-contracts.js/Spam';
24
20
  import type { BootstrapNode } from '@aztec/p2p/bootstrap';
25
21
  import { createBootstrapNodeFromPrivateKey, getBootstrapNodeEnr } from '@aztec/p2p/test-helpers';
26
22
  import { tryStop } from '@aztec/stdlib/interfaces/server';
27
- import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
28
23
  import { TopicType } from '@aztec/stdlib/p2p';
29
- import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
24
+ import type { GenesisData } from '@aztec/stdlib/world-state';
30
25
  import { ZkPassportProofParams } from '@aztec/stdlib/zkpassport';
31
26
  import { getGenesisValues } from '@aztec/world-state/testing';
32
27
 
@@ -34,10 +29,13 @@ import getPort from 'get-port';
34
29
  import { type GetContractReturnType, getAddress, getContract } from 'viem';
35
30
  import { privateKeyToAccount } from 'viem/accounts';
36
31
 
32
+ import {
33
+ SCHNORR_HARDCODED_PRIVATE_KEY,
34
+ SchnorrHardcodedKeyAccountContract,
35
+ } from '../fixtures/schnorr_hardcoded_account_contract.js';
37
36
  import {
38
37
  type EndToEndContext,
39
38
  type SetupOptions,
40
- deployAccounts,
41
39
  getPrivateKeyFromIndex,
42
40
  getSponsoredFPCAddress,
43
41
  setup,
@@ -76,8 +74,8 @@ export class P2PNetworkTest {
76
74
  public peerIdPrivateKeys: string[] = [];
77
75
  public validators: Operator[] = [];
78
76
 
79
- public deployedAccounts: InitialAccountData[] = [];
80
- public prefilledPublicData: PublicDataTreeLeaf[] = [];
77
+ public hardcodedAccountData!: InitialAccountData;
78
+ public genesis: GenesisData | undefined;
81
79
 
82
80
  // The re-execution test needs a wallet and a spam contract
83
81
  public wallet?: TestWallet;
@@ -124,12 +122,11 @@ export class P2PNetworkTest {
124
122
  initialValidatorConfig.aztecProofSubmissionEpochs ?? l1ContractsConfig.aztecProofSubmissionEpochs,
125
123
  slashingRoundSizeInEpochs:
126
124
  initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs,
127
- slasherFlavor: initialValidatorConfig.slasherFlavor ?? 'tally',
125
+ slasherEnabled: initialValidatorConfig.slasherEnabled ?? true,
128
126
  aztecTargetCommitteeSize: numberOfValidators,
129
127
  metricsPort: metricsPort,
130
128
  numberOfInitialFundedAccounts: 2,
131
129
  startProverNode,
132
- walletMinFeePadding: 2.0,
133
130
  };
134
131
 
135
132
  this.deployL1ContractsArgs = {
@@ -137,7 +134,7 @@ export class P2PNetworkTest {
137
134
  aztecEpochDuration: initialValidatorConfig.aztecEpochDuration ?? l1ContractsConfig.aztecEpochDuration,
138
135
  slashingRoundSizeInEpochs:
139
136
  initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs,
140
- slasherFlavor: initialValidatorConfig.slasherFlavor ?? 'tally',
137
+ slasherEnabled: initialValidatorConfig.slasherEnabled ?? true,
141
138
 
142
139
  ethereumSlotDuration: initialValidatorConfig.ethereumSlotDuration ?? l1ContractsConfig.ethereumSlotDuration,
143
140
  aztecSlotDuration: initialValidatorConfig.aztecSlotDuration ?? l1ContractsConfig.aztecSlotDuration,
@@ -192,10 +189,10 @@ export class P2PNetworkTest {
192
189
  }
193
190
 
194
191
  get fundedAccount() {
195
- if (!this.deployedAccounts[0]) {
196
- throw new Error('Call setupAccount to create a funded account.');
192
+ if (!this.hardcodedAccountData) {
193
+ throw new Error('Call setup to initialize the hardcoded account.');
197
194
  }
198
- return this.deployedAccounts[0];
195
+ return this.hardcodedAccountData;
199
196
  }
200
197
 
201
198
  async addBootstrapNode() {
@@ -303,17 +300,22 @@ export class P2PNetworkTest {
303
300
  await this._sendDummyTx(this.context.deployL1ContractsValues.l1Client);
304
301
  }
305
302
 
303
+ /** Points the wallet to a P2P-enabled node so transactions can propagate through the network. */
304
+ setupWalletOnNode(node: AztecNodeService) {
305
+ this.logger.info('Pointing wallet to a P2P-enabled node');
306
+ this.context.wallet.updateNode(node);
307
+ }
308
+
309
+ /** Registers the hardcoded account in PXE without on-chain deployment. No sequencer needed. */
306
310
  async setupAccount() {
307
- this.logger.info('Setting up account');
308
- const { deployedAccounts } = await deployAccounts(
309
- 1,
310
- this.logger,
311
- )({
312
- wallet: this.context.wallet,
313
- initialFundedAccounts: this.context.initialFundedAccounts,
311
+ this.logger.info('Registering hardcoded account (no deployment)');
312
+ const contract = new SchnorrHardcodedKeyAccountContract();
313
+ const accountManager = await (this.context.wallet as TestWallet).createAccount({
314
+ secret: this.hardcodedAccountData.secret,
315
+ salt: this.hardcodedAccountData.salt,
316
+ contract,
314
317
  });
315
- this.deployedAccounts = deployedAccounts;
316
- [{ address: this.defaultAccountAddress }] = deployedAccounts;
318
+ this.defaultAccountAddress = accountManager.address;
317
319
  this.wallet = this.context.wallet;
318
320
  }
319
321
 
@@ -354,13 +356,30 @@ export class P2PNetworkTest {
354
356
 
355
357
  async setup() {
356
358
  this.logger.info('Setting up subsystems from fresh');
359
+
360
+ // Pre-compute hardcoded account data so it gets funded in genesis.
361
+ const contract = new SchnorrHardcodedKeyAccountContract();
362
+ const secret = Fr.random();
363
+ const salt = Fr.random();
364
+ this.hardcodedAccountData = {
365
+ secret,
366
+ salt,
367
+ signingKey: SCHNORR_HARDCODED_PRIVATE_KEY,
368
+ address: await getAccountContractAddress(contract, secret, salt),
369
+ };
370
+
371
+ // Generate regular Schnorr accounts for tests that need deployable accounts (e.g. add_rollup).
372
+ const regularAccounts = await generateSchnorrAccounts(this.setupOptions.numberOfInitialFundedAccounts ?? 2);
373
+
357
374
  this.context = await setup(
358
375
  0,
359
376
  {
360
377
  ...this.setupOptions,
361
378
  fundSponsoredFPC: true,
362
379
  skipAccountDeployment: true,
363
- slasherFlavor: this.setupOptions.slasherFlavor ?? this.deployL1ContractsArgs.slasherFlavor ?? 'none',
380
+ skipInitialSequencer: true,
381
+ initialFundedAccounts: [...regularAccounts, this.hardcodedAccountData],
382
+ slasherEnabled: this.setupOptions.slasherEnabled ?? this.deployL1ContractsArgs.slasherEnabled ?? false,
364
383
  aztecTargetCommitteeSize: 0,
365
384
  l1ContractsArgs: this.deployL1ContractsArgs,
366
385
  },
@@ -372,8 +391,13 @@ export class P2PNetworkTest {
372
391
  const sponsoredFPCAddress = await getSponsoredFPCAddress();
373
392
  const initialFundedAccounts = [...this.context.initialFundedAccounts.map(a => a.address), sponsoredFPCAddress];
374
393
 
375
- const { prefilledPublicData } = await getGenesisValues(initialFundedAccounts);
376
- this.prefilledPublicData = prefilledPublicData;
394
+ const { genesis } = await getGenesisValues(
395
+ initialFundedAccounts,
396
+ undefined,
397
+ undefined,
398
+ this.context.genesis!.genesisTimestamp,
399
+ );
400
+ this.genesis = genesis;
377
401
 
378
402
  const rollupContract = RollupContract.getFromL1ContractsValues(this.context.deployL1ContractsValues);
379
403
  this.monitor = new ChainMonitor(rollupContract, this.context.dateProvider).start();
@@ -468,8 +492,7 @@ export class P2PNetworkTest {
468
492
  async getContracts(): Promise<{
469
493
  rollup: RollupContract;
470
494
  slasherContract: GetContractReturnType<typeof SlasherAbi, ViemClient>;
471
- slashingProposer: EmpireSlashingProposerContract | TallySlashingProposerContract | undefined;
472
- slashFactory: SlashFactoryContract;
495
+ slashingProposer: SlashingProposerContract | undefined;
473
496
  }> {
474
497
  if (!this.ctx.deployL1ContractsValues) {
475
498
  throw new Error('DeployAztecL1ContractsValues not set');
@@ -486,14 +509,9 @@ export class P2PNetworkTest {
486
509
  client: this.ctx.deployL1ContractsValues.l1Client,
487
510
  });
488
511
 
489
- // Get the actual slashing proposer from rollup (which handles both empire and tally)
512
+ // Get the actual slashing proposer from rollup
490
513
  const slashingProposer = await rollup.getSlashingProposer();
491
514
 
492
- const slashFactory = new SlashFactoryContract(
493
- this.ctx.deployL1ContractsValues.l1Client,
494
- getAddress(this.ctx.deployL1ContractsValues.l1ContractAddresses.slashFactoryAddress!.toString()),
495
- );
496
-
497
- return { rollup, slasherContract, slashingProposer, slashFactory };
515
+ return { rollup, slasherContract, slashingProposer };
498
516
  }
499
517
  }
@@ -91,7 +91,7 @@ export async function runReqrespTxTest(params: {
91
91
  t.bootstrapNodeEnr,
92
92
  NUM_VALIDATORS,
93
93
  BOOT_NODE_UDP_PORT,
94
- t.prefilledPublicData,
94
+ t.genesis,
95
95
  dataDir,
96
96
  shouldCollectMetrics(),
97
97
  );
@@ -194,8 +194,8 @@ export async function runReqrespTxTest(params: {
194
194
  // Wait for L1 checkpoint sync, which may lag behind P2P block propagation.
195
195
  const checkpoints = await retryUntil(
196
196
  async () => {
197
- const cps = await nodes[0].getCheckpoints(CheckpointNumber(1), 50);
198
- return cps.length > 0 && cps.some(cp => cp.checkpoint.blocks.length >= 2) ? cps : undefined;
197
+ const cps = await nodes[0].getCheckpoints(CheckpointNumber(1), 50, { includeBlocks: true });
198
+ return cps.length > 0 && cps.some(cp => (cp.blocks?.length ?? 0) >= 2) ? cps : undefined;
199
199
  },
200
200
  'waiting for multi-block checkpoint to sync from L1',
201
201
  30,
@@ -203,16 +203,17 @@ export async function runReqrespTxTest(params: {
203
203
  );
204
204
 
205
205
  let mbpsFound = false;
206
- let expectedBlockNumber = checkpoints[0].checkpoint.blocks[0].number;
206
+ let expectedBlockNumber = checkpoints[0].blocks![0].number;
207
207
 
208
208
  for (const published of checkpoints) {
209
- const blockCount = published.checkpoint.blocks.length;
209
+ const blocks = published.blocks!;
210
+ const blockCount = blocks.length;
210
211
  mbpsFound = mbpsFound || blockCount >= 2;
211
212
 
212
213
  for (let i = 0; i < blockCount; i++) {
213
- const block = published.checkpoint.blocks[i];
214
+ const block = blocks[i];
214
215
  expect(block.indexWithinCheckpoint).toBe(i);
215
- expect(block.checkpointNumber).toBe(published.checkpoint.number);
216
+ expect(block.checkpointNumber).toBe(published.number);
216
217
  expect(block.number).toBe(expectedBlockNumber);
217
218
  expectedBlockNumber++;
218
219
  }
@@ -7,11 +7,7 @@ import type { Logger } from '@aztec/aztec.js/log';
7
7
  import { TxHash } from '@aztec/aztec.js/tx';
8
8
  import type { RollupCheatCodes } from '@aztec/aztec/testing';
9
9
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
10
- import type {
11
- EmpireSlashingProposerContract,
12
- RollupContract,
13
- TallySlashingProposerContract,
14
- } from '@aztec/ethereum/contracts';
10
+ import type { RollupContract, SlashingProposerContract } from '@aztec/ethereum/contracts';
15
11
  import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
16
12
  import { timesAsync, unique } from '@aztec/foundation/collection';
17
13
  import { EthAddress } from '@aztec/foundation/eth-address';
@@ -22,8 +18,8 @@ import { TestContract, TestContractArtifact } from '@aztec/noir-test-contracts.j
22
18
  import { getPXEConfig, getPXEConfig as getRpcConfig } from '@aztec/pxe/server';
23
19
  import { getRoundForOffense } from '@aztec/slasher';
24
20
  import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
25
- import type { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
26
21
 
22
+ import { SchnorrHardcodedKeyAccountContract } from '../fixtures/schnorr_hardcoded_account_contract.js';
27
23
  import { submitTxsTo } from '../shared/submit-transactions.js';
28
24
  import { TestWallet } from '../test-wallet/test_wallet.js';
29
25
  import { type ProvenTx, proveInteraction } from '../test-wallet/utils.js';
@@ -60,10 +56,17 @@ export const submitTransactions = async (
60
56
  rpcConfig.proverEnabled = false;
61
57
  const wallet = await TestWallet.create(
62
58
  node,
63
- { ...getPXEConfig(), proverEnabled: false },
59
+ // Use checkpointed chain tip to avoid anchoring on provisional blocks that the archiver can prune
60
+ // when their slot ends without a checkpoint landing on L1.
61
+ { ...getPXEConfig(), proverEnabled: false, syncChainTip: 'checkpointed' },
64
62
  { loggerActorLabel: 'pxe-tx' },
65
63
  );
66
- const fundedAccountManager = await wallet.createSchnorrAccount(fundedAccount.secret, fundedAccount.salt);
64
+ const contract = new SchnorrHardcodedKeyAccountContract();
65
+ const fundedAccountManager = await wallet.createAccount({
66
+ secret: fundedAccount.secret,
67
+ salt: fundedAccount.salt,
68
+ contract,
69
+ });
67
70
  return submitTxsTo(wallet, fundedAccountManager.address, numTxs, logger);
68
71
  };
69
72
 
@@ -78,10 +81,15 @@ export async function prepareTransactions(
78
81
 
79
82
  const wallet = await TestWallet.create(
80
83
  node,
81
- { ...getPXEConfig(), proverEnabled: false },
84
+ { ...getPXEConfig(), proverEnabled: false, syncChainTip: 'checkpointed' },
82
85
  { loggerActorLabel: 'pxe-tx' },
83
86
  );
84
- const fundedAccountManager = await wallet.createSchnorrAccount(fundedAccount.secret, fundedAccount.salt);
87
+ const accountContract = new SchnorrHardcodedKeyAccountContract();
88
+ const fundedAccountManager = await wallet.createAccount({
89
+ secret: fundedAccount.secret,
90
+ salt: fundedAccount.salt,
91
+ contract: accountContract,
92
+ });
85
93
 
86
94
  const testContractInstance = await getContractInstanceFromInstantiationParams(TestContractArtifact, {
87
95
  salt: Fr.random(),
@@ -99,7 +107,7 @@ export async function prepareTransactions(
99
107
  }
100
108
 
101
109
  export function awaitProposalExecution(
102
- slashingProposer: EmpireSlashingProposerContract | TallySlashingProposerContract,
110
+ slashingProposer: SlashingProposerContract,
103
111
  timeoutSeconds: number,
104
112
  logger: Logger,
105
113
  ): Promise<bigint> {
@@ -109,24 +117,12 @@ export function awaitProposalExecution(
109
117
  reject(new Error(`Timeout waiting for proposal execution after ${timeoutSeconds}s`));
110
118
  }, timeoutSeconds * 1000);
111
119
 
112
- if (slashingProposer.type === 'empire') {
113
- const unwatch = slashingProposer.listenToPayloadSubmitted(args => {
114
- logger.warn(`Proposal ${args.payload} from round ${args.round} executed`);
115
- clearTimeout(timeout);
116
- unwatch();
117
- resolve(args.round);
118
- });
119
- } else if (slashingProposer.type === 'tally') {
120
- const unwatch = slashingProposer.listenToRoundExecuted(args => {
121
- logger.warn(`Slash from round ${args.round} executed`);
122
- clearTimeout(timeout);
123
- unwatch();
124
- resolve(args.round);
125
- });
126
- } else {
120
+ const unwatch = slashingProposer.listenToRoundExecuted(args => {
121
+ logger.warn(`Slash from round ${args.round} executed`);
127
122
  clearTimeout(timeout);
128
- reject(new Error(`Unknown slashing proposer type: ${(slashingProposer as any).type}`));
129
- }
123
+ unwatch();
124
+ resolve(args.round);
125
+ });
130
126
  });
131
127
  }
132
128
 
@@ -245,7 +241,6 @@ export async function awaitCommitteeKicked({
245
241
  rollup,
246
242
  cheatCodes,
247
243
  committee,
248
- slashFactory,
249
244
  slashingProposer,
250
245
  slashingRoundSize,
251
246
  aztecSlotDuration,
@@ -256,8 +251,7 @@ export async function awaitCommitteeKicked({
256
251
  rollup: RollupContract;
257
252
  cheatCodes: RollupCheatCodes;
258
253
  committee: readonly `0x${string}`[];
259
- slashFactory: SlashFactoryContract;
260
- slashingProposer: EmpireSlashingProposerContract | TallySlashingProposerContract | undefined;
254
+ slashingProposer: SlashingProposerContract | undefined;
261
255
  slashingRoundSize: number;
262
256
  aztecSlotDuration: number;
263
257
  aztecEpochDuration: number;
@@ -270,36 +264,14 @@ export async function awaitCommitteeKicked({
270
264
 
271
265
  await cheatCodes.debugRollup();
272
266
 
273
- if (slashingProposer.type === 'empire') {
274
- // Await for the slash payload to be created if empire (no payload is created on tally until execution time)
275
- const targetEpoch = EpochNumber((await cheatCodes.getEpoch()) + (await rollup.getLagInEpochsForValidatorSet()) + 1);
276
- logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
277
- await cheatCodes.advanceToEpoch(targetEpoch);
278
-
279
- const slashPayloadEvents = await retryUntil(
280
- async () => {
281
- const events = await slashFactory.getSlashPayloadCreatedEvents();
282
- return events.length > 0 ? events : undefined;
283
- },
284
- 'slash payload created',
285
- 120,
286
- 1,
287
- );
288
- expect(slashPayloadEvents.length).toBe(1);
289
- // The uniqueness check is needed since a validator may be slashed more than once on the same round (eg because they let two epochs be pruned)
290
- expect(unique(slashPayloadEvents[0].slashes.map(slash => slash.validator.toString()))).toHaveLength(
291
- committee.length,
292
- );
293
- } else {
294
- // Use the slash offset to ensure we are in the right epoch for tally
295
- const slashOffsetInRounds = await slashingProposer.getSlashOffsetInRounds();
296
- const slashingRoundSizeInEpochs = slashingRoundSize / aztecEpochDuration;
297
- const slashingOffsetInEpochs = Number(slashOffsetInRounds) * slashingRoundSizeInEpochs;
298
- const firstEpochInOffenseRound = offenseEpoch - (offenseEpoch % slashingRoundSizeInEpochs);
299
- const targetEpoch = firstEpochInOffenseRound + slashingOffsetInEpochs;
300
- logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
301
- await cheatCodes.advanceToEpoch(EpochNumber(targetEpoch), { offset: -aztecSlotDuration / 2 });
302
- }
267
+ // Use the slash offset to ensure we are in the right epoch for tally
268
+ const slashOffsetInRounds = await slashingProposer.getSlashOffsetInRounds();
269
+ const slashingRoundSizeInEpochs = slashingRoundSize / aztecEpochDuration;
270
+ const slashingOffsetInEpochs = Number(slashOffsetInRounds) * slashingRoundSizeInEpochs;
271
+ const firstEpochInOffenseRound = offenseEpoch - (offenseEpoch % slashingRoundSizeInEpochs);
272
+ const targetEpoch = firstEpochInOffenseRound + slashingOffsetInEpochs;
273
+ logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
274
+ await cheatCodes.advanceToEpoch(EpochNumber(targetEpoch), { offset: -aztecSlotDuration / 2 });
303
275
 
304
276
  const attestersPre = await rollup.getAttesters();
305
277
  expect(attestersPre.length).toBe(committee.length);
@@ -17,6 +17,10 @@ async function buildProxyCall(proxy: GenericProxyContract, action: ContractFunct
17
17
  return proxy.methods.forward_private_3(call.to, call.selector, call.args);
18
18
  } else if (argCount === 4) {
19
19
  return proxy.methods.forward_private_4(call.to, call.selector, call.args);
20
+ } else if (argCount === 5) {
21
+ return proxy.methods.forward_private_5(call.to, call.selector, call.args);
22
+ } else if (argCount === 6) {
23
+ return proxy.methods.forward_private_6(call.to, call.selector, call.args);
20
24
  }
21
25
  throw new Error(`No forward_private_${argCount} method on proxy`);
22
26
  }
@@ -223,8 +223,11 @@ export class FullProverTest {
223
223
 
224
224
  this.logger.verbose('Starting prover node');
225
225
  const sponsoredFPCAddress = await getSponsoredFPCAddress();
226
- const { prefilledPublicData } = await getGenesisValues(
226
+ const { genesis } = await getGenesisValues(
227
227
  this.context.initialFundedAccounts.map(a => a.address).concat(sponsoredFPCAddress),
228
+ undefined,
229
+ undefined,
230
+ this.context.genesis!.genesisTimestamp,
228
231
  );
229
232
 
230
233
  const proverNodeConfig: Parameters<typeof AztecNodeService.createAndSync>[0] = {
@@ -252,7 +255,7 @@ export class FullProverTest {
252
255
  this.proverAztecNode = await AztecNodeService.createAndSync(
253
256
  proverNodeConfig,
254
257
  { dateProvider: this.context.dateProvider, p2pClientDeps: { rpcTxProviders: [this.aztecNode] } },
255
- { prefilledPublicData },
258
+ { genesis },
256
259
  );
257
260
  this.logger.warn(`Proofs are now enabled`, { realProofs: this.realProofs });
258
261
  return this;
@@ -1,5 +1,27 @@
1
+ import type { AztecNode } from '@aztec/aztec.js/node';
2
+ import type { GasFees } from '@aztec/stdlib/gas';
3
+
1
4
  export const METRICS_PORT = 4318;
2
5
 
6
+ /** Default fee padding applied to predicted min fees in e2e tests. */
7
+ export const DEFAULT_MIN_FEE_PADDING = 5;
8
+
9
+ /**
10
+ * Large fee padding for txs that may be mined significantly later than when they were created,
11
+ * such as cloned txs in throughput/capacity benchmarks, where fees may spike between creation and mining.
12
+ */
13
+ export const LARGE_MIN_FEE_PADDING = 15;
14
+
15
+ /** Returns worst-case predicted min fees with padding applied, mirroring the BaseWallet pattern. */
16
+ export async function getPaddedMaxFeesPerGas(node: AztecNode, padding = DEFAULT_MIN_FEE_PADDING): Promise<GasFees> {
17
+ const predicted = await node.getPredictedMinFees();
18
+ const worstCase =
19
+ predicted.length > 0
20
+ ? predicted.reduce((worst, fees) => (fees.feePerL2Gas > worst.feePerL2Gas ? fees : worst))
21
+ : await node.getCurrentMinFees();
22
+ return worstCase.mul(1 + padding);
23
+ }
24
+
3
25
  export const shouldCollectMetrics = () => {
4
26
  if (process.env.COLLECT_METRICS) {
5
27
  return METRICS_PORT;
@@ -11,7 +11,7 @@ import { privateKeyToAccount } from 'viem/accounts';
11
11
  */
12
12
  export interface HADatabaseConfig {
13
13
  /** PostgreSQL connection URL */
14
- databaseUrl: string;
14
+ databaseUrl: SecretValue<string>;
15
15
  /** Node ID for HA coordination */
16
16
  nodeId: string;
17
17
  /** Enable HA signing */
@@ -28,7 +28,9 @@ export interface HADatabaseConfig {
28
28
  * Get database configuration from environment variables
29
29
  */
30
30
  export function createHADatabaseConfig(nodeId: string): HADatabaseConfig {
31
- const databaseUrl = process.env.DATABASE_URL || 'postgresql://aztec:aztec@localhost:5432/aztec_ha_test';
31
+ const databaseUrl = new SecretValue(
32
+ process.env.DATABASE_URL || 'postgresql://aztec:aztec@localhost:5432/aztec_ha_test',
33
+ );
32
34
 
33
35
  return {
34
36
  databaseUrl,