@aztec/end-to-end 0.0.1-commit.2ed92850 → 0.0.1-commit.3d8f95d

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 (90) hide show
  1. package/dest/bench/client_flows/config.d.ts +2 -2
  2. package/dest/bench/client_flows/config.d.ts.map +1 -1
  3. package/dest/bench/client_flows/config.js +18 -0
  4. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +1 -1
  5. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  6. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +3 -2
  7. package/dest/e2e_epochs/epochs_test.d.ts +7 -1
  8. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  9. package/dest/e2e_epochs/epochs_test.js +37 -12
  10. package/dest/e2e_l1_publisher/write_json.d.ts +3 -2
  11. package/dest/e2e_l1_publisher/write_json.d.ts.map +1 -1
  12. package/dest/e2e_l1_publisher/write_json.js +1 -7
  13. package/dest/e2e_p2p/reqresp/utils.d.ts +22 -0
  14. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -0
  15. package/dest/e2e_p2p/reqresp/utils.js +153 -0
  16. package/dest/e2e_p2p/shared.d.ts +1 -1
  17. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  18. package/dest/e2e_p2p/shared.js +5 -2
  19. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts +2 -0
  20. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts.map +1 -0
  21. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.js +184 -0
  22. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts +18 -0
  23. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts.map +1 -0
  24. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.js +120 -0
  25. package/dest/fixtures/e2e_prover_test.js +1 -1
  26. package/dest/fixtures/ha_setup.d.ts +71 -0
  27. package/dest/fixtures/ha_setup.d.ts.map +1 -0
  28. package/dest/fixtures/ha_setup.js +114 -0
  29. package/dest/fixtures/index.d.ts +2 -1
  30. package/dest/fixtures/index.d.ts.map +1 -1
  31. package/dest/fixtures/index.js +1 -0
  32. package/dest/fixtures/setup.d.ts +15 -15
  33. package/dest/fixtures/setup.d.ts.map +1 -1
  34. package/dest/fixtures/setup.js +30 -90
  35. package/dest/fixtures/setup_p2p_test.d.ts +12 -8
  36. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  37. package/dest/fixtures/setup_p2p_test.js +29 -21
  38. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  39. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  40. package/dest/shared/uniswap_l1_l2.js +8 -6
  41. package/dest/spartan/tx_metrics.d.ts +35 -1
  42. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  43. package/dest/spartan/tx_metrics.js +150 -0
  44. package/dest/spartan/utils/config.d.ts +4 -1
  45. package/dest/spartan/utils/config.d.ts.map +1 -1
  46. package/dest/spartan/utils/config.js +2 -1
  47. package/dest/spartan/utils/index.d.ts +4 -4
  48. package/dest/spartan/utils/index.d.ts.map +1 -1
  49. package/dest/spartan/utils/index.js +2 -2
  50. package/dest/spartan/utils/k8s.d.ts +29 -1
  51. package/dest/spartan/utils/k8s.d.ts.map +1 -1
  52. package/dest/spartan/utils/k8s.js +118 -0
  53. package/dest/spartan/utils/nodes.d.ts +11 -1
  54. package/dest/spartan/utils/nodes.d.ts.map +1 -1
  55. package/dest/spartan/utils/nodes.js +198 -27
  56. package/dest/spartan/utils/scripts.d.ts +18 -4
  57. package/dest/spartan/utils/scripts.d.ts.map +1 -1
  58. package/dest/spartan/utils/scripts.js +19 -4
  59. package/package.json +42 -39
  60. package/src/bench/client_flows/client_flows_benchmark.ts +5 -5
  61. package/src/bench/client_flows/config.ts +9 -1
  62. package/src/bench/utils.ts +1 -1
  63. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +1 -1
  64. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +6 -7
  65. package/src/e2e_deploy_contract/deploy_test.ts +2 -2
  66. package/src/e2e_epochs/epochs_test.ts +44 -13
  67. package/src/e2e_fees/fees_test.ts +6 -6
  68. package/src/e2e_l1_publisher/write_json.ts +1 -6
  69. package/src/e2e_nested_contract/nested_contract_test.ts +1 -1
  70. package/src/e2e_p2p/inactivity_slash_test.ts +4 -4
  71. package/src/e2e_p2p/p2p_network.ts +4 -4
  72. package/src/e2e_p2p/reqresp/utils.ts +207 -0
  73. package/src/e2e_p2p/shared.ts +11 -2
  74. package/src/e2e_storage_proof/fixtures/storage_proof.json +915 -0
  75. package/src/e2e_storage_proof/fixtures/storage_proof_fetcher.ts +190 -0
  76. package/src/e2e_storage_proof/fixtures/storage_proof_fixture.ts +173 -0
  77. package/src/e2e_token_contract/token_contract_test.ts +1 -1
  78. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  79. package/src/fixtures/e2e_prover_test.ts +4 -4
  80. package/src/fixtures/ha_setup.ts +184 -0
  81. package/src/fixtures/index.ts +1 -0
  82. package/src/fixtures/setup.ts +33 -118
  83. package/src/fixtures/setup_p2p_test.ts +31 -27
  84. package/src/shared/uniswap_l1_l2.ts +8 -10
  85. package/src/spartan/tx_metrics.ts +126 -0
  86. package/src/spartan/utils/config.ts +1 -0
  87. package/src/spartan/utils/index.ts +3 -1
  88. package/src/spartan/utils/k8s.ts +152 -0
  89. package/src/spartan/utils/nodes.ts +239 -24
  90. package/src/spartan/utils/scripts.ts +43 -7
