@aztec/aztec 0.0.1-commit.2f68f620 → 0.0.1-commit.321f6a9

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 (67) hide show
  1. package/dest/bin/index.js +2 -0
  2. package/dest/cli/aztec_start_action.d.ts +1 -1
  3. package/dest/cli/aztec_start_action.d.ts.map +1 -1
  4. package/dest/cli/aztec_start_action.js +6 -27
  5. package/dest/cli/aztec_start_options.js +1 -1
  6. package/dest/cli/cmds/compile.d.ts +1 -1
  7. package/dest/cli/cmds/compile.d.ts.map +1 -1
  8. package/dest/cli/cmds/compile.js +25 -17
  9. package/dest/cli/cmds/prover.d.ts +4 -0
  10. package/dest/cli/cmds/prover.d.ts.map +1 -0
  11. package/dest/cli/cmds/prover.js +24 -0
  12. package/dest/cli/cmds/standby.d.ts +28 -2
  13. package/dest/cli/cmds/standby.d.ts.map +1 -1
  14. package/dest/cli/cmds/standby.js +45 -2
  15. package/dest/cli/cmds/start_bot.d.ts +1 -1
  16. package/dest/cli/cmds/start_bot.d.ts.map +1 -1
  17. package/dest/cli/cmds/start_bot.js +5 -1
  18. package/dest/cli/cmds/start_node.d.ts +1 -1
  19. package/dest/cli/cmds/start_node.d.ts.map +1 -1
  20. package/dest/cli/cmds/start_node.js +14 -23
  21. package/dest/cli/cmds/utils/artifacts.d.ts +6 -1
  22. package/dest/cli/cmds/utils/artifacts.d.ts.map +1 -1
  23. package/dest/cli/util.d.ts +10 -5
  24. package/dest/cli/util.d.ts.map +1 -1
  25. package/dest/cli/util.js +20 -49
  26. package/dest/examples/token.js +3 -3
  27. package/dest/local-network/local-network.d.ts +6 -5
  28. package/dest/local-network/local-network.d.ts.map +1 -1
  29. package/dest/local-network/local-network.js +33 -76
  30. package/dest/testing/cheat_codes.d.ts +16 -23
  31. package/dest/testing/cheat_codes.d.ts.map +1 -1
  32. package/dest/testing/cheat_codes.js +20 -82
  33. package/dest/testing/epoch_test_settler.d.ts +2 -2
  34. package/dest/testing/epoch_test_settler.d.ts.map +1 -1
  35. package/dest/testing/epoch_test_settler.js +5 -26
  36. package/dest/testing/index.d.ts +2 -2
  37. package/dest/testing/index.d.ts.map +1 -1
  38. package/dest/testing/index.js +1 -1
  39. package/dest/testing/local-network.d.ts +51 -0
  40. package/dest/testing/local-network.d.ts.map +1 -0
  41. package/dest/testing/local-network.js +60 -0
  42. package/dest/testing/token_allowed_setup.d.ts +9 -4
  43. package/dest/testing/token_allowed_setup.d.ts.map +1 -1
  44. package/dest/testing/token_allowed_setup.js +12 -8
  45. package/package.json +34 -34
  46. package/scripts/templates/counter/contract/src/main.nr +4 -4
  47. package/src/bin/index.ts +2 -0
  48. package/src/cli/aztec_start_action.ts +3 -14
  49. package/src/cli/aztec_start_options.ts +1 -1
  50. package/src/cli/cmds/compile.ts +29 -16
  51. package/src/cli/cmds/prover.ts +42 -0
  52. package/src/cli/cmds/standby.ts +55 -3
  53. package/src/cli/cmds/start_bot.ts +6 -1
  54. package/src/cli/cmds/start_node.ts +17 -23
  55. package/src/cli/cmds/utils/artifacts.ts +5 -0
  56. package/src/cli/util.ts +21 -62
  57. package/src/examples/token.ts +11 -3
  58. package/src/local-network/local-network.ts +40 -88
  59. package/src/testing/cheat_codes.ts +19 -103
  60. package/src/testing/epoch_test_settler.ts +8 -30
  61. package/src/testing/index.ts +1 -1
  62. package/src/testing/local-network.ts +97 -0
  63. package/src/testing/token_allowed_setup.ts +15 -8
  64. package/dest/testing/anvil_test_watcher.d.ts +0 -54
  65. package/dest/testing/anvil_test_watcher.d.ts.map +0 -1
  66. package/dest/testing/anvil_test_watcher.js +0 -235
  67. package/src/testing/anvil_test_watcher.ts +0 -273
@@ -6,13 +6,16 @@ import type { GenesisStateConfig } from '@aztec/ethereum/config';
6
6
  import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
7
7
  import type { EthAddress } from '@aztec/foundation/eth-address';
