@aztec/aztec 0.0.1-commit.d1f2d6c → 0.0.1-commit.d20b825a7

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 (148) hide show
  1. package/dest/bin/index.js +7 -3
  2. package/dest/cli/admin_api_key_store.d.ts +45 -0
  3. package/dest/cli/admin_api_key_store.d.ts.map +1 -0
  4. package/dest/cli/admin_api_key_store.js +98 -0
  5. package/dest/cli/aztec_start_action.d.ts +1 -1
  6. package/dest/cli/aztec_start_action.d.ts.map +1 -1
  7. package/dest/cli/aztec_start_action.js +73 -19
  8. package/dest/cli/aztec_start_options.d.ts +2 -2
  9. package/dest/cli/aztec_start_options.d.ts.map +1 -1
  10. package/dest/cli/aztec_start_options.js +38 -9
  11. package/dest/cli/cli.d.ts +1 -1
  12. package/dest/cli/cli.d.ts.map +1 -1
  13. package/dest/cli/cli.js +3 -4
  14. package/dest/cli/cmds/compile.d.ts +4 -0
  15. package/dest/cli/cmds/compile.d.ts.map +1 -0
  16. package/dest/cli/cmds/compile.js +155 -0
  17. package/dest/cli/cmds/profile.d.ts +4 -0
  18. package/dest/cli/cmds/profile.d.ts.map +1 -0
  19. package/dest/cli/cmds/profile.js +8 -0
  20. package/dest/cli/cmds/profile_flamegraph.d.ts +4 -0
  21. package/dest/cli/cmds/profile_flamegraph.d.ts.map +1 -0
  22. package/dest/cli/cmds/profile_flamegraph.js +52 -0
  23. package/dest/cli/cmds/profile_gates.d.ts +4 -0
  24. package/dest/cli/cmds/profile_gates.d.ts.map +1 -0
  25. package/dest/cli/cmds/profile_gates.js +58 -0
  26. package/dest/cli/cmds/profile_utils.d.ts +18 -0
  27. package/dest/cli/cmds/profile_utils.d.ts.map +1 -0
  28. package/dest/cli/cmds/profile_utils.js +50 -0
  29. package/dest/cli/cmds/standby.d.ts +32 -0
  30. package/dest/cli/cmds/standby.d.ts.map +1 -0
  31. package/dest/cli/cmds/standby.js +97 -0
  32. package/dest/cli/cmds/start_archiver.d.ts +2 -2
  33. package/dest/cli/cmds/start_archiver.d.ts.map +1 -1
  34. package/dest/cli/cmds/start_archiver.js +4 -2
  35. package/dest/cli/cmds/start_bot.d.ts +3 -3
  36. package/dest/cli/cmds/start_bot.d.ts.map +1 -1
  37. package/dest/cli/cmds/start_bot.js +9 -5
  38. package/dest/cli/cmds/start_node.d.ts +3 -2
  39. package/dest/cli/cmds/start_node.d.ts.map +1 -1
  40. package/dest/cli/cmds/start_node.js +73 -31
  41. package/dest/cli/cmds/start_p2p_bootstrap.d.ts +2 -2
  42. package/dest/cli/cmds/start_p2p_bootstrap.d.ts.map +1 -1
  43. package/dest/cli/cmds/start_p2p_bootstrap.js +1 -2
  44. package/dest/cli/cmds/start_prover_agent.d.ts +1 -1
  45. package/dest/cli/cmds/start_prover_agent.d.ts.map +1 -1
  46. package/dest/cli/cmds/start_prover_agent.js +4 -16
  47. package/dest/cli/cmds/start_prover_broker.d.ts +1 -1
  48. package/dest/cli/cmds/start_prover_broker.d.ts.map +1 -1
  49. package/dest/cli/cmds/start_prover_broker.js +14 -8
  50. package/dest/cli/cmds/start_txe.d.ts +2 -2
  51. package/dest/cli/cmds/start_txe.d.ts.map +1 -1
  52. package/dest/cli/cmds/start_txe.js +4 -3
  53. package/dest/cli/cmds/utils/artifacts.d.ts +21 -0
  54. package/dest/cli/cmds/utils/artifacts.d.ts.map +1 -0
  55. package/dest/cli/cmds/utils/artifacts.js +24 -0
  56. package/dest/cli/cmds/utils/collect_crate_dirs.d.ts +21 -0
  57. package/dest/cli/cmds/utils/collect_crate_dirs.d.ts.map +1 -0
  58. package/dest/cli/cmds/utils/collect_crate_dirs.js +114 -0
  59. package/dest/cli/cmds/utils/needs_recompile.d.ts +10 -0
  60. package/dest/cli/cmds/utils/needs_recompile.d.ts.map +1 -0
  61. package/dest/cli/cmds/utils/needs_recompile.js +90 -0
  62. package/dest/cli/cmds/utils/spawn.d.ts +3 -0
  63. package/dest/cli/cmds/utils/spawn.d.ts.map +1 -0
  64. package/dest/cli/cmds/utils/spawn.js +16 -0
  65. package/dest/cli/cmds/utils/warn_if_aztec_version_mismatch.d.ts +4 -0
  66. package/dest/cli/cmds/utils/warn_if_aztec_version_mismatch.d.ts.map +1 -0
  67. package/dest/cli/cmds/utils/warn_if_aztec_version_mismatch.js +62 -0
  68. package/dest/cli/util.d.ts +7 -18
  69. package/dest/cli/util.d.ts.map +1 -1
  70. package/dest/cli/util.js +50 -86
  71. package/dest/examples/token.js +6 -6
  72. package/dest/local-network/banana_fpc.js +1 -1
  73. package/dest/local-network/local-network.d.ts +6 -5
  74. package/dest/local-network/local-network.d.ts.map +1 -1
  75. package/dest/local-network/local-network.js +53 -21
  76. package/dest/testing/anvil_test_watcher.d.ts +15 -3
  77. package/dest/testing/anvil_test_watcher.d.ts.map +1 -1
  78. package/dest/testing/anvil_test_watcher.js +85 -22
  79. package/dest/testing/cheat_codes.d.ts +11 -15
  80. package/dest/testing/cheat_codes.d.ts.map +1 -1
  81. package/dest/testing/cheat_codes.js +34 -32
  82. package/dest/testing/epoch_test_settler.d.ts +1 -1
  83. package/dest/testing/epoch_test_settler.d.ts.map +1 -1
  84. package/dest/testing/epoch_test_settler.js +3 -4
  85. package/dest/testing/index.d.ts +3 -2
  86. package/dest/testing/index.d.ts.map +1 -1
  87. package/dest/testing/index.js +1 -0
  88. package/dest/testing/token_allowed_setup.d.ts +7 -0
  89. package/dest/testing/token_allowed_setup.d.ts.map +1 -0
  90. package/dest/testing/token_allowed_setup.js +20 -0
  91. package/package.json +34 -34
  92. package/scripts/add_crate.sh +52 -0
  93. package/scripts/aztec.sh +15 -5
  94. package/scripts/init.sh +23 -19
  95. package/scripts/new.sh +48 -24
  96. package/scripts/setup_workspace.sh +69 -0
  97. package/scripts/templates/blank/contract/Nargo.toml +6 -0
  98. package/scripts/templates/blank/contract/src/main.nr +10 -0
  99. package/scripts/templates/blank/test/Nargo.toml +7 -0
  100. package/scripts/templates/blank/test/src/lib.nr +11 -0
  101. package/scripts/templates/counter/contract/Nargo.toml +7 -0
  102. package/scripts/templates/counter/contract/src/main.nr +48 -0
  103. package/scripts/templates/counter/test/Nargo.toml +7 -0
  104. package/scripts/templates/counter/test/src/lib.nr +32 -0
  105. package/src/bin/index.ts +7 -3
  106. package/src/cli/admin_api_key_store.ts +128 -0
  107. package/src/cli/aztec_start_action.ts +66 -15
  108. package/src/cli/aztec_start_options.ts +46 -10
  109. package/src/cli/cli.ts +3 -4
  110. package/src/cli/cmds/compile.ts +178 -0
  111. package/src/cli/cmds/profile.ts +25 -0
  112. package/src/cli/cmds/profile_flamegraph.ts +64 -0
  113. package/src/cli/cmds/profile_gates.ts +68 -0
  114. package/src/cli/cmds/profile_utils.ts +58 -0
  115. package/src/cli/cmds/standby.ts +132 -0
  116. package/src/cli/cmds/start_archiver.ts +8 -2
  117. package/src/cli/cmds/start_bot.ts +8 -5
  118. package/src/cli/cmds/start_node.ts +83 -35
  119. package/src/cli/cmds/start_p2p_bootstrap.ts +2 -2
  120. package/src/cli/cmds/start_prover_agent.ts +5 -8
  121. package/src/cli/cmds/start_prover_broker.ts +19 -15
  122. package/src/cli/cmds/start_txe.ts +5 -3
  123. package/src/cli/cmds/utils/artifacts.ts +44 -0
  124. package/src/cli/cmds/utils/collect_crate_dirs.ts +118 -0
  125. package/src/cli/cmds/utils/needs_recompile.ts +98 -0
  126. package/src/cli/cmds/utils/spawn.ts +16 -0
  127. package/src/cli/cmds/utils/warn_if_aztec_version_mismatch.ts +77 -0
  128. package/src/cli/util.ts +57 -95
  129. package/src/examples/token.ts +8 -6
  130. package/src/local-network/banana_fpc.ts +1 -1
  131. package/src/local-network/local-network.ts +59 -22
  132. package/src/testing/anvil_test_watcher.ts +95 -20
  133. package/src/testing/cheat_codes.ts +42 -36
  134. package/src/testing/epoch_test_settler.ts +3 -4
  135. package/src/testing/index.ts +2 -1
  136. package/src/testing/token_allowed_setup.ts +19 -0
  137. package/dest/cli/cmds/start_prover_node.d.ts +0 -7
  138. package/dest/cli/cmds/start_prover_node.d.ts.map +0 -1
  139. package/dest/cli/cmds/start_prover_node.js +0 -108
  140. package/dest/cli/release_version.d.ts +0 -2
  141. package/dest/cli/release_version.d.ts.map +0 -1
  142. package/dest/cli/release_version.js +0 -14
  143. package/scripts/compile.sh +0 -44
  144. package/scripts/extract_function.js +0 -47
  145. package/scripts/flamegraph.sh +0 -59
  146. package/scripts/setup_project.sh +0 -31
  147. package/src/cli/cmds/start_prover_node.ts +0 -124
  148. package/src/cli/release_version.ts +0 -21