@@ -0,0 +1,184 @@
1
+ import { EthAddress } from '@aztec/aztec.js/addresses';
2
+ import { Fr } from '@aztec/aztec.js/fields';
3
+ import type { Logger } from '@aztec/aztec.js/log';
4
+ import { SecretValue } from '@aztec/foundation/config';
5
+
6
+ import { Pool } from 'pg';
7
+ import { privateKeyToAccount } from 'viem/accounts';
8
+
9
+ /**
10
+ * Configuration for HA database connection
11
+ */
12
+ export interface HADatabaseConfig {
13
+ /** PostgreSQL connection URL */
14
+ databaseUrl: string;
15
+ /** Node ID for HA coordination */
16
+ nodeId: string;
17
+ /** Enable HA signing */
18
+ haSigningEnabled: boolean;
19
+ /** Polling interval in ms */
20
+ pollingIntervalMs: number;
21
+ /** Signing timeout in ms */
22
+ signingTimeoutMs: number;
23
+ /** Max stuck duties age in ms */
24
+ maxStuckDutiesAgeMs: number;
25
+ }
26
+
27
+ /**
28
+ * Get database configuration from environment variables
29
+ */
30
+ export function createHADatabaseConfig(nodeId: string): HADatabaseConfig {
31
+ const databaseUrl = process.env.DATABASE_URL || 'postgresql://aztec:aztec@localhost:5432/aztec_ha_test';
32
+
33
+ return {
34
+ databaseUrl,
35
+ nodeId,
36
+ haSigningEnabled: true,
37
+ pollingIntervalMs: 100,
38
+ signingTimeoutMs: 3000,
39
+ maxStuckDutiesAgeMs: 72000,
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Setup PostgreSQL database connection pool for HA tests
45
+ *
46
+ * Note: Database migrations should be run separately before starting tests,
47
+ * either via docker-compose entrypoint or manually with: aztec migrate-ha-db up
48
+ */
49
+ export function setupHADatabase(databaseUrl: string, logger?: Logger): Pool {
50
+ try {
51
+ // Create connection pool for test usage
52
+ // Migrations are already run by docker-compose entrypoint before tests start
53
+ const pool = new Pool({ connectionString: databaseUrl });
54
+
55
+ logger?.info('Connected to HA database (migrations should already be applied)');
56
+
57
+ return pool;
58
+ } catch (error) {
59
+ logger?.error(`Failed to connect to HA database: ${error}`);
60
+ throw error;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Clean up HA database - drop all tables
66
+ * Use this between tests to ensure clean state
67
+ */
68
+ export async function cleanupHADatabase(pool: Pool, logger?: Logger): Promise<void> {
69
+ try {
70
+ // Drop all HA tables
71
+ await pool.query('DROP TABLE IF EXISTS validator_duties CASCADE');
72
+ await pool.query('DROP TABLE IF EXISTS slashing_protection CASCADE');
73
+ await pool.query('DROP TABLE IF EXISTS schema_version CASCADE');
74
+
75
+ logger?.info('HA database cleaned up successfully');
76
+ } catch (error) {
77
+ logger?.error(`Failed to cleanup HA database: ${error}`);
78
+ throw error;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Query validator duties from the database
84
+ */
85
+ export async function getValidatorDuties(
86
+ pool: Pool,
87
+ slot: bigint,
88
+ dutyType?: 'ATTESTATION' | 'BLOCK_PROPOSAL' | 'GOVERNANCE_VOTE' | 'SLASHING_VOTE',
89
+ ): Promise<
90
+ Array<{
91
+ slot: string;
92
+ dutyType: string;
93
+ validatorAddress: string;
94
+ nodeId: string;
95
+ startedAt: Date;
96
+ completedAt: Date | undefined;
97
+ }>
98
+ > {
99
+ const query = dutyType
100
+ ? 'SELECT slot, duty_type, validator_address, node_id, started_at, completed_at FROM validator_duties WHERE slot = $1 AND duty_type = $2 ORDER BY started_at'
101
+ : 'SELECT slot, duty_type, validator_address, node_id, started_at, completed_at FROM validator_duties WHERE slot = $1 ORDER BY started_at';
102
+
103
+ const params = dutyType ? [slot.toString(), dutyType] : [slot.toString()];
104
+
105
+ const result = await pool.query<{
106
+ slot: string;
107
+ duty_type: string;
108
+ validator_address: string;
109
+ node_id: string;
110
+ started_at: Date;
111
+ completed_at: Date | undefined;
112
+ }>(query, params);
113
+
114
+ return result.rows.map(row => ({
115
+ slot: row.slot,
116
+ dutyType: row.duty_type,
117
+ validatorAddress: row.validator_address,
118
+ nodeId: row.node_id,
119
+ startedAt: row.started_at,
120
+ completedAt: row.completed_at,
121
+ }));
122
+ }
123
+
124
+ /**
125
+ * Convert private keys to Ethereum addresses
126
+ */
127
+ export function getAddressesFromPrivateKeys(privateKeys: `0x${string}`[]): string[] {
128
+ return privateKeys.map(pk => {
129
+ const account = privateKeyToAccount(pk);
130
+ return account.address;
131
+ });
132
+ }
133
+
134
+ /**
135
+ * Create initial validators from private keys for L1 contract deployment
136
+ */
137
+ export function createInitialValidatorsFromPrivateKeys(attesterPrivateKeys: `0x${string}`[]): Array<{
138
+ attester: EthAddress;
139
+ withdrawer: EthAddress;
140
+ privateKey: `0x${string}`;
141
+ bn254SecretKey: SecretValue<bigint>;
142
+ }> {
143
+ return attesterPrivateKeys.map(pk => {
144
+ const account = privateKeyToAccount(pk);
145
+ return {
146
+ attester: EthAddress.fromString(account.address),
147
+ withdrawer: EthAddress.fromString(account.address),
148
+ privateKey: pk,
149
+ bn254SecretKey: new SecretValue(Fr.random().toBigInt()),
150
+ };
151
+ });
152
+ }
153
+
154
+ /**
155
+ * Verify no duplicate attestations per validator (HA coordination check)
156
+ * Groups duties by validator address and verifies each validator attested exactly once
157
+ */
158
+ export function verifyNoDuplicateAttestations(
159
+ attestationDuties: Array<{
160
+ validatorAddress: string;
161
+ nodeId: string;
162
+ completedAt: Date | undefined;
163
+ }>,
164
+ logger?: Logger,
165
+ ): Map<string, typeof attestationDuties> {
166
+ const dutiesByValidator = new Map<string, typeof attestationDuties>();
167
+ for (const duty of attestationDuties) {
168
+ const existing = dutiesByValidator.get(duty.validatorAddress) || [];
169
+ existing.push(duty);
170
+ dutiesByValidator.set(duty.validatorAddress, existing);
171
+ }
172
+
173
+ for (const [validatorAddress, validatorDuties] of dutiesByValidator.entries()) {
174
+ if (validatorDuties.length !== 1) {
175
+ throw new Error(`Validator ${validatorAddress} attested ${validatorDuties.length} times (expected exactly once)`);
176
+ }
177
+ if (!validatorDuties[0].completedAt) {
178
+ throw new Error(`Validator ${validatorAddress} attestation duty not completed`);
179
+ }
180
+ logger?.info(`Validator ${validatorAddress} attested once via node ${validatorDuties[0].nodeId}`);
181
+ }
182
+
183
+ return dutiesByValidator;
184
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './fixtures.js';
2
+ export * from './ha_setup.js';
2
3
  export * from './logging.js';
3
4
  export * from './utils.js';
4
5
  export * from './token_utils.js';
@@ -1,5 +1,5 @@
1
1
  import { SchnorrAccountContractArtifact } from '@aztec/accounts/schnorr';
2
- import { type InitialAccountData, generateSchnorrAccounts, getInitialTestAccountsData } from '@aztec/accounts/testing';
2
+ import { type InitialAccountData, generateSchnorrAccounts } from '@aztec/accounts/testing';
3
3
  import { type Archiver, createArchiver } from '@aztec/archiver';
4
4
  import { type AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node';
5
5
  import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
@@ -13,7 +13,7 @@ import {
13
13
  import { publishContractClass, publishInstance } from '@aztec/aztec.js/deployment';
14
14
  import { Fr } from '@aztec/aztec.js/fields';
15
15
  import { type Logger, createLogger } from '@aztec/aztec.js/log';
16
- import { type AztecNode, createAztecNodeClient, waitForNode } from '@aztec/aztec.js/node';
16
+ import type { AztecNode } from '@aztec/aztec.js/node';
17
17
  import type { Wallet } from '@aztec/aztec.js/wallet';
18
18
  import { AnvilTestWatcher, CheatCodes } from '@aztec/aztec/testing';
19
19
  import { createBlobClientWithFileStores } from '@aztec/blob-client/client';
@@ -41,7 +41,7 @@ import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
41
41
  import { SecretValue } from '@aztec/foundation/config';
42
42
  import { randomBytes } from '@aztec/foundation/crypto/random';
43
43
  import { tryRmDir } from '@aztec/foundation/fs';
44
- import { withLogNameSuffix } from '@aztec/foundation/log';
44
+ import { withLoggerBindings } from '@aztec/foundation/log/server';
45
45
  import { retryUntil } from '@aztec/foundation/retry';
46
46
  import { sleep } from '@aztec/foundation/sleep';
47
47
  import { DateProvider, TestDateProvider } from '@aztec/foundation/timer';
@@ -92,9 +92,6 @@ import { getEndToEndTestTelemetryClient } from './with_telemetry_utils.js';
92
92
 
93
93
  export { startAnvil };
94
94
 
95
- const { AZTEC_NODE_URL = '' } = process.env;
96
- const getAztecUrl = () => AZTEC_NODE_URL;
97
-
98
95
  let telemetry: TelemetryClient | undefined = undefined;
99
96
  async function getTelemetryClient(partialConfig: Partial<TelemetryClientConfig> & { benchmark?: boolean } = {}) {
100
97
  if (!telemetry) {
@@ -125,14 +122,14 @@ export async function setupSharedBlobStorage(config: { dataDirectory?: string }
125
122
  * @param aztecNode - An instance of Aztec Node.
126
123
  * @param opts - Partial configuration for the PXE.
127
124
  * @param logger - The logger to be used.
128
- * @param useLogSuffix - Whether to add a randomly generated suffix to the PXE debug logs.
125
+ * @param actor - Actor label to include in log output (e.g., 'pxe-test').
129
126
  * @returns A test wallet, logger and teardown function.
130
127
  */
131
128
  export async function setupPXEAndGetWallet(
132
129
  aztecNode: AztecNode,
133
130
  opts: Partial<PXEConfig> = {},
134
131
  logger = getLogger(),
135
- useLogSuffix = false,
132
+ actor?: string,
136
133
  ): Promise<{
137
134
  wallet: TestWallet;
138
135
  logger: Logger;
@@ -150,9 +147,7 @@ export async function setupPXEAndGetWallet(
150
147
 
151
148
  const teardown = configuredDataDirectory ? () => Promise.resolve() : () => tryRmDir(PXEConfig.dataDirectory!);
152
149
 
153
- const wallet = await TestWallet.create(aztecNode, PXEConfig, {
154
- useLogSuffix,
155
- });
150
+ const wallet = await TestWallet.create(aztecNode, PXEConfig, { loggerActorLabel: actor });
156
151
 
157
152
  return {
158
153
  wallet,
@@ -219,13 +214,13 @@ export type EndToEndContext = {
219
214
  anvil: Anvil | undefined;
220
215
  /** The Aztec Node service or client a connected to it. */
221
216
  aztecNode: AztecNode;
222
- /** The Aztec Node as a service (only set if running locally). */
223
- aztecNodeService: AztecNodeService | undefined;
224
- /** Client to the Aztec Node admin interface (undefined if connected to remote environment) */
225
- aztecNodeAdmin: AztecNodeAdmin | undefined;
217
+ /** The Aztec Node as a service. */
218
+ aztecNodeService: AztecNodeService;
219
+ /** Client to the Aztec Node admin interface. */
220
+ aztecNodeAdmin: AztecNodeAdmin;
226
221
  /** The prover node service (only set if startProverNode is true) */
227
222
  proverNode: ProverNode | undefined;
228
- /** A client to the sequencer service (undefined if connected to remote environment) */
223
+ /** A client to the sequencer service. */
229
224
  sequencer: SequencerClient | undefined;
230
225
  /** Return values from deployAztecL1Contracts function. */
231
226
  deployL1ContractsValues: DeployAztecL1ContractsReturnType;
@@ -245,12 +240,12 @@ export type EndToEndContext = {
245
240
  cheatCodes: CheatCodes;
246
241
  /** The cheat codes for L1 */
247
242
  ethCheatCodes: EthCheatCodes;
248
- /** The anvil test watcher (undefined if connected to remote environment) */
249
- watcher: AnvilTestWatcher | undefined;
250
- /** Allows tweaking current system time, used by the epoch cache only (undefined if connected to remote environment) */
251
- dateProvider: TestDateProvider | undefined;
243
+ /** The anvil test watcher. */
244
+ watcher: AnvilTestWatcher;
245
+ /** Allows tweaking current system time, used by the epoch cache only. */
246
+ dateProvider: TestDateProvider;
252
247
  /** Telemetry client */
253
- telemetryClient: TelemetryClient | undefined;
248
+ telemetryClient: TelemetryClient;
254
249
  /** Mock gossip sub network used for gossipping messages (only if mockGossipSubNetwork was set to true in opts) */
255
250
  mockGossipSubNetwork: MockGossipSubNetwork | undefined;
256
251
  /** Prefilled public data used for setting up nodes. */
@@ -260,87 +255,11 @@ export type EndToEndContext = {
260
255
  /** BB config (only set if running locally). */
261
256
  bbConfig: Awaited<ReturnType<typeof getBBConfig>>;
262
257
  /** Directory to cleanup on teardown. */
263
- directoryToCleanup: string | undefined;
258
+ directoryToCleanup: string;
264
259
  /** Function to stop the started services. */
265
260
  teardown: () => Promise<void>;
266
261
  };
267
262
 
268
- /**
269
- * Function to setup the test against a remote deployment. It is assumed that L1 contract are already deployed
270
- */
271
- async function setupWithRemoteEnvironment(
272
- account: HDAccount | PrivateKeyAccount,
273
- config: AztecNodeConfig & SetupOptions,
274
- logger: Logger,
275
- numberOfAccounts: number,
276
- ): Promise<EndToEndContext> {
277
- const aztecNodeUrl = getAztecUrl();
278
- logger.verbose(`Creating Aztec Node client to remote host ${aztecNodeUrl}`);
279
- const aztecNode = createAztecNodeClient(aztecNodeUrl);
280
- await waitForNode(aztecNode, logger);
281
- logger.verbose('JSON RPC client connected to Aztec Node');
282
- logger.verbose(`Retrieving contract addresses from ${aztecNodeUrl}`);
283
- const { l1ContractAddresses, rollupVersion } = await aztecNode.getNodeInfo();
284
-
285
- const l1Client = createExtendedL1Client(config.l1RpcUrls, account, foundry);
286
-
287
- const deployL1ContractsValues: DeployAztecL1ContractsReturnType = {
288
- l1ContractAddresses,
289
- l1Client,
290
- rollupVersion,
291
- };
292
- const ethCheatCodes = new EthCheatCodes(config.l1RpcUrls, new DateProvider());
293
- const wallet = await TestWallet.create(aztecNode);
294
-
295
- if (config.walletMinFeePadding !== undefined) {
296
- wallet.setMinFeePadding(config.walletMinFeePadding);
297
- }
298
-
299
- const cheatCodes = await CheatCodes.create(config.l1RpcUrls, aztecNode, new DateProvider());
300
- const teardown = () => Promise.resolve();
301
-
302
- logger.verbose('Populating wallet from already registered accounts...');
303
- const initialFundedAccounts = await getInitialTestAccountsData();
304
-
305
- if (initialFundedAccounts.length < numberOfAccounts) {
306
- throw new Error(`Required ${numberOfAccounts} accounts. Found ${initialFundedAccounts.length}.`);
307
- }
308
-
309
- const testAccounts = await Promise.all(
310
- initialFundedAccounts.slice(0, numberOfAccounts).map(async account => {
311
- const accountManager = await wallet.createSchnorrAccount(account.secret, account.salt, account.signingKey);
312
- return accountManager.address;
313
- }),
314
- );
315
-
316
- return {
317
- anvil: undefined,
318
- aztecNode,
319
- aztecNodeService: undefined,
320
- aztecNodeAdmin: undefined,
321
- sequencer: undefined,
322
- proverNode: undefined,
323
- deployL1ContractsValues,
324
- config,
325
- aztecNodeConfig: config,
326
- initialFundedAccounts,
327
- wallet,
328
- accounts: testAccounts,
329
- logger,
330
- cheatCodes,
331
- ethCheatCodes,
332
- prefilledPublicData: undefined,
333
- mockGossipSubNetwork: undefined,
334
- watcher: undefined,
335
- dateProvider: undefined,
336
- telemetryClient: undefined,
337
- acvmConfig: undefined,
338
- bbConfig: undefined,
339
- directoryToCleanup: undefined,
340
- teardown,
341
- };
342
- }
343
-
344
263
  /**
345
264
  * Sets up the environment for the end-to-end tests.
346
265
  * @param numberOfAccounts - The number of new accounts to be created once the PXE is initiated.
@@ -383,16 +302,10 @@ export async function setup(
383
302
  if (!isAnvilTestChain(chain.id)) {
384
303
  throw new Error(`No ETHEREUM_HOSTS set but non anvil chain requested`);
385
304
  }
386
- if (AZTEC_NODE_URL) {
387
- throw new Error(
388
- `AZTEC_NODE_URL provided but no ETHEREUM_HOSTS set. Refusing to run, please set both variables so tests can deploy L1 contracts to the same Anvil instance`,
389
- );
390
- }
391
-
392
305
  const res = await startAnvil({
393
306
  l1BlockTime: opts.ethereumSlotDuration,
394
307
  accounts: opts.anvilAccounts,
395
- port: opts.anvilPort,
308
+ port: opts.anvilPort ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : undefined),
396
309
  });
397
310
  anvil = res.anvil;
398
311
  config.l1RpcUrls = [res.rpcUrl];
@@ -443,11 +356,6 @@ export async function setup(
443
356
  config.coinbase = EthAddress.fromString(publisherHdAccount.address);
444
357
  }
445
358
 
446
- if (AZTEC_NODE_URL) {
447
- // we are setting up against a remote environment, l1 contracts are assumed to already be deployed
448
- return await setupWithRemoteEnvironment(publisherHdAccount!, config, logger, numberOfAccounts);
449
- }
450
-
451
359
  // Determine which addresses to fund in genesis
452
360
  const initialFundedAccounts =
453
361
  opts.initialFundedAccounts ??
@@ -574,10 +482,12 @@ export async function setup(
574
482
  }
575
483
  }
576
484
 
577
- const aztecNodeService = await AztecNodeService.createAndSync(
578
- config,
579
- { dateProvider, telemetry: telemetryClient, p2pClientDeps, logger: createLogger('node:MAIN-aztec-node') },
580
- { prefilledPublicData },
485
+ const aztecNodeService = await withLoggerBindings({ actor: 'node-0' }, () =>
486
+ AztecNodeService.createAndSync(
487
+ config,
488
+ { dateProvider, telemetry: telemetryClient, p2pClientDeps },
489
+ { prefilledPublicData },
490
+ ),
581
491
  );
582
492
  const sequencerClient = aztecNodeService.getSequencer();
583
493
 
@@ -595,7 +505,7 @@ export async function setup(
595
505
  const proverNodeConfig = {
596
506
  ...config.proverNodeConfig,
597
507
  dataDirectory: proverNodeDataDirectory,
598
- p2pEnabled: false,
508
+ p2pEnabled: !!mockGossipSubNetwork,
599
509
  };
600
510
  proverNode = await createAndSyncProverNode(
601
511
  proverNodePrivateKeyHex,
@@ -603,6 +513,11 @@ export async function setup(
603
513
  proverNodeConfig,
604
514
  aztecNodeService,
605
515
  prefilledPublicData,
516
+ {
517
+ p2pClientDeps: mockGossipSubNetwork
518
+ ? { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) }
519
+ : undefined,
520
+ },
606
521
  );
607
522
  }
608
523
 
@@ -611,7 +526,7 @@ export async function setup(
611
526
  pxeConfig.dataDirectory = path.join(directoryToCleanup, randomBytes(8).toString('hex'));
612
527
  // For tests we only want proving enabled if specifically requested
613
528
  pxeConfig.proverEnabled = !!pxeOpts.proverEnabled;
614
- const wallet = await TestWallet.create(aztecNodeService, pxeConfig);
529
+ const wallet = await TestWallet.create(aztecNodeService, pxeConfig, { loggerActorLabel: 'pxe-0' });
615
530
 
616
531
  if (opts.walletMinFeePadding !== undefined) {
617
532
  wallet.setMinFeePadding(opts.walletMinFeePadding);
@@ -683,7 +598,7 @@ export async function setup(
683
598
  logger.error(`Error during e2e test teardown`, err);
684
599
  } finally {
685
600
  try {
686
- await telemetryClient?.stop();
601
+ await telemetryClient.stop();
687
602
  } catch (err) {
688
603
  logger.error(`Error during telemetry client stop`, err);
689
604
  }
@@ -797,7 +712,7 @@ export function createAndSyncProverNode(
797
712
  prefilledPublicData: PublicDataTreeLeaf[] = [],
798
713
  proverNodeDeps: ProverNodeDeps = {},
799
714
  ) {
800
- return withLogNameSuffix('prover-node', async () => {
715
+ return withLoggerBindings({ actor: 'prover-0' }, async () => {
801
716
  const aztecNodeTxProvider = aztecNode && {
802
717
  getTxByHash: aztecNode.getTxByHash.bind(aztecNode),
803
718
  getTxsByHash: aztecNode.getTxsByHash.bind(aztecNode),
@@ -4,14 +4,13 @@
4
4
  import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
5
5
  import { range } from '@aztec/foundation/array';
6
6
  import { SecretValue } from '@aztec/foundation/config';
7
- import { addLogNameHandler, removeLogNameHandler } from '@aztec/foundation/log';
7
+ import { withLoggerBindings } from '@aztec/foundation/log/server';
8
8
  import { bufferToHex } from '@aztec/foundation/string';
9
9
  import type { DateProvider } from '@aztec/foundation/timer';
10
10
  import type { ProverNodeConfig, ProverNodeDeps } from '@aztec/prover-node';
11
11
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
12
12
 
13
13
  import getPort from 'get-port';
14
- import { AsyncLocalStorage } from 'node:async_hooks';
15
14
 
16
15
  import { TEST_PEER_CHECK_INTERVAL_MS } from './fixtures.js';
17
16
  import { createAndSyncProverNode, getPrivateKeyFromIndex } from './utils.js';
@@ -22,6 +21,11 @@ import { getEndToEndTestTelemetryClient } from './with_telemetry_utils.js';
22
21
  // to avoid running validators with the same key
23
22
  export const ATTESTER_PRIVATE_KEYS_START_INDEX = 3;
24
23
 
24
+ // Global counters for actor naming (start at 1)
25
+ let validatorCounter = 1;
26
+ let nodeCounter = 1;
27
+ let proverCounter = 1;
28
+
25
29
  export function generatePrivateKeys(startIndex: number, numberOfKeys: number): `0x${string}`[] {
26
30
  const privateKeys: `0x${string}`[] = [];
27
31
  // Do not start from 0 as it is used during setup
@@ -44,10 +48,6 @@ export async function createNodes(
44
48
  validatorsPerNode = 1,
45
49
  ): Promise<AztecNodeService[]> {
46
50
  const nodePromises: Promise<AztecNodeService>[] = [];
47
- const loggerIdStorage = new AsyncLocalStorage<string>();
48
- const logNameHandler = (module: string) =>
49
- loggerIdStorage.getStore() ? `${module}:${loggerIdStorage.getStore()}` : module;
50
- addLogNameHandler(logNameHandler);
51
51
 
52
52
  for (let i = 0; i < numNodes; i++) {
53
53
  const index = indexOffset + i;
@@ -69,7 +69,6 @@ export async function createNodes(
69
69
  prefilledPublicData,
70
70
  dataDir,
71
71
  metricsPort,
72
- loggerIdStorage,
73
72
  );
74
73
  nodePromises.push(nodePromise);
75
74
  }
@@ -81,13 +80,20 @@ export async function createNodes(
81
80
  throw new Error('Sequencer not found');
82
81
  }
83
82
 
84
- removeLogNameHandler(logNameHandler);
85
83
  return nodes;
86
84
  }
87
85
 
88
- /** Creates a P2P enabled instance of Aztec Node Service with a validator */
86
+ /** Extended config type for createNode with test-specific overrides. */
87
+ export type CreateNodeConfig = AztecNodeConfig & {
88
+ /** Whether to skip starting the sequencer. */
89
+ dontStartSequencer?: boolean;
90
+ /** Override the private key (instead of deriving from addressIndex). */
91
+ validatorPrivateKey?: `0x${string}`;
92
+ };
93
+
94
+ /** Creates a P2P enabled instance of Aztec Node Service with a validator. */
89
95
  export async function createNode(
90
- config: AztecNodeConfig & { dontStartSequencer?: boolean },
96
+ config: CreateNodeConfig,
91
97
  dateProvider: DateProvider,
92
98
  tcpPort: number,
93
99
  bootstrapNode: string | undefined,
@@ -95,9 +101,9 @@ export async function createNode(
95
101
  prefilledPublicData?: PublicDataTreeLeaf[],
96
102
  dataDirectory?: string,
97
103
  metricsPort?: number,
98
- loggerIdStorage?: AsyncLocalStorage<string>,
99
104
  ) {
100
- const createNode = async () => {
105
+ const actorIndex = validatorCounter++;
106
+ return await withLoggerBindings({ actor: `validator-${actorIndex}` }, async () => {
101
107
  const validatorConfig = await createValidatorConfig(config, bootstrapNode, tcpPort, addressIndex, dataDirectory);
102
108
  const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
103
109
  return await AztecNodeService.createAndSync(
@@ -105,8 +111,7 @@ export async function createNode(
105
111
  { telemetry, dateProvider },
106
112
  { prefilledPublicData, dontStartSequencer: config.dontStartSequencer },
107
113
  );
108
- };
109
- return loggerIdStorage ? await loggerIdStorage.run(tcpPort.toString(), createNode) : createNode();
114
+ });
110
115
  }
111
116
 
112
117
  /** Creates a P2P enabled instance of Aztec Node Service without a validator */
@@ -118,9 +123,9 @@ export async function createNonValidatorNode(
118
123
  prefilledPublicData?: PublicDataTreeLeaf[],
119
124
  dataDirectory?: string,
120
125
  metricsPort?: number,
121
- loggerIdStorage?: AsyncLocalStorage<string>,
122
126
  ) {
123
- const createNode = async () => {
127
+ const actorIndex = nodeCounter++;
128
+ return await withLoggerBindings({ actor: `node-${actorIndex}` }, async () => {
124
129
  const p2pConfig = await createP2PConfig(baseConfig, bootstrapNode, tcpPort, dataDirectory);
125
130
  const config: AztecNodeConfig = {
126
131
  ...p2pConfig,
@@ -130,8 +135,7 @@ export async function createNonValidatorNode(
130
135
  };
131
136
  const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
132
137
  return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { prefilledPublicData });
133
- };
134
- return loggerIdStorage ? await loggerIdStorage.run(tcpPort.toString(), createNode) : createNode();
138
+ });
135
139
  }
136
140
 
137
141
  export async function createProverNode(
@@ -143,9 +147,9 @@ export async function createProverNode(
143
147
  prefilledPublicData?: PublicDataTreeLeaf[],
144
148
  dataDirectory?: string,
145
149
  metricsPort?: number,
146
- loggerIdStorage?: AsyncLocalStorage<string>,
147
150
  ) {
148
- const createProverNode = async () => {
151
+ const actorIndex = proverCounter++;
152
+ return await withLoggerBindings({ actor: `prover-${actorIndex}` }, async () => {
149
153
  const proverNodePrivateKey = getPrivateKeyFromIndex(ATTESTER_PRIVATE_KEYS_START_INDEX + addressIndex)!;
150
154
  const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
151
155
 
@@ -165,8 +169,7 @@ export async function createProverNode(
165
169
  prefilledPublicData,
166
170
  { ...proverNodeDeps, telemetry },
167
171
  );
168
- };
169
- return loggerIdStorage ? await loggerIdStorage.run(tcpPort.toString(), createProverNode) : createProverNode();
172
+ });
170
173
  }
171
174
 
172
175
  export async function createP2PConfig(
@@ -192,20 +195,21 @@ export async function createP2PConfig(
192
195
  }
193
196
 
194
197
  export async function createValidatorConfig(
195
- config: AztecNodeConfig,
198
+ config: CreateNodeConfig,
196
199
  bootstrapNodeEnr?: string,
197
200
  port?: number,
198
201
  addressIndex: number | number[] = 1,
199
202
  dataDirectory?: string,
200
203
  ) {
201
204
  const addressIndices = Array.isArray(addressIndex) ? addressIndex : [addressIndex];
202
- if (addressIndices.length === 0) {
205
+ if (addressIndices.length === 0 && !config.validatorPrivateKey) {
203
206
  throw new Error('At least one address index must be provided to create a validator config');
204
207
  }
205
208
 
206
- const attesterPrivateKeys = addressIndices.map(index =>
207
- bufferToHex(getPrivateKeyFromIndex(ATTESTER_PRIVATE_KEYS_START_INDEX + index)!),
208
- );
209
+ // Use override private key if provided, otherwise derive from address indices
210
+ const attesterPrivateKeys = config.validatorPrivateKey
211
+ ? [config.validatorPrivateKey]
212
+ : addressIndices.map(index => bufferToHex(getPrivateKeyFromIndex(ATTESTER_PRIVATE_KEYS_START_INDEX + index)!));
209
213
  const p2pConfig = await createP2PConfig(config, bootstrapNodeEnr, port, dataDirectory);
210
214
  const nodeConfig: AztecNodeConfig = {
211
215
  ...config,
@@ -11,7 +11,7 @@ import type { DeployAztecL1ContractsReturnType } from '@aztec/ethereum/deploy-az
11
11
  import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract';
12
12
  import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
13
13
  import { extractEvent } from '@aztec/ethereum/utils';
14
- import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
14
+ import { EpochNumber } from '@aztec/foundation/branded-types';
15
15
  import { sha256ToField } from '@aztec/foundation/crypto/sha256';
16
16
  import { InboxAbi, UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts';
17
17
  import { UniswapContract } from '@aztec/noir-contracts.js/Uniswap';
@@ -84,7 +84,7 @@ export const uniswapL1L2TestSuite = (
84
84
 
85
85
  l1Client = deployL1ContractsValues.l1Client;
86
86
 
87
- t.watcher?.setIsMarkingAsProven(false);
87
+ t.watcher.setIsMarkingAsProven(false);
88
88
 
89
89
  if (Number(await l1Client.getBlockNumber()) < expectedForkBlockNumber) {
90
90
  throw new Error('This test must be run on a fork of mainnet with the expected fork block');
@@ -250,8 +250,8 @@ export const uniswapL1L2TestSuite = (
250
250
  await wethCrossChainHarness.expectPublicBalanceOnL2(uniswapL2Contract.address, 0n);
251
251
 
252
252
  // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch.
253
- const checkpointNumber = CheckpointNumber.fromBlockNumber(l2UniswapInteractionReceipt.blockNumber!);
254
- const epoch = await rollup.getEpochNumberForCheckpoint(checkpointNumber);
253
+ const block = await aztecNode.getBlock(l2UniswapInteractionReceipt.blockNumber!);
254
+ const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber);
255
255
  await cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1));
256
256
  await waitForProven(aztecNode, l2UniswapInteractionReceipt, { provenTimeout: 300 });
257
257
 
@@ -838,9 +838,8 @@ export const uniswapL1L2TestSuite = (
838
838
  chainId: new Fr(l1Client.chain.id),
839
839
  });
840
840
 
841
- const epoch = await rollup.getEpochNumberForCheckpoint(
842
- CheckpointNumber.fromBlockNumber(withdrawReceipt.blockNumber!),
843
- );
841
+ const block = await aztecNode.getBlock(withdrawReceipt.blockNumber!);
842
+ const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber);
844
843
  const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPrivateLeaf);
845
844
  const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
846
845
 
@@ -972,9 +971,8 @@ export const uniswapL1L2TestSuite = (
972
971
  chainId: new Fr(l1Client.chain.id),
973
972
  });
974
973
 
975
- const epoch = await rollup.getEpochNumberForCheckpoint(
976
- CheckpointNumber.fromBlockNumber(withdrawReceipt.blockNumber!),
977
- );
974
+ const block = await aztecNode.getBlock(withdrawReceipt.blockNumber!);
975
+ const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber);
978
976
  const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPublicLeaf);
979
977
  const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
980
978