8
8
  import { startHttpRpcServer } from '@aztec/foundation/json-rpc/server';
9
- import type { LogFn } from '@aztec/foundation/log';
9
+ import { type LogFn, createLogger } from '@aztec/foundation/log';
10
10
  import { retryUntil } from '@aztec/foundation/retry';
11
11
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
12
+ import type { VersionCheck } from '@aztec/stdlib/update-checker';
12
13
  import { getGenesisValues } from '@aztec/world-state/testing';
13
14
 
14
15
  import Koa from 'koa';
15
16
 
17
+ import { isShuttingDown, softShutdown } from '../util.js';
18
+
16
19
  const ROLLUP_POLL_INTERVAL_S = 60;
17
20
 
18
21
  /**
@@ -23,7 +26,7 @@ const ROLLUP_POLL_INTERVAL_S = 60;
23
26
  export async function computeExpectedGenesisRoot(config: GenesisStateConfig, userLog: LogFn) {
24
27
  const testAccounts = config.testAccounts ? (await getInitialTestAccountsData()).map(a => a.address) : [];
25
28
  const sponsoredFPCAccounts = config.sponsoredFPC ? [await getSponsoredFPCAddress()] : [];
26
- const prefundAddresses = (config.prefundAddresses ?? []).map(a => AztecAddress.fromString(a));
29
+ const prefundAddresses = (config.prefundAddresses ?? []).map(a => AztecAddress.fromStringUnsafe(a));
27
30
  const initialFundedAccounts = testAccounts.concat(sponsoredFPCAccounts).concat(prefundAddresses);
28
31
 
29
32
  userLog(`Initial funded accounts: ${initialFundedAccounts.map(a => a.toString()).join(', ')}`);
@@ -35,7 +38,12 @@ export async function computeExpectedGenesisRoot(config: GenesisStateConfig, use
35
38
  return { genesisArchiveRoot, genesis };
36
39
  }
37
40
 
38
- async function checkRollupCompatibility(
41
+ /**
42
+ * Compares the rollup's on-chain protocol constants (genesis archive root, VK tree root, protocol
43
+ * contracts hash) against the node's expected local values. Returns a list of human-readable mismatch
44
+ * descriptions, empty if the rollup is compatible.
45
+ */
46
+ export async function checkRollupCompatibility(
39
47
  rollup: RollupContract,
40
48
  expected: { genesisArchiveRoot: Fr; vkTreeRoot: Fr; protocolContractsHash: Fr },
41
49
  ): Promise<string[]> {
@@ -130,3 +138,47 @@ export async function waitForCompatibleRollup(
130
138
  await new Promise<void>((resolve, reject) => standbyServer.close(err => (err ? reject(err) : resolve())));
131
139
  }
132
140
  }