@@ -2,7 +2,7 @@ import { getInitialTestAccountsData } from '@aztec/accounts/testing';
2
2
  import { createAztecNodeClient } from '@aztec/aztec.js/node';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { TokenContract } from '@aztec/noir-contracts.js/Token';
5
- import { TestWallet } from '@aztec/test-wallet/server';
5
+ import { EmbeddedWallet } from '@aztec/wallets/embedded';
6
6
 
7
7
  const logger = createLogger('example:token');
8
8
 
@@ -19,7 +19,7 @@ const TRANSFER_AMOUNT = 33n;
19
19
  async function main() {
20
20
  logger.info('Running token contract test on HTTP interface.');
21
21
 
22
- const wallet = await TestWallet.create(node);
22
+ const wallet = await EmbeddedWallet.create(node);
23
23
 
24
24
  // During local network setup we deploy a few accounts. Below we add them to our wallet.
25
25
  const [aliceInitialAccountData, bobInitialAccountData] = await getInitialTestAccountsData();
@@ -32,7 +32,9 @@ async function main() {
32
32
  logger.info(`Fetched Alice and Bob accounts: ${alice.toString()}, ${bob.toString()}`);
33
33
 
34
34
  logger.info('Deploying Token...');
35
- const token = await TokenContract.deploy(wallet, alice, 'TokenName', 'TokenSymbol', 18).send({ from: alice });
35
+ const { contract: token } = await TokenContract.deploy(wallet, alice, 'TokenName', 'TokenSymbol', 18).send({
36
+ from: alice,
37
+ });
36
38
  logger.info('Token deployed');
37
39
 
38
40
  // Mint tokens to Alice
@@ -41,7 +43,7 @@ async function main() {
41
43
 
42
44
  logger.info(`${ALICE_MINT_BALANCE} tokens were successfully minted by Alice and transferred to private`);
43
45
 
44
- const balanceAfterMint = await token.methods.balance_of_private(alice).simulate({ from: alice });
46
+ const { result: balanceAfterMint } = await token.methods.balance_of_private(alice).simulate({ from: alice });
45
47
  logger.info(`Tokens successfully minted. New Alice's balance: ${balanceAfterMint}`);
46
48
 
47
49
  // We will now transfer tokens from Alice to Bob
@@ -49,10 +51,10 @@ async function main() {
49
51
  await token.methods.transfer(bob, TRANSFER_AMOUNT).send({ from: alice });
50
52
 
51
53
  // Check the new balances
52
- const aliceBalance = await token.methods.balance_of_private(alice).simulate({ from: alice });
54
+ const { result: aliceBalance } = await token.methods.balance_of_private(alice).simulate({ from: alice });
53
55
  logger.info(`Alice's balance ${aliceBalance}`);
54
56
 
55
- const bobBalance = await token.methods.balance_of_private(bob).simulate({ from: bob });
57
+ const { result: bobBalance } = await token.methods.balance_of_private(bob).simulate({ from: bob });
56
58
  logger.info(`Bob's balance ${bobBalance}`);
57
59
  }
58
60
 
@@ -48,7 +48,7 @@ export async function getBananaFPCAddress(initialAccounts: InitialAccountData[])
48
48
  export async function setupBananaFPC(initialAccounts: InitialAccountData[], wallet: Wallet, log: LogFn) {
49
49
  const bananaCoinAddress = await getBananaCoinAddress(initialAccounts);
50
50
  const admin = getBananaAdmin(initialAccounts);
51
- const [bananaCoin, fpc] = await Promise.all([
51
+ const [{ contract: bananaCoin }, { contract: fpc }] = await Promise.all([
52
52
  TokenContract.deploy(wallet, admin, bananaCoinArgs.name, bananaCoinArgs.symbol, bananaCoinArgs.decimal).send({
53
53
  from: admin,
54
54
  contractAddressSalt: BANANA_COIN_SALT,
@@ -18,13 +18,17 @@ import type { LogFn } from '@aztec/foundation/log';
18
18
  import { DateProvider, TestDateProvider } from '@aztec/foundation/timer';
19
19
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
20
20
  import { protocolContractsHash } from '@aztec/protocol-contracts';
21
- import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
21
+ import { SequencerState } from '@aztec/sequencer-client';
22
+ import { AztecAddress } from '@aztec/stdlib/aztec-address';
23
+ import type { ProvingJobBroker } from '@aztec/stdlib/interfaces/server';
24
+ import type { GenesisData } from '@aztec/stdlib/world-state';
22
25
  import {
23
26
  type TelemetryClient,
24
27
  getConfigEnvVars as getTelemetryClientConfig,
25
28
  initTelemetryClient,
26
29
  } from '@aztec/telemetry-client';
27
- import { TestWallet, deployFundedSchnorrAccounts } from '@aztec/test-wallet/server';
30
+ import { EmbeddedWallet } from '@aztec/wallets/embedded';
31
+ import { deployFundedSchnorrAccounts } from '@aztec/wallets/testing';
28
32
  import { getGenesisValues } from '@aztec/world-state/testing';
29
33
 
30
34
  import { type Hex, createPublicClient, fallback, http as httpViemTransport } from 'viem';
@@ -35,6 +39,7 @@ import { createAccountLogs } from '../cli/util.js';
35
39
  import { DefaultMnemonic } from '../mnemonic.js';
36
40
  import { AnvilTestWatcher } from '../testing/anvil_test_watcher.js';
37
41
  import { EpochTestSettler } from '../testing/epoch_test_settler.js';
42
+ import { getTokenAllowedSetupFunctions } from '../testing/token_allowed_setup.js';
38
43
  import { getBananaFPCAddress, setupBananaFPC } from './banana_fpc.js';
39
44
  import { getSponsoredFPCAddress } from './sponsored_fpc.js';
40
45
 
@@ -65,7 +70,7 @@ export async function deployContractsToL1(
65
70
  genesisArchiveRoot: opts.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT),
66
71
  feeJuicePortalInitialBalance: opts.feeJuicePortalInitialBalance,
67
72
  aztecTargetCommitteeSize: 0, // no committee in local network
68
- slasherFlavor: 'none', // no slashing in local network
73
+ slasherEnabled: false, // no slashing in local network
69
74
  realVerifier: false,
70
75
  });
71
76
 
@@ -98,18 +103,25 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
98
103
  logger.warn(`Multiple L1 RPC URLs provided. Local networks will only use the first one: ${l1RpcUrl}`);
99
104
  }
100
105
 
106
+ // The local network deploys a banana FPC with Token contracts, so include Token entries
107
+ // in the setup allowlist so FPC-based fee payments work out of the box.
108
+ const tokenAllowList = await getTokenAllowedSetupFunctions();
109
+
101
110
  const aztecNodeConfig: AztecNodeConfig = {
102
111
  ...getConfigEnvVars(),
103
112
  ...config,
113
+ txPublicSetupAllowListExtend: [...tokenAllowList, ...(config.txPublicSetupAllowListExtend ?? [])],
104
114
  };
105
115
  const hdAccount = mnemonicToAccount(config.l1Mnemonic || DefaultMnemonic);
106
116
  if (
107
- aztecNodeConfig.publisherPrivateKeys == undefined ||
108
- !aztecNodeConfig.publisherPrivateKeys.length ||
109
- aztecNodeConfig.publisherPrivateKeys[0].getValue() === NULL_KEY
117
+ aztecNodeConfig.sequencerPublisherPrivateKeys == undefined ||
118
+ !aztecNodeConfig.sequencerPublisherPrivateKeys.length ||
119
+ aztecNodeConfig.sequencerPublisherPrivateKeys[0].getValue() === NULL_KEY
110
120
  ) {
111
121
  const privKey = hdAccount.getHdKey().privateKey;
112
- aztecNodeConfig.publisherPrivateKeys = [new SecretValue(`0x${Buffer.from(privKey!).toString('hex')}` as const)];
122
+ aztecNodeConfig.sequencerPublisherPrivateKeys = [
123
+ new SecretValue(`0x${Buffer.from(privKey!).toString('hex')}` as const),
124
+ ];
113
125
  }
114
126
  if (!aztecNodeConfig.validatorPrivateKeys?.getValue().length) {
115
127
  const privKey = hdAccount.getHdKey().privateKey;
@@ -133,10 +145,13 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
133
145
 
134
146
  const bananaFPC = await getBananaFPCAddress(initialAccounts);
135
147
  const sponsoredFPC = await getSponsoredFPCAddress();
136
- const fundedAddresses = initialAccounts.length
137
- ? [...initialAccounts.map(a => a.address), bananaFPC, sponsoredFPC]
138
- : [];
139
- const { genesisArchiveRoot, prefilledPublicData, fundingNeeded } = await getGenesisValues(fundedAddresses);
148
+ const prefundAddresses = (aztecNodeConfig.prefundAddresses ?? []).map(a => AztecAddress.fromString(a));
149
+ const fundedAddresses = [
150
+ ...initialAccounts.map(a => a.address),
151
+ ...(initialAccounts.length ? [bananaFPC, sponsoredFPC] : []),
152
+ ...prefundAddresses,
153
+ ];
154
+ const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(fundedAddresses);
140
155
 
141
156
  const dateProvider = new TestDateProvider();
142
157
 
@@ -175,7 +190,22 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
175
190
  const telemetry = await initTelemetryClient(getTelemetryClientConfig());
176
191
  // Create a local blob client client inside the local network, no http connectivity
177
192
  const blobClient = createBlobClient();
178
- const node = await createAztecNode(aztecNodeConfig, { telemetry, blobClient, dateProvider }, { prefilledPublicData });
193
+ const node = await createAztecNode(aztecNodeConfig, { telemetry, blobClient, dateProvider }, { genesis });
194
+
195
+ // Now that the node is up, let the watcher check for pending txs so it can skip unfilled slots faster when
196
+ // transactions are waiting in the mempool. Also let it check if the sequencer is actively building, to avoid
197
+ // warping time out from under an in-progress block.
198
+ watcher?.setGetPendingTxCount(() => node.getPendingTxCount());
199
+ const sequencer = node.getSequencer()?.getSequencer();
200
+ if (sequencer) {
201
+ const idleStates: Set<string> = new Set([
202
+ SequencerState.STOPPED,
203
+ SequencerState.STOPPING,
204
+ SequencerState.IDLE,
205
+ SequencerState.SYNCHRONIZING,
206
+ ]);
207
+ watcher?.setIsSequencerBuilding(() => !idleStates.has(sequencer.getState()));
208
+ }
179
209
 
180
210
  let epochTestSettler: EpochTestSettler | undefined;
181
211
  if (!aztecNodeConfig.p2pEnabled) {
@@ -190,16 +220,14 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
190
220
  }
191
221
 
192
222
  if (initialAccounts.length) {
193
- const PXEConfig = { proverEnabled: aztecNodeConfig.realProofs };
194
- const wallet = await TestWallet.create(node, PXEConfig);
223
+ const wallet = await EmbeddedWallet.create(node, {
224
+ pxeConfig: { proverEnabled: aztecNodeConfig.realProofs },
225
+ ephemeral: true,
226
+ });
195
227
 
196
228
  userLog('Setting up funded test accounts...');
197
229
  const accountManagers = await deployFundedSchnorrAccounts(wallet, initialAccounts);
198
- const accountsWithSecrets = accountManagers.map((manager, i) => ({
199
- account: manager,
200
- secretKey: initialAccounts[i].secret,
201
- }));
202
- const accLogs = await createAccountLogs(accountsWithSecrets, wallet);
230
+ const accLogs = await createAccountLogs(accountManagers, wallet);
203
231
  userLog(accLogs.join(''));
204
232
 
205
233
  await setupBananaFPC(initialAccounts, wallet, userLog);
@@ -225,8 +253,13 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
225
253
  */
226
254
  export async function createAztecNode(
227
255
  config: Partial<AztecNodeConfig> = {},
228
- deps: { telemetry?: TelemetryClient; blobClient?: BlobClientInterface; dateProvider?: DateProvider } = {},
229
- options: { prefilledPublicData?: PublicDataTreeLeaf[] } = {},
256
+ deps: {
257
+ telemetry?: TelemetryClient;
258
+ blobClient?: BlobClientInterface;
259
+ dateProvider?: DateProvider;
260
+ proverBroker?: ProvingJobBroker;
261
+ } = {},
262
+ options: { genesis?: GenesisData } = {},
230
263
  ) {
231
264
  // TODO(#12272): will clean this up. This is criminal.
232
265
  const { l1Contracts, ...rest } = getConfigEnvVars();
@@ -235,6 +268,10 @@ export async function createAztecNode(
235
268
  ...config,
236
269
  l1Contracts: { ...l1Contracts, ...config.l1Contracts },
237
270
  };
238
- const node = await AztecNodeService.createAndSync(aztecNodeConfig, deps, options);
271
+ const node = await AztecNodeService.createAndSync(
272
+ aztecNodeConfig,
273
+ { ...deps, proverNodeDeps: { broker: deps.proverBroker } },
274
+ options,
275
+ );
239
276
  return node;
240
277
  }
@@ -9,6 +9,11 @@ import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
9
9
 
10
10
  import { type GetContractReturnType, getAddress, getContract } from 'viem';
11
11
 
12
+ export type AnvilTestWatcherOpts = {
13
+ isLocalNetwork?: boolean;
14
+ isMarkingAsProven?: boolean;
15
+ };
16
+
12
17
  /**
13
18
  * Represents a watcher for a rollup contract.
14
19
  *
@@ -17,7 +22,8 @@ import { type GetContractReturnType, getAddress, getContract } from 'viem';
17
22
  * block within the slot. And if so, it will time travel into the next slot.
18
23
  */
19
24
  export class AnvilTestWatcher {
20
- private isLocalNetwork: boolean = false;
25
+ private isLocalNetwork;
26
+ private isMarkingAsProven;
21
27
 
22
28
  private rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
23
29
  private rollupCheatCodes: RollupCheatCodes;
@@ -29,13 +35,21 @@ export class AnvilTestWatcher {
29
35
 
30
36
  private logger: Logger = createLogger(`aztecjs:utils:watcher`);
31
37
 
32
- private isMarkingAsProven = true;
38
+ // Optional callback to check if there are pending txs in the mempool.
39
+ private getPendingTxCount?: () => Promise<number>;
40
+
41
+ // Optional callback to check if the sequencer is actively building a block.
42
+ private isSequencerBuilding?: () => boolean;
43
+
44
+ // Tracks when we first observed the current unfilled slot with pending txs (real wall time).
45
+ private unfilledSlotFirstSeen?: { slot: number; realTime: number };
33
46
 
34
47
  constructor(
35
48
  private cheatcodes: EthCheatCodes,
36
49
  rollupAddress: EthAddress,
37
50
  l1Client: ViemClient,
38
51
  private dateProvider?: TestDateProvider,
52
+ opts: AnvilTestWatcherOpts = {},
39
53
  ) {
40
54
  this.rollup = getContract({
41
55
  address: getAddress(rollupAddress.toString()),
@@ -47,6 +61,9 @@ export class AnvilTestWatcher {
47
61
  rollupAddress,
48
62
  });
49
63
 
64
+ this.isLocalNetwork = opts.isLocalNetwork ?? false;
65
+ this.isMarkingAsProven = opts.isMarkingAsProven ?? true;
66
+
50
67
  this.logger.debug(`Watcher created for rollup at ${rollupAddress}`);
51
68
  }
52
69
 
@@ -59,6 +76,16 @@ export class AnvilTestWatcher {
59
76
  this.isLocalNetwork = isLocalNetwork;
60
77
  }
61
78
 
79
+ /** Sets a callback to check for pending txs, used to skip unfilled slots faster when txs are waiting. */
80
+ setGetPendingTxCount(fn: () => Promise<number>) {
81
+ this.getPendingTxCount = fn;
82
+ }
83
+
84
+ /** Sets a callback to check if the sequencer is actively building, to avoid warping while it works. */
85
+ setIsSequencerBuilding(fn: () => boolean) {
86
+ this.isSequencerBuilding = fn;
87
+ }
88
+
62
89
  async start() {
63
90
  if (this.filledRunningPromise) {
64
91
  throw new Error('Watcher already watching for filled slot');
@@ -111,14 +138,21 @@ export class AnvilTestWatcher {
111
138
  return;
112
139
  }
113
140
 
114
- const l1Time = (await this.cheatcodes.timestamp()) * 1000;
141
+ const l1Time = (await this.cheatcodes.lastBlockTimestamp()) * 1000;
115
142
  const wallTime = this.dateProvider.now();
116
143
  if (l1Time > wallTime) {
117
144
  this.logger.warn(`L1 is ahead of wall time. Syncing wall time to L1 time`);
118
145
  this.dateProvider.setTime(l1Time);
119
146
  } else if (l1Time + Number(this.l2SlotDuration) * 1000 < wallTime) {
120
- this.logger.warn(`L1 is more than 1 L2 slot behind wall time. Warping to wall time`);
121
- await this.cheatcodes.warp(Math.ceil(wallTime / 1000));
147
+ // Warp L1 to the slot boundary at-or-before wall time. Rounding to a slot boundary (rather than
148
+ // `ceil(wallTime / 1000)`) keeps this loop's target aligned with `warpTimeIfNeeded`'s
149
+ // `nextSlotTimestamp` target, avoiding a race where the two loops pick timestamps a fraction of
150
+ // a second apart and one of them is then rejected by anvil as non-monotonic.
151
+ const wallSec = Math.floor(wallTime / 1000);
152
+ const targetSlot = await this.rollup.read.getSlotAt([BigInt(wallSec)]);
153
+ const targetTimestamp = Number(await this.rollup.read.getTimestampForSlot([targetSlot]));
154
+ this.logger.warn(`L1 is more than 1 L2 slot behind wall time. Warping to slot ${targetSlot} boundary`);
155
+ await this.warpToTimestamp(targetTimestamp);
122
156
  }
123
157
  }
124
158
 
@@ -131,16 +165,10 @@ export class AnvilTestWatcher {
131
165
  const nextSlotTimestamp = Number(await this.rollup.read.getTimestampForSlot([BigInt(nextSlot)]));
132
166
 
133
167
  if (BigInt(currentSlot) === checkpointLog.slotNumber) {
134
- // We should jump to the next slot
135
- try {
136
- await this.cheatcodes.warp(nextSlotTimestamp, {
137
- resetBlockInterval: true,
138
- });
139
- } catch (e) {
140
- this.logger.error(`Failed to warp to timestamp ${nextSlotTimestamp}: ${e}`);
168
+ // The current slot has been filled, we should jump to the next slot.
169
+ if (await this.warpToTimestamp(nextSlotTimestamp)) {
170
+ this.logger.info(`Slot ${currentSlot} was filled, jumped to next slot`);
141
171
  }
142
-
143
- this.logger.info(`Slot ${currentSlot} was filled, jumped to next slot`);
144
172
  return;
145
173
  }
146
174
 
@@ -149,18 +177,65 @@ export class AnvilTestWatcher {
149
177
  return;
150
178
  }
151
179
 
180
+ // If there are pending txs and the sequencer missed them, warp quickly (after a 2s real-time debounce) so the
181
+ // sequencer can retry in the next slot. Without this, we'd have to wait a full real-time slot duration (~36s) for
182
+ // the dateProvider to catch up to the next slot timestamp. We skip the warp if the sequencer is actively building
183
+ // to avoid invalidating its in-progress work.
184
+ if (this.getPendingTxCount) {
185
+ const pendingTxs = await this.getPendingTxCount();
186
+ if (pendingTxs > 0) {
187
+ if (this.isSequencerBuilding?.()) {
188
+ this.unfilledSlotFirstSeen = undefined;
189
+ return;
190
+ }
191
+
192
+ const realNow = Date.now();
193
+ if (!this.unfilledSlotFirstSeen || this.unfilledSlotFirstSeen.slot !== currentSlot) {
194
+ this.unfilledSlotFirstSeen = { slot: currentSlot, realTime: realNow };
195
+ return;
196
+ }
197
+
198
+ if (realNow - this.unfilledSlotFirstSeen.realTime > 2000) {
199
+ if (await this.warpToTimestamp(nextSlotTimestamp)) {
200
+ this.logger.info(`Slot ${currentSlot} was missed with pending txs, jumped to next slot`);
201
+ }
202
+ this.unfilledSlotFirstSeen = undefined;
203
+ }
204
+
205
+ return;
206
+ }
207
+ }
208
+
209
+ // Fallback: warp when the dateProvider time has passed the next slot timestamp.
152
210
  const currentTimestamp = this.dateProvider?.now() ?? Date.now();
153
211
  if (currentTimestamp > nextSlotTimestamp * 1000) {
154
- try {
155
- await this.cheatcodes.warp(nextSlotTimestamp, { resetBlockInterval: true });
156
- } catch (e) {
157
- this.logger.error(`Failed to warp to timestamp ${nextSlotTimestamp}: ${e}`);
212
+ if (await this.warpToTimestamp(nextSlotTimestamp)) {
213
+ this.logger.info(`Slot ${currentSlot} was missed, jumped to next slot`);
158
214
  }
159
-
160
- this.logger.info(`Slot ${currentSlot} was missed, jumped to next slot`);
161
215
  }
162
216
  } catch {
163
217
  this.logger.error('mineIfSlotFilled failed');
164
218
  }
165
219
  }
220
+
221
+ /**
222
+ * Warps L1 to `timestamp`, unless L1 is already at or past it. Returns true when a warp actually
223
+ * happened, false when skipped or on error. Callers use the return value to gate success logs.
224
+ */
225
+ private async warpToTimestamp(timestamp: number): Promise<boolean> {
226
+ try {
227
+ // Anvil rejects evm_setNextBlockTimestamp values <= the current block's timestamp. The two
228
+ // watcher loops can race and pick targets a fraction of a second apart; skip here rather than
229
+ // letting the second one error out noisily.
230
+ const lastTimestamp = await this.cheatcodes.lastBlockTimestamp();
231
+ if (timestamp <= lastTimestamp) {
232
+ return false;
233
+ }
234
+ await this.cheatcodes.warp(timestamp, { resetBlockInterval: true });
235
+ return true;
236
+ } catch (e) {
237
+ this.logger.error(`Failed to warp to timestamp ${timestamp}: ${e}`);
238
+ return false;
239
+ }
240
+ }
166
241
  }
@@ -1,9 +1,8 @@
1
1
  import { EthCheatCodes, RollupCheatCodes } from '@aztec/ethereum/test';
2
- import { BlockNumber } from '@aztec/foundation/branded-types';
3
- import { retryUntil } from '@aztec/foundation/retry';
2
+ import { SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { createLogger } from '@aztec/foundation/log';
4
4
  import type { DateProvider } from '@aztec/foundation/timer';
5
- import type { SequencerClient } from '@aztec/sequencer-client';
6
- import type { AztecNode } from '@aztec/stdlib/interfaces/client';
5
+ import type { AztecNode, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
7
6
 
8
7
  /**
9
8
  * A class that provides utility functions for interacting with the chain.
@@ -12,6 +11,8 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
12
11
  * codes, please consider whether it makes sense to just introduce new utils in your tests instead.
13
12
  */
14
13
  export class CheatCodes {
14
+ private logger = createLogger('aztecjs:cheat_codes');
15
+
15
16
  constructor(
16
17
  /** Cheat codes for L1.*/
17
18
  public eth: EthCheatCodes,
@@ -30,50 +31,55 @@ export class CheatCodes {
30
31
 
31
32
  /**
32
33
  * Warps the L1 timestamp to a target timestamp and mines an L2 block that advances the L2 timestamp to at least
33
- * the target timestamp. L2 timestamp is not advanced exactly to the target timestamp because it is determined
34
- * by the slot number, which advances in fixed intervals.
35
- * This is useful for testing time-dependent contract behavior.
36
- * @param sequencerClient - The sequencer client to use to force an empty block to be mined.
37
- * @param node - The Aztec node used to query if a new block has been mined.
34
+ * the target timestamp. If the target timestamp falls within the current L2 slot (which already has a block),
35
+ * the timestamp is automatically adjusted forward to the start of the next slot so that `mineBlock()` succeeds.
36
+ * @param node - The Aztec node used to force an empty block to be mined.
38
37
  * @param targetTimestamp - The target timestamp to warp to (in seconds)
39
38
  */
40
- async warpL2TimeAtLeastTo(sequencerClient: SequencerClient, node: AztecNode, targetTimestamp: bigint | number) {
41
- const currentL2BlockNumber: BlockNumber = await node.getBlockNumber();
39
+ async warpL2TimeAtLeastTo(node: AztecNodeDebug, targetTimestamp: bigint | number) {
40
+ const targetBigInt = BigInt(targetTimestamp);
41
+ const currentTimestamp = BigInt(await this.eth.lastBlockTimestamp());
42
42
 
43
- // We warp the L1 timestamp
44
- await this.eth.warp(targetTimestamp, { resetBlockInterval: true });
43
+ if (targetBigInt <= currentTimestamp) {
44
+ throw new Error(
45
+ `warpL2TimeAtLeastTo: target timestamp ${targetBigInt} is not in the future (current L1 timestamp is ${currentTimestamp}).`,
46
+ );
47
+ }
45
48
 
46
- // Wait until an L2 block is mined
47
- const sequencer = sequencerClient.getSequencer();
48
- const minTxsPerBlock = sequencer.getConfig().minTxsPerBlock;
49
- sequencer.updateConfig({ minTxsPerBlock: 0 });
49
+ const currentSlot = await this.rollup.getSlot();
50
+ const targetSlot = await this.rollup.getSlotAt(targetBigInt);
50
51
 
51
- await retryUntil(
52
- async () => {
53
- const newL2BlockNumber: BlockNumber = await node.getBlockNumber();
54
- return newL2BlockNumber > currentL2BlockNumber;
55
- },
56
- 'new block after warping L2 time',
57
- 36,
58
- 1,
59
- );
52
+ let effectiveTimestamp = targetBigInt;
60
53
 
61
- // Restore original minTxsPerBlock
62
- sequencer.updateConfig({ minTxsPerBlock });
54
+ if (targetSlot <= currentSlot) {
55
+ // Target lands in the same (or earlier) slot — auto-adjust to the next slot's start.
56
+ const nextSlot = SlotNumber(currentSlot + 1);
57
+ const nextSlotTimestamp = await this.rollup.getTimestampForSlot(nextSlot);
58
+ this.logger.warn(
59
+ `warpL2TimeAtLeastTo: target timestamp ${targetBigInt} falls in current slot ${currentSlot}. ` +
60
+ `Auto-adjusting to start of slot ${nextSlot} at timestamp ${nextSlotTimestamp}.`,
61
+ );
62
+ effectiveTimestamp = nextSlotTimestamp;
63
+ }
64
+
65
+ await this.eth.warp(effectiveTimestamp, { resetBlockInterval: true });
66
+ await node.mineBlock();
63
67
  }
64
68
 
65
69
  /**
66
70
  * Warps the L1 timestamp forward by a specified duration and mines an L2 block that advances the L2 timestamp at
67
- * least by the duration. L2 timestamp is not advanced exactly by the duration because it is determined by the slot
68
- * number, which advances in fixed intervals.
69
- * This is useful for testing time-dependent contract behavior.
70
- * @param sequencerClient - The sequencer client to use to force an empty block to be mined.
71
- * @param node - The Aztec node used to query if a new block has been mined.
71
+ * least by the duration. If the duration is too short to cross an L2 slot boundary, the warp is automatically
72
+ * extended to the start of the next slot so that `mineBlock()` succeeds.
73
+ * @param node - The Aztec node used to force an empty block to be mined.
72
74
  * @param duration - The duration to advance time by (in seconds)
73
75
  */
74
- async warpL2TimeAtLeastBy(sequencerClient: SequencerClient, node: AztecNode, duration: bigint | number) {
75
- const currentTimestamp = await this.eth.timestamp();
76
+ async warpL2TimeAtLeastBy(node: AztecNodeDebug, duration: bigint | number) {
77
+ if (BigInt(duration) <= 0n) {
78
+ throw new Error(`warpL2TimeAtLeastBy: duration must be positive, got ${duration} seconds.`);
79
+ }
80
+
81
+ const currentTimestamp = await this.eth.lastBlockTimestamp();
76
82
  const targetTimestamp = BigInt(currentTimestamp) + BigInt(duration);
77
- await this.warpL2TimeAtLeastTo(sequencerClient, node, targetTimestamp);
83
+ await this.warpL2TimeAtLeastTo(node, targetTimestamp);
78
84
  }
79
85
  }
@@ -4,7 +4,7 @@ import { type EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
4
4
  import type { Logger } from '@aztec/foundation/log';
5
5
  import { EpochMonitor } from '@aztec/prover-node';
6
6
  import type { EthAddress, L2BlockSource } from '@aztec/stdlib/block';
7
- import { computeL2ToL1MembershipWitnessFromMessagesInEpoch } from '@aztec/stdlib/messaging';
7
+ import { computeEpochOutHash } from '@aztec/stdlib/messaging';
8
8
 
9
9
  export class EpochTestSettler {
10
10
  private rollupCheatCodes: RollupCheatCodes;
@@ -51,9 +51,8 @@ export class EpochTestSettler {
51
51
  messagesInEpoch[checkpointIndex].push(block.body.txEffects.map(txEffect => txEffect.l2ToL1Msgs));
52
52
  }
53
53
 
54
- const [firstMessage] = messagesInEpoch.flat(3);
55
- if (firstMessage) {
56
- const { root: outHash } = computeL2ToL1MembershipWitnessFromMessagesInEpoch(messagesInEpoch, firstMessage);
54
+ const outHash = computeEpochOutHash(messagesInEpoch);
55
+ if (!outHash.isZero()) {
57
56
  await this.rollupCheatCodes.insertOutbox(epoch, outHash.toBigInt());
58
57
  } else {
59
58
  this.log.info(`No L2 to L1 messages in epoch ${epoch}`);
@@ -1,4 +1,5 @@
1
- export { AnvilTestWatcher } from './anvil_test_watcher.js';
1
+ export { AnvilTestWatcher, type AnvilTestWatcherOpts } from './anvil_test_watcher.js';
2
2
  export { EthCheatCodes, RollupCheatCodes } from '@aztec/ethereum/test';
3
3
  export { CheatCodes } from './cheat_codes.js';
4
4
  export { EpochTestSettler } from './epoch_test_settler.js';
5
+ export { getTokenAllowedSetupFunctions } from './token_allowed_setup.js';
@@ -0,0 +1,19 @@
1
+ import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
2
+ import { buildAllowedElement } from '@aztec/p2p/msg_validators';
3
+ import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
4
+ import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
5
+
6
+ /**
7
+ * Returns Token-specific allowlist entries needed for FPC-based fee payments.
8
+ * These are test-only: FPC-based fee payment with custom tokens won't work on mainnet alpha.
9
+ */
10
+ export async function getTokenAllowedSetupFunctions(): Promise<AllowedElement[]> {
11
+ const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id;
12
+ const target = { classId: tokenClassId };
13
+ return Promise.all([
14
+ // Token: needed for private transfers via FPC (transfer_to_public enqueues this)
15
+ buildAllowedElement(TokenContractArtifact, target, '_increase_public_balance', { onlySelf: true }),
16
+ // Token: needed for public transfers via FPC (fee_entrypoint_public enqueues this)
17
+ buildAllowedElement(TokenContractArtifact, target, 'transfer_in_public'),
18
+ ]);
19
+ }
@@ -1,7 +0,0 @@
1
- import type { NamespacedApiHandlers } from '@aztec/foundation/json-rpc/server';
2
- import type { LogFn } from '@aztec/foundation/log';
3
- import { type ProverNodeConfig } from '@aztec/prover-node';
4
- export declare function startProverNode(options: any, signalHandlers: (() => Promise<void>)[], services: NamespacedApiHandlers, userLog: LogFn): Promise<{
5
- config: ProverNodeConfig;
6
- }>;
7
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhcnRfcHJvdmVyX25vZGUuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbGkvY21kcy9zdGFydF9wcm92ZXJfbm9kZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFLQSxPQUFPLEtBQUssRUFBRSxxQkFBcUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBRS9FLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBRW5ELE9BQU8sRUFDTCxLQUFLLGdCQUFnQixFQUl0QixNQUFNLG9CQUFvQixDQUFDO0FBUzVCLHdCQUFzQixlQUFlLENBQ25DLE9BQU8sRUFBRSxHQUFHLEVBQ1osY0FBYyxFQUFFLENBQUMsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUN2QyxRQUFRLEVBQUUscUJBQXFCLEVBQy9CLE9BQU8sRUFBRSxLQUFLLEdBQ2IsT0FBTyxDQUFDO0lBQUUsTUFBTSxFQUFFLGdCQUFnQixDQUFBO0NBQUUsQ0FBQyxDQStGdkMifQ==
@@ -1 +0,0 @@
1
- {"version":3,"file":"start_prover_node.d.ts","sourceRoot":"","sources":["../../../src/cli/cmds/start_prover_node.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAE/E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EACL,KAAK,gBAAgB,EAItB,MAAM,oBAAoB,CAAC;AAS5B,wBAAsB,eAAe,CACnC,OAAO,EAAE,GAAG,EACZ,cAAc,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EACvC,QAAQ,EAAE,qBAAqB,EAC/B,OAAO,EAAE,KAAK,GACb,OAAO,CAAC;IAAE,MAAM,EAAE,gBAAgB,CAAA;CAAE,CAAC,CA+FvC"}