141
+
142
+ /**
143
+ * Polls the canonical rollup's protocol constants every 10 minutes and soft-shuts-down the node once they
144
+ * diverge from the node's expected local values (i.e. an incompatible rollup has become canonical on L1).
145
+ * The HTTP health server is left running so K8s probes keep passing on the wound-down pod. This is the
146
+ * inverse of {@link waitForCompatibleRollup}; it should only be set up for nodes following the canonical
147
+ * rollup. Reuses the {@link checkRollupCompatibility} diff and the generic VersionChecker poll primitive.
148
+ */
149
+ export async function setupAutoShutdown(
150
+ config: { l1RpcUrls: string[]; l1ChainId: number },
151
+ registryAddress: EthAddress,
152
+ rollupVersion: number | 'canonical',
153
+ expected: { genesisArchiveRoot: Fr; vkTreeRoot: Fr; protocolContractsHash: Fr },
154
+ signalHandlers: Array<() => Promise<void>>,
155
+ ): Promise<void> {
156
+ const { VersionChecker } = await import('@aztec/stdlib/update-checker');
157
+
158
+ const logger = createLogger('auto_shutdown');
159
+ const publicClient = getPublicClient(config);
160
+ const registry = new RegistryContract(publicClient, registryAddress);
161
+
162
+ const check: VersionCheck = {
163
+ name: 'rollup',
164
+ currentVersion: 'compatible',
165
+ getLatestVersion: async () => {
166
+ const rollupAddress = await registry.getRollupAddress(rollupVersion);
167
+ const rollup = new RollupContract(publicClient, rollupAddress.toString());
168
+ const mismatches = await checkRollupCompatibility(rollup, expected);
169
+ return mismatches.length === 0 ? 'compatible' : `incompatible: ${mismatches.join('; ')}`;
170
+ },
171
+ };
172
+
173
+ const checker = new VersionChecker([check], 600_000, logger);
174
+ checker.on('newVersion', ({ latestVersion }) => {
175
+ if (isShuttingDown()) {
176
+ return;
177
+ }
178
+ logger.warn('Canonical rollup is no longer compatible; auto-shutting down node', { latestVersion });
179
+ // softShutdown never rejects (it awaits handlers via allSettled); fire-and-forget from the listener.
180
+ void softShutdown(logger.info.bind(logger), signalHandlers);
181
+ });
182
+ checker.start();
183
+ signalHandlers.push(() => checker.stop());
184
+ }
@@ -56,6 +56,11 @@ export async function addBot(
56
56
  const config = extractRelevantOptions<BotConfig>(options, botConfigMappings, 'bot');
57
57
  userLog?.(`Starting bot with config ${stringifyConfig(config)}`);
58
58
 
59
+ // The bot wallet's embedded PXE syncs to this tip (see start_bot.ts/start_node.ts which build the wallet from the
60
+ // same options). L1-to-L2 readiness checks must be evaluated at this tip rather than at 'latest', or the bot can
61
+ // consider a message ready while the PXE simulation anchors to an older block that cannot prove its membership yet.
62
+ const { syncChainTip } = extractRelevantOptions<PXEConfig & CliPXEOptions>(options, allPxeConfigMappings, 'pxe');
63
+
59
64
  const db = await (config.dataDirectory
60
65
  ? createStore('bot', BotStore.SCHEMA_VERSION, config)
61
66
  : openTmpStore('bot', true, config.dataStoreMapSizeKb));
@@ -63,7 +68,7 @@ export async function addBot(
63
68
  const store = new BotStore(db);
64
69
  await store.cleanupOldClaims();
65
70
 
66
- const botRunner = new BotRunner(config, wallet, aztecNode, telemetry, aztecNodeAdmin, store);
71
+ const botRunner = new BotRunner(config, wallet, aztecNode, telemetry, aztecNodeAdmin, store, syncChainTip);
67
72
  if (!config.noStart) {
68
73
  void botRunner.start(); // Do not block since bot setup takes time
69
74
  }
@@ -1,7 +1,11 @@
1
- import { type AztecNodeConfig, aztecNodeConfigMappings, getConfigEnvVars } from '@aztec/aztec-node';
1
+ import {
2
+ type AztecNodeConfig,
3
+ aztecNodeConfigMappings,
4
+ getConfigEnvVars,
5
+ registerAztecNodeRpcHandlers,
6
+ } from '@aztec/aztec-node';
2
7
  import { Fr } from '@aztec/aztec.js/fields';
3
8
  import { getL1Config } from '@aztec/cli/config';
4
- import { getPublicClient } from '@aztec/ethereum/client';
5
9
  import { getGenesisStateConfigEnvVars } from '@aztec/ethereum/config';
6
10
  import { type NetworkNames, SecretValue } from '@aztec/foundation/config';
7
11
  import type { NamespacedApiHandlers } from '@aztec/foundation/json-rpc/server';
@@ -15,8 +19,7 @@ import {
15
19
  proverBrokerBackoff,
16
20
  } from '@aztec/prover-client/broker';
17
21
  import { type CliPXEOptions, type PXEConfig, allPxeConfigMappings } from '@aztec/pxe/config';
18
- import { AztecNodeAdminApiSchema, AztecNodeApiSchema } from '@aztec/stdlib/interfaces/client';
19
- import { P2PApiSchema, ProverNodeApiSchema, type ProvingJobBroker } from '@aztec/stdlib/interfaces/server';
22
+ import { ProverNodeApiSchema, type ProvingJobBroker } from '@aztec/stdlib/interfaces/server';
20
23
  import {
21
24
  type TelemetryClientConfig,
22
25
  initTelemetryClient,
@@ -26,14 +29,9 @@ import {
26
29
  import { EmbeddedWallet } from '@aztec/wallets/embedded';
27
30
 
28
31
  import { createAztecNode } from '../../local-network/index.js';
29
- import {
30
- extractNamespacedOptions,
31
- extractRelevantOptions,
32
- preloadCrsDataForVerifying,
33
- setupVersionChecker,
34
- } from '../util.js';
32
+ import { extractNamespacedOptions, extractRelevantOptions, preloadCrsDataForVerifying } from '../util.js';
35
33
  import { getVersions } from '../versioning.js';
36
- import { computeExpectedGenesisRoot, waitForCompatibleRollup } from './standby.js';
34
+ import { computeExpectedGenesisRoot, setupAutoShutdown, waitForCompatibleRollup } from './standby.js';
37
35
  import { startProverBroker } from './start_prover_broker.js';
38
36
 
39
37
  export async function startNode(
@@ -156,15 +154,12 @@ export async function startNode(
156
154
  // Create and start Aztec Node
157
155
  const node = await createAztecNode(nodeConfig, { telemetry, proverBroker: broker }, { genesis });
158
156
 
159
- // Add node and p2p to services list
160
- services.node = [node, AztecNodeApiSchema];
161
- services.p2p = [node.getP2P(), P2PApiSchema];
162
- adminServices.nodeAdmin = [node, AztecNodeAdminApiSchema];
157
+ registerAztecNodeRpcHandlers(node, services, adminServices, { debug: options.nodeDebug });
163
158
 
164
159
  // Register prover-node services if the prover node subsystem is running
165
160
  const proverNode = node.getProverNode();
166
161
  if (proverNode) {
167
- services.prover = [proverNode, ProverNodeApiSchema];
162
+ adminServices.prover = [proverNode, ProverNodeApiSchema];
168
163
  if (!nodeConfig.proverBrokerUrl) {
169
164
  services.provingJobSource = [proverNode.getProver().getProvingJobSource(), ProvingJobConsumerSchema];
170
165
  }
@@ -183,15 +178,14 @@ export async function startNode(
183
178
  await addBot(options, signalHandlers, services, wallet, node, telemetry, undefined);
184
179
  }
185
180
 
186
- if (nodeConfig.enableVersionCheck && networkName !== 'local') {
187
- const cacheDir = process.env.DATA_DIRECTORY ? `${process.env.DATA_DIRECTORY}/cache` : undefined;
181
+ if (nodeConfig.enableAutoShutdown && networkName !== 'local' && followsCanonicalRollup) {
188
182
  try {
189
- await setupVersionChecker(
190
- networkName,
191
- followsCanonicalRollup,
192
- getPublicClient(nodeConfig!),
183
+ await setupAutoShutdown(
184
+ nodeConfig,
185
+ nodeConfig.registryAddress,
186
+ (nodeConfig.rollupVersion as number | 'canonical') ?? 'canonical',
187
+ { genesisArchiveRoot, vkTreeRoot: getVKTreeRoot(), protocolContractsHash },
193
188
  signalHandlers,
194
- cacheDir,
195
189
  );
196
190
  } catch {
197
191
  /* no-op */
@@ -6,6 +6,11 @@ export interface CompiledArtifact {
6
6
  file_map: unknown;
7
7
  functions: ContractFunction[];
8
8
  bytecode?: string;
9
+ /**
10
+ * Set to true by the AVM transpiler (invoked via `bb aztec_process`) once the contract has been transpiled and its
11
+ * verification keys generated. Absent on raw `nargo compile` output, hence optional.
12
+ */
13
+ transpiled?: boolean;
9
14
  }
10
15
 
11
16
  export interface ContractFunction {
package/src/cli/util.ts CHANGED
@@ -1,18 +1,13 @@
1
1
  import type { AztecNodeConfig } from '@aztec/aztec-node';
2
2
  import type { AccountManager } from '@aztec/aztec.js/wallet';
3
- import { getNetworkConfig } from '@aztec/cli/config';
4
- import { RegistryContract } from '@aztec/ethereum/contracts';
5
- import type { ViemClient } from '@aztec/ethereum/types';
6
- import type { ConfigMappingsType, NetworkNames } from '@aztec/foundation/config';
3
+ import type { ConfigMappingsType } from '@aztec/foundation/config';
7
4
  import { jsonStringify } from '@aztec/foundation/json-rpc';
8
- import { type LogFn, createLogger } from '@aztec/foundation/log';
5
+ import type { LogFn } from '@aztec/foundation/log';
9
6
  import type { ProverConfig } from '@aztec/stdlib/interfaces/server';
10
- import { type VersionCheck, getPackageVersion } from '@aztec/stdlib/update-checker';
11
7
  import type { EmbeddedWallet } from '@aztec/wallets/embedded';
12
8
 
13
9
  import chalk from 'chalk';
14
10
  import type { Command } from 'commander';
15
- import type { Hex } from 'viem';
16
11
 
17
12
  import { type AztecStartOption, aztecStartOptions } from './aztec_start_options.js';
18
13
 
@@ -51,6 +46,24 @@ export function isShuttingDown(): boolean {
51
46
  return shutdownPromise !== undefined;
52
47
  }
53
48
 
49
+ /**
50
+ * Stops the node's subsystems (via the registered signal handlers) without exiting the process, leaving
51
+ * the HTTP health server listening so K8s liveness/readiness probes keep passing. Unlike {@link shutdown}
52
+ * this deliberately does not latch `shutdownPromise` or call `process.exit`; instead it re-arms
53
+ * SIGTERM/SIGINT so a later K8s pod deletion still terminates the wound-down pod with a clean exit.
54
+ */
55
+ export async function softShutdown(logFn: LogFn, signalHandlers: Array<() => Promise<void>>): Promise<void> {
56
+ logFn('Canonical rollup upgrade detected: stopping subsystems, health server stays up.', {
57
+ exitCode: ExitCode.ROLLUP_UPGRADE,
58
+ });
59
+ await Promise.allSettled(signalHandlers.map(fn => fn()));
60
+ for (const sig of ['SIGTERM', 'SIGINT'] as const) {
61
+ process.removeAllListeners(sig);
62
+ process.once(sig, () => process.exit(ExitCode.ROLLUP_UPGRADE));
63
+ }
64
+ logFn('Subsystems stopped due to rollup upgrade. Health server remains active.');
65
+ }
66
+
54
67
  export const installSignalHandlers = (logFn: LogFn, cb?: Array<() => Promise<void>>) => {
55
68
  const signals = [
56
69
  ['SIGINT', ExitCode.SIGINT],
@@ -81,7 +94,7 @@ export async function createAccountLogs(accountManagers: AccountManager[], walle
81
94
  if (registeredAccounts.find(a => a.item.equals(completeAddress.address))) {
82
95
  accountLogStrings.push(` Address: ${completeAddress.address.toString()}\n`);
83
96
  accountLogStrings.push(` Partial Address: ${completeAddress.partialAddress.toString()}\n`);
84
- accountLogStrings.push(` Secret Key: ${account.getSecretKey().toString()}\n`);
97
+ accountLogStrings.push(` Secret Key: ${accountManager.getSecretKey().toString()}\n`);
85
98
  accountLogStrings.push(` Master nullifier public key hash: ${completeAddress.publicKeys.npkMHash.toString()}\n`);
86
99
  accountLogStrings.push(` Master incoming viewing public key: ${completeAddress.publicKeys.ivpkM.toString()}\n\n`);
87
100
  accountLogStrings.push(
@@ -291,60 +304,6 @@ export async function preloadCrsDataForServerSideProving(
291
304
  }
292
305
  }
293
306
 
294
- export async function setupVersionChecker(
295
- network: NetworkNames,
296
- followsCanonicalRollup: boolean,
297
- publicClient: ViemClient,
298
- signalHandlers: Array<() => Promise<void>>,
299
- cacheDir?: string,
300
- ): Promise<void> {
301
- const networkConfig = await getNetworkConfig(network, cacheDir);
302
- if (!networkConfig) {
303
- return;
304
- }
305
-
306
- const { VersionChecker } = await import('@aztec/stdlib/update-checker');
307
-
308
- const logger = createLogger('version_check');
309
- const registry = new RegistryContract(publicClient, networkConfig.registryAddress as Hex);
310
-
311
- const checks: Array<VersionCheck> = [];
312
- checks.push({
313
- name: 'node',
314
- currentVersion: getPackageVersion(),
315
- getLatestVersion: async () => {
316
- const cfg = await getNetworkConfig(network, cacheDir);
317
- return cfg?.nodeVersion;
318
- },
319
- });
320
-
321
- if (followsCanonicalRollup) {
322
- const getLatestVersion = async () => {
323
- const version = (await registry.getRollupVersions()).at(-1);
324
- return version !== undefined ? String(version) : undefined;
325
- };
326
- const currentVersion = await getLatestVersion();
327
- if (currentVersion !== undefined) {
328
- checks.push({
329
- name: 'rollup',
330
- currentVersion,
331
- getLatestVersion,
332
- });
333
- }
334
- }
335
-
336
- const checker = new VersionChecker(checks, 600_000, logger);
337
- checker.on('newVersion', ({ name, latestVersion, currentVersion }) => {
338
- if (isShuttingDown()) {
339
- return;
340
- }
341
-
342
- logger.warn(`New ${name} version available`, { latestVersion, currentVersion });
343
- });
344
- checker.start();
345
- signalHandlers.push(() => checker.stop());
346
- }
347
-
348
307
  export function stringifyConfig(config: object): string {
349
308
  return Object.entries(config)
350
309
  .map(([key, value]) => `${key}=${jsonStringify(value)}`)
@@ -21,10 +21,18 @@ async function main() {
21
21
 
22
22
  const wallet = await EmbeddedWallet.create(node);
23
23
 
24
- // During local network setup we deploy a few accounts. Below we add them to our wallet.
24
+ // During local network setup we create a few initializerless accounts. Below we add them to our wallet.
25
25
  const [aliceInitialAccountData, bobInitialAccountData] = await getInitialTestAccountsData();
26
- await wallet.createSchnorrAccount(aliceInitialAccountData.secret, aliceInitialAccountData.salt);
27
- await wallet.createSchnorrAccount(bobInitialAccountData.secret, bobInitialAccountData.salt);
26
+ await wallet.createSchnorrInitializerlessAccount(
27
+ aliceInitialAccountData.secret,
28
+ aliceInitialAccountData.salt,
29
+ aliceInitialAccountData.signingKey,
30
+ );
31
+ await wallet.createSchnorrInitializerlessAccount(
32
+ bobInitialAccountData.secret,
33
+ bobInitialAccountData.salt,
34
+ bobInitialAccountData.signingKey,
35
+ );
28
36
 
29
37
  const alice = aliceInitialAccountData.address;
30
38
  const bob = bobInitialAccountData.address;
@@ -1,25 +1,22 @@
1
1
  #!/usr/bin/env -S node --no-warnings
2
2
  import { getInitialTestAccountsData } from '@aztec/accounts/testing';
3
- import { AztecNodeService } from '@aztec/aztec-node';
3
+ import { createAztecNodeService } from '@aztec/aztec-node';
4
4
  import { type AztecNodeConfig, getConfigEnvVars } from '@aztec/aztec-node/config';
5
5
  import { Fr } from '@aztec/aztec.js/fields';
6
6
  import { createLogger } from '@aztec/aztec.js/log';
7
7
  import { type BlobClientInterface, createBlobClient } from '@aztec/blob-client/client';
8
8
  import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
9
- import { createEthereumChain } from '@aztec/ethereum/chain';
10
9
  import { waitForPublicClient } from '@aztec/ethereum/client';
11
10
  import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
12
11
  import { NULL_KEY } from '@aztec/ethereum/constants';
13
12
  import { deployAztecL1Contracts } from '@aztec/ethereum/deploy-aztec-l1-contracts';
14
13
  import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
15
- import { EthCheatCodes } from '@aztec/ethereum/test';
16
14
  import { SecretValue } from '@aztec/foundation/config';
17
15
  import { EthAddress } from '@aztec/foundation/eth-address';
18
16
  import type { LogFn } from '@aztec/foundation/log';
19
17
  import { DateProvider, TestDateProvider } from '@aztec/foundation/timer';
20
18
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
21
19
  import { protocolContractsHash } from '@aztec/protocol-contracts';
22
- import { SequencerState } from '@aztec/sequencer-client';
23
20
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
24
21
  import type { ProvingJobBroker } from '@aztec/stdlib/interfaces/server';
25
22
  import { TxStatus } from '@aztec/stdlib/tx';
@@ -30,17 +27,15 @@ import {
30
27
  initTelemetryClient,
31
28
  } from '@aztec/telemetry-client';
32
29
  import { EmbeddedWallet } from '@aztec/wallets/embedded';
33
- import { deployFundedSchnorrAccounts } from '@aztec/wallets/testing';
30
+ import { createFundedInitializerlessAccounts } from '@aztec/wallets/testing';
34
31
  import { getGenesisValues } from '@aztec/world-state/testing';
35
32
 
36
- import { type Hex, createPublicClient, fallback, http as httpViemTransport } from 'viem';
33
+ import type { Hex } from 'viem';
37
34
  import { mnemonicToAccount, privateKeyToAddress } from 'viem/accounts';
38
35
  import { foundry } from 'viem/chains';
39
36
 
40
37
  import { createAccountLogs } from '../cli/util.js';
41
38
  import { DefaultMnemonic } from '../mnemonic.js';
42
- import { AnvilTestWatcher } from '../testing/anvil_test_watcher.js';
43
- import { EpochTestSettler } from '../testing/epoch_test_settler.js';
44
39
  import { getTokenAllowedSetupFunctions } from '../testing/token_allowed_setup.js';
45
40
  import { publishStandardAuthRegistry } from './auth_registry.js';
46
41
  import { getBananaFPCAddress, setupBananaFPC } from './banana_fpc.js';
@@ -54,8 +49,6 @@ const logger = createLogger('local-network');
54
49
  // P2P node"). Wait for the checkpoint so each setup tx is durably included before the next is sent.
55
50
  const setupWaitOpts = { waitForStatus: TxStatus.CHECKPOINTED };
56
51
 
57
- const localAnvil = foundry;
58
-
59
52
  /**
60
53
  * Function to deploy our L1 contracts to the local network L1
61
54
  * @param aztecNodeConfig - The Aztec Node Config
@@ -95,6 +88,8 @@ export type LocalNetworkConfig = AztecNodeConfig & {
95
88
  l1Mnemonic: string;
96
89
  /** Whether to deploy test accounts on local network start.*/
97
90
  testAccounts: boolean;
91
+ /** Override the default per-address fee juice granted at genesis to funded addresses. */
92
+ initialAccountFeeJuice?: Fr;
98
93
  };
99
94
 
100
95
  /**
@@ -116,10 +111,33 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
116
111
  // in the setup allowlist so FPC-based fee payments work out of the box.
117
112
  const tokenAllowList = await getTokenAllowedSetupFunctions();
118
113
 
114
+ const envConfig = getConfigEnvVars();
119
115
  const aztecNodeConfig: AztecNodeConfig = {
120
- ...getConfigEnvVars(),
116
+ ...envConfig,
121
117
  ...config,
118
+ skipOrphanProposedBlockPruning: true,
119
+ // The local network builds node config from env without a DATA_DIRECTORY, so the validator's
120
+ // local signing protection runs against an ephemeral store. That is acceptable for this dev
121
+ // network; production validators must persist it and fail-fast when the data directory is unset.
122
+ allowEphemeralSigningProtection: config.allowEphemeralSigningProtection ?? true,
122
123
  txPublicSetupAllowListExtend: [...tokenAllowList, ...(config.txPublicSetupAllowListExtend ?? [])],
124
+ // The local network runs against anvil with no committee, so it defaults to the deterministic
125
+ // AutomineSequencer, which owns L1 time control (warps the dateProvider and L1 timestamps to slot
126
+ // boundaries as it builds), replacing the deleted AnvilTestWatcher. This remains true when p2p is
127
+ // enabled for local peer testing; local-network is not a mode for connecting to an existing network.
128
+ useAutomineSequencer: config.useAutomineSequencer ?? true,
129
+ // The AutomineSequencer owns epoch proving in the local network — it writes epoch out hashes to
130
+ // the L1 Outbox and advances the proven tip as checkpoints land, through the same serial queue as
131
+ // its builds — replacing the standalone EpochTestSettler that used to race the build loop.
132
+ automineEnableProveEpoch: config.automineEnableProveEpoch ?? true,
133
+ // Defaults for the local network / sandbox; callers (e.g. the CLI) may override. No real proving
134
+ // happens here — the AutomineSequencer synthetically settles epochs. Short epochs let it write out
135
+ // hashes quickly (so users can consume L2-to-L1 messages without a long wait), with a wider
136
+ // proof-submission window so the synthetic settler has headroom before the rollup would prune an
137
+ // unproven checkpoint.
138
+ realProofs: config.realProofs ?? false,
139
+ aztecEpochDuration: config.aztecEpochDuration ?? 4,
140
+ aztecProofSubmissionEpochs: config.aztecProofSubmissionEpochs ?? 2,
123
141
  };
124
142
  const hdAccount = mnemonicToAccount(config.l1Mnemonic || DefaultMnemonic);
125
143
  if (
@@ -143,7 +161,7 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
143
161
  const initialAccounts = await (async () => {
144
162
  if (config.testAccounts === true || config.testAccounts === undefined) {
145
163
  if (aztecNodeConfig.p2pEnabled) {
146
- userLog(`Not setting up test accounts as we are connecting to a network`);
164
+ userLog(`Not setting up test accounts when p2p is enabled`);
147
165
  } else {
148
166
  userLog(`Setting up test accounts`);
149
167
  return await getInitialTestAccountsData();
@@ -154,46 +172,24 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
154
172
 
155
173
  const bananaFPC = await getBananaFPCAddress(initialAccounts);
156
174
  const sponsoredFPC = await getSponsoredFPCAddress();
157
- const prefundAddresses = (aztecNodeConfig.prefundAddresses ?? []).map(a => AztecAddress.fromString(a));
175
+ const prefundAddresses = (aztecNodeConfig.prefundAddresses ?? []).map(a => AztecAddress.fromStringUnsafe(a));
158
176
  const fundedAddresses = [
159
177
  ...initialAccounts.map(a => a.address),
160
178
  ...(initialAccounts.length ? [bananaFPC, sponsoredFPC] : []),
161
179
  ...prefundAddresses,
162
180
  ];
163
- const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(fundedAddresses);
181
+ const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(
182
+ fundedAddresses,
183
+ config.initialAccountFeeJuice,
184
+ );
164
185
 
165
186
  const dateProvider = new TestDateProvider();
166
187
 
167
- let cheatcodes: EthCheatCodes | undefined;
168
- let rollupAddress: EthAddress | undefined;
169
- let watcher: AnvilTestWatcher | undefined;
170
188
  if (!aztecNodeConfig.p2pEnabled) {
171
- ({ rollupAddress } = await deployContractsToL1(
172
- aztecNodeConfig,
173
- aztecNodeConfig.validatorPrivateKeys.getValue()[0],
174
- {
175
- genesisArchiveRoot,
176
- feeJuicePortalInitialBalance: fundingNeeded,
177
- },
178
- ));
179
-
180
- const chain =
181
- aztecNodeConfig.l1RpcUrls.length > 0
182
- ? createEthereumChain([l1RpcUrl], aztecNodeConfig.l1ChainId)
183
- : { chainInfo: localAnvil };
184
-
185
- const publicClient = createPublicClient({
186
- chain: chain.chainInfo,
187
- transport: fallback([httpViemTransport(l1RpcUrl)]) as any,
189
+ await deployContractsToL1(aztecNodeConfig, aztecNodeConfig.validatorPrivateKeys.getValue()[0], {
190
+ genesisArchiveRoot,
191
+ feeJuicePortalInitialBalance: fundingNeeded,
188
192
  });
189
-
190
- cheatcodes = new EthCheatCodes([l1RpcUrl], dateProvider);
191
-
192
- watcher = new AnvilTestWatcher(cheatcodes, rollupAddress, publicClient, dateProvider);
193
- watcher.setisLocalNetwork(true);
194
- watcher.setIsMarkingAsProven(false); // Do not mark as proven in the watcher. It's marked in the epochTestSettler after the out hash is set.
195
-
196
- await watcher.start();
197
193
  }
198
194
 
199
195
  const telemetry = await initTelemetryClient(getTelemetryClientConfig());
@@ -201,48 +197,6 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
201
197
  const blobClient = createBlobClient();
202
198
  const node = await createAztecNode(aztecNodeConfig, { telemetry, blobClient, dateProvider }, { genesis });
203
199
 
204
- // Now that the node is up, let the watcher check for pending txs so it can skip unfilled slots faster when
205
- // transactions are waiting in the mempool. Also let it check if the sequencer is actively building, to avoid
206
- // warping time out from under an in-progress block.
207
- watcher?.setGetPendingTxCount(() => node.getPendingTxCount());
208
- const sequencer = node.getSequencer()?.getSequencer();
209
- if (sequencer) {
210
- const idleStates: Set<string> = new Set([
211
- SequencerState.STOPPED,
212
- SequencerState.STOPPING,
213
- SequencerState.IDLE,
214
- SequencerState.SYNCHRONIZING,
215
- ]);
216
- watcher?.setIsSequencerBuilding(() => !idleStates.has(sequencer.getState()));
217
- // Under proposer pipelining the L1 publish for slot N happens during wall-clock slot N,
218
- // but the proposer for slot N has already built the checkpoint during slot N-1 and is
219
- // waiting for L1 to advance. We need to fast-forward L1 to wake that wait — and the wait
220
- // we have to break first is `waitForValidParentCheckpointOnL1`, which blocks the
221
- // checkpoint_proposal_job's background submission task until the archiver has synced past
222
- // the build slot. That wait happens *before* `PUBLISHING_CHECKPOINT` is set, so a hook on
223
- // that state transition would be circular (L1 has to advance before the state we'd use to
224
- // advance L1 fires). The earliest pre-wait signal is `block-proposed`, which the sequencer
225
- // emits once each block is built. In sandbox single-block-per-slot mode this is
226
- // effectively "checkpoint built", and the watcher warp is harmless if a subsequent
227
- // assembly/validation/parent-wait step aborts: L1 just sits one slot ahead, which the
228
- // cascade absorbs.
229
- if (watcher) {
230
- sequencer.on('block-proposed', ({ slot }) => watcher!.setProposedTargetSlot(Number(slot)));
231
- }
232
- }
233
-
234
- let epochTestSettler: EpochTestSettler | undefined;
235
- if (!aztecNodeConfig.p2pEnabled) {
236
- epochTestSettler = new EpochTestSettler(
237
- cheatcodes!,
238
- rollupAddress!,
239
- node.getBlockSource(),
240
- logger.createChild('epoch-settler'),
241
- { pollingIntervalMs: 200 },
242
- );
243
- await epochTestSettler.start();
244
- }
245
-
246
200
  if (initialAccounts.length) {
247
201
  const wallet = await EmbeddedWallet.create(node, {
248
202
  pxeConfig: { proverEnabled: aztecNodeConfig.realProofs },
@@ -250,7 +204,7 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
250
204
  });
251
205
 
252
206
  userLog('Setting up funded test accounts...');
253
- const accountManagers = await deployFundedSchnorrAccounts(wallet, initialAccounts, setupWaitOpts);
207
+ const accountManagers = await createFundedInitializerlessAccounts(wallet, initialAccounts);
254
208
  const accLogs = await createAccountLogs(accountManagers, wallet);
255
209
  userLog(accLogs.join(''));
256
210
 
@@ -267,8 +221,6 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
267
221
 
268
222
  const stop = async () => {
269
223
  await node.stop();
270
- await watcher?.stop();
271
- await epochTestSettler?.stop();
272
224
  };
273
225
 
274
226
  return { node, stop };
@@ -294,7 +246,7 @@ export async function createAztecNode(
294
246
  ...getConfigEnvVars(),
295
247
  ...config,
296
248
  };
297
- const node = await AztecNodeService.createAndSync(
249
+ const node = await createAztecNodeService(
298
250
  aztecNodeConfig,
299
251
  { ...deps, proverNodeDeps: { broker: deps.proverBroker } },
300
252
  options,