@aztec/aztec 0.0.1-commit.a072138 → 0.0.1-commit.a89ec08

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 (128) 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 +71 -16
  8. package/dest/cli/aztec_start_options.d.ts +1 -1
  9. package/dest/cli/aztec_start_options.d.ts.map +1 -1
  10. package/dest/cli/aztec_start_options.js +31 -8
  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 +168 -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_bot.d.ts +3 -3
  33. package/dest/cli/cmds/start_bot.d.ts.map +1 -1
  34. package/dest/cli/cmds/start_bot.js +9 -5
  35. package/dest/cli/cmds/start_node.d.ts +3 -2
  36. package/dest/cli/cmds/start_node.d.ts.map +1 -1
  37. package/dest/cli/cmds/start_node.js +71 -27
  38. package/dest/cli/cmds/start_prover_agent.d.ts +1 -1
  39. package/dest/cli/cmds/start_prover_agent.d.ts.map +1 -1
  40. package/dest/cli/cmds/start_prover_agent.js +4 -16
  41. package/dest/cli/cmds/start_prover_broker.d.ts +1 -1
  42. package/dest/cli/cmds/start_prover_broker.d.ts.map +1 -1
  43. package/dest/cli/cmds/start_prover_broker.js +14 -8
  44. package/dest/cli/cmds/utils/artifacts.d.ts +21 -0
  45. package/dest/cli/cmds/utils/artifacts.d.ts.map +1 -0
  46. package/dest/cli/cmds/utils/artifacts.js +24 -0
  47. package/dest/cli/cmds/utils/collect_crate_dirs.d.ts +21 -0
  48. package/dest/cli/cmds/utils/collect_crate_dirs.d.ts.map +1 -0
  49. package/dest/cli/cmds/utils/collect_crate_dirs.js +114 -0
  50. package/dest/cli/cmds/utils/needs_recompile.d.ts +10 -0
  51. package/dest/cli/cmds/utils/needs_recompile.d.ts.map +1 -0
  52. package/dest/cli/cmds/utils/needs_recompile.js +90 -0
  53. package/dest/cli/cmds/utils/spawn.d.ts +3 -0
  54. package/dest/cli/cmds/utils/spawn.d.ts.map +1 -0
  55. package/dest/cli/cmds/utils/spawn.js +16 -0
  56. package/dest/cli/cmds/utils/warn_if_aztec_version_mismatch.d.ts +4 -0
  57. package/dest/cli/cmds/utils/warn_if_aztec_version_mismatch.d.ts.map +1 -0
  58. package/dest/cli/cmds/utils/warn_if_aztec_version_mismatch.js +41 -0
  59. package/dest/cli/util.d.ts +7 -18
  60. package/dest/cli/util.d.ts.map +1 -1
  61. package/dest/cli/util.js +47 -83
  62. package/dest/examples/token.js +6 -6
  63. package/dest/local-network/banana_fpc.js +1 -1
  64. package/dest/local-network/local-network.d.ts +4 -2
  65. package/dest/local-network/local-network.d.ts.map +1 -1
  66. package/dest/local-network/local-network.js +50 -18
  67. package/dest/testing/anvil_test_watcher.d.ts +9 -1
  68. package/dest/testing/anvil_test_watcher.d.ts.map +1 -1
  69. package/dest/testing/anvil_test_watcher.js +81 -18
  70. package/dest/testing/cheat_codes.d.ts +11 -15
  71. package/dest/testing/cheat_codes.d.ts.map +1 -1
  72. package/dest/testing/cheat_codes.js +34 -32
  73. package/dest/testing/epoch_test_settler.d.ts +1 -1
  74. package/dest/testing/epoch_test_settler.d.ts.map +1 -1
  75. package/dest/testing/epoch_test_settler.js +3 -4
  76. package/dest/testing/index.d.ts +2 -1
  77. package/dest/testing/index.d.ts.map +1 -1
  78. package/dest/testing/index.js +1 -0
  79. package/dest/testing/token_allowed_setup.d.ts +7 -0
  80. package/dest/testing/token_allowed_setup.d.ts.map +1 -0
  81. package/dest/testing/token_allowed_setup.js +20 -0
  82. package/package.json +35 -34
  83. package/scripts/add_crate.sh +102 -0
  84. package/scripts/aztec.sh +10 -3
  85. package/scripts/init.sh +23 -19
  86. package/scripts/new.sh +48 -24
  87. package/scripts/setup_workspace.sh +68 -0
  88. package/src/bin/index.ts +7 -3
  89. package/src/cli/admin_api_key_store.ts +128 -0
  90. package/src/cli/aztec_start_action.ts +64 -12
  91. package/src/cli/aztec_start_options.ts +33 -7
  92. package/src/cli/cli.ts +3 -4
  93. package/src/cli/cmds/compile.ts +194 -0
  94. package/src/cli/cmds/profile.ts +25 -0
  95. package/src/cli/cmds/profile_flamegraph.ts +64 -0
  96. package/src/cli/cmds/profile_gates.ts +68 -0
  97. package/src/cli/cmds/profile_utils.ts +58 -0
  98. package/src/cli/cmds/standby.ts +132 -0
  99. package/src/cli/cmds/start_bot.ts +8 -5
  100. package/src/cli/cmds/start_node.ts +83 -33
  101. package/src/cli/cmds/start_prover_agent.ts +5 -8
  102. package/src/cli/cmds/start_prover_broker.ts +19 -15
  103. package/src/cli/cmds/utils/artifacts.ts +44 -0
  104. package/src/cli/cmds/utils/collect_crate_dirs.ts +118 -0
  105. package/src/cli/cmds/utils/needs_recompile.ts +98 -0
  106. package/src/cli/cmds/utils/spawn.ts +16 -0
  107. package/src/cli/cmds/utils/warn_if_aztec_version_mismatch.ts +54 -0
  108. package/src/cli/util.ts +55 -93
  109. package/src/examples/token.ts +8 -6
  110. package/src/local-network/banana_fpc.ts +1 -1
  111. package/src/local-network/local-network.ts +54 -17
  112. package/src/testing/anvil_test_watcher.ts +85 -18
  113. package/src/testing/cheat_codes.ts +42 -36
  114. package/src/testing/epoch_test_settler.ts +3 -4
  115. package/src/testing/index.ts +1 -0
  116. package/src/testing/token_allowed_setup.ts +19 -0
  117. package/dest/cli/cmds/start_prover_node.d.ts +0 -7
  118. package/dest/cli/cmds/start_prover_node.d.ts.map +0 -1
  119. package/dest/cli/cmds/start_prover_node.js +0 -108
  120. package/dest/cli/release_version.d.ts +0 -2
  121. package/dest/cli/release_version.d.ts.map +0 -1
  122. package/dest/cli/release_version.js +0 -14
  123. package/scripts/compile.sh +0 -44
  124. package/scripts/extract_function.js +0 -47
  125. package/scripts/flamegraph.sh +0 -59
  126. package/scripts/setup_project.sh +0 -31
  127. package/src/cli/cmds/start_prover_node.ts +0 -124
  128. package/src/cli/release_version.ts +0 -21
@@ -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 { SequencerState } from '@aztec/sequencer-client';
22
+ import { AztecAddress } from '@aztec/stdlib/aztec-address';
23
+ import type { ProvingJobBroker } from '@aztec/stdlib/interfaces/server';
21
24
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
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
 
@@ -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,9 +145,12 @@ 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
- : [];
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
+ ];
139
154
  const { genesisArchiveRoot, prefilledPublicData, fundingNeeded } = await getGenesisValues(fundedAddresses);
140
155
 
141
156
  const dateProvider = new TestDateProvider();
@@ -177,6 +192,21 @@ export async function createLocalNetwork(config: Partial<LocalNetworkConfig> = {
177
192
  const blobClient = createBlobClient();
178
193
  const node = await createAztecNode(aztecNodeConfig, { telemetry, blobClient, dateProvider }, { prefilledPublicData });
179
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
+ }
209
+
180
210
  let epochTestSettler: EpochTestSettler | undefined;
181
211
  if (!aztecNodeConfig.p2pEnabled) {
182
212
  epochTestSettler = new EpochTestSettler(
@@ -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,7 +253,12 @@ 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 } = {},
256
+ deps: {
257
+ telemetry?: TelemetryClient;
258
+ blobClient?: BlobClientInterface;
259
+ dateProvider?: DateProvider;
260
+ proverBroker?: ProvingJobBroker;
261
+ } = {},
229
262
  options: { prefilledPublicData?: PublicDataTreeLeaf[] } = {},
230
263
  ) {
231
264
  // TODO(#12272): will clean this up. This is criminal.
@@ -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
  }
@@ -31,6 +31,15 @@ export class AnvilTestWatcher {
31
31
 
32
32
  private isMarkingAsProven = true;
33
33
 
34
+ // Optional callback to check if there are pending txs in the mempool.
35
+ private getPendingTxCount?: () => Promise<number>;
36
+
37
+ // Optional callback to check if the sequencer is actively building a block.
38
+ private isSequencerBuilding?: () => boolean;
39
+
40
+ // Tracks when we first observed the current unfilled slot with pending txs (real wall time).
41
+ private unfilledSlotFirstSeen?: { slot: number; realTime: number };
42
+
34
43
  constructor(
35
44
  private cheatcodes: EthCheatCodes,
36
45
  rollupAddress: EthAddress,
@@ -59,6 +68,16 @@ export class AnvilTestWatcher {
59
68
  this.isLocalNetwork = isLocalNetwork;
60
69
  }
61
70
 
71
+ /** Sets a callback to check for pending txs, used to skip unfilled slots faster when txs are waiting. */
72
+ setGetPendingTxCount(fn: () => Promise<number>) {
73
+ this.getPendingTxCount = fn;
74
+ }
75
+
76
+ /** Sets a callback to check if the sequencer is actively building, to avoid warping while it works. */
77
+ setIsSequencerBuilding(fn: () => boolean) {
78
+ this.isSequencerBuilding = fn;
79
+ }
80
+
62
81
  async start() {
63
82
  if (this.filledRunningPromise) {
64
83
  throw new Error('Watcher already watching for filled slot');
@@ -111,14 +130,21 @@ export class AnvilTestWatcher {
111
130
  return;
112
131
  }
113
132
 
114
- const l1Time = (await this.cheatcodes.timestamp()) * 1000;
133
+ const l1Time = (await this.cheatcodes.lastBlockTimestamp()) * 1000;
115
134
  const wallTime = this.dateProvider.now();
116
135
  if (l1Time > wallTime) {
117
136
  this.logger.warn(`L1 is ahead of wall time. Syncing wall time to L1 time`);
118
137
  this.dateProvider.setTime(l1Time);
119
138
  } 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));
139
+ // Warp L1 to the slot boundary at-or-before wall time. Rounding to a slot boundary (rather than
140
+ // `ceil(wallTime / 1000)`) keeps this loop's target aligned with `warpTimeIfNeeded`'s
141
+ // `nextSlotTimestamp` target, avoiding a race where the two loops pick timestamps a fraction of
142
+ // a second apart and one of them is then rejected by anvil as non-monotonic.
143
+ const wallSec = Math.floor(wallTime / 1000);
144
+ const targetSlot = await this.rollup.read.getSlotAt([BigInt(wallSec)]);
145
+ const targetTimestamp = Number(await this.rollup.read.getTimestampForSlot([targetSlot]));
146
+ this.logger.warn(`L1 is more than 1 L2 slot behind wall time. Warping to slot ${targetSlot} boundary`);
147
+ await this.warpToTimestamp(targetTimestamp);
122
148
  }
123
149
  }
124
150
 
@@ -131,16 +157,10 @@ export class AnvilTestWatcher {
131
157
  const nextSlotTimestamp = Number(await this.rollup.read.getTimestampForSlot([BigInt(nextSlot)]));
132
158
 
133
159
  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}`);
160
+ // The current slot has been filled, we should jump to the next slot.
161
+ if (await this.warpToTimestamp(nextSlotTimestamp)) {
162
+ this.logger.info(`Slot ${currentSlot} was filled, jumped to next slot`);
141
163
  }
142
-
143
- this.logger.info(`Slot ${currentSlot} was filled, jumped to next slot`);
144
164
  return;
145
165
  }
146
166
 
@@ -149,18 +169,65 @@ export class AnvilTestWatcher {
149
169
  return;
150
170
  }
151
171
 
172
+ // If there are pending txs and the sequencer missed them, warp quickly (after a 2s real-time debounce) so the
173
+ // sequencer can retry in the next slot. Without this, we'd have to wait a full real-time slot duration (~36s) for
174
+ // the dateProvider to catch up to the next slot timestamp. We skip the warp if the sequencer is actively building
175
+ // to avoid invalidating its in-progress work.
176
+ if (this.getPendingTxCount) {
177
+ const pendingTxs = await this.getPendingTxCount();
178
+ if (pendingTxs > 0) {
179
+ if (this.isSequencerBuilding?.()) {
180
+ this.unfilledSlotFirstSeen = undefined;
181
+ return;
182
+ }
183
+
184
+ const realNow = Date.now();
185
+ if (!this.unfilledSlotFirstSeen || this.unfilledSlotFirstSeen.slot !== currentSlot) {
186
+ this.unfilledSlotFirstSeen = { slot: currentSlot, realTime: realNow };
187
+ return;
188
+ }
189
+
190
+ if (realNow - this.unfilledSlotFirstSeen.realTime > 2000) {
191
+ if (await this.warpToTimestamp(nextSlotTimestamp)) {
192
+ this.logger.info(`Slot ${currentSlot} was missed with pending txs, jumped to next slot`);
193
+ }
194
+ this.unfilledSlotFirstSeen = undefined;
195
+ }
196
+
197
+ return;
198
+ }
199
+ }
200
+
201
+ // Fallback: warp when the dateProvider time has passed the next slot timestamp.
152
202
  const currentTimestamp = this.dateProvider?.now() ?? Date.now();
153
203
  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}`);
204
+ if (await this.warpToTimestamp(nextSlotTimestamp)) {
205
+ this.logger.info(`Slot ${currentSlot} was missed, jumped to next slot`);
158
206
  }
159
-
160
- this.logger.info(`Slot ${currentSlot} was missed, jumped to next slot`);
161
207
  }
162
208
  } catch {
163
209
  this.logger.error('mineIfSlotFilled failed');
164
210
  }
165
211
  }
212
+
213
+ /**
214
+ * Warps L1 to `timestamp`, unless L1 is already at or past it. Returns true when a warp actually
215
+ * happened, false when skipped or on error. Callers use the return value to gate success logs.
216
+ */
217
+ private async warpToTimestamp(timestamp: number): Promise<boolean> {
218
+ try {
219
+ // Anvil rejects evm_setNextBlockTimestamp values <= the current block's timestamp. The two
220
+ // watcher loops can race and pick targets a fraction of a second apart; skip here rather than
221
+ // letting the second one error out noisily.
222
+ const lastTimestamp = await this.cheatcodes.lastBlockTimestamp();
223
+ if (timestamp <= lastTimestamp) {
224
+ return false;
225
+ }
226
+ await this.cheatcodes.warp(timestamp, { resetBlockInterval: true });
227
+ return true;
228
+ } catch (e) {
229
+ this.logger.error(`Failed to warp to timestamp ${timestamp}: ${e}`);
230
+ return false;
231
+ }
232
+ }
166
233
  }
@@ -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}`);
@@ -2,3 +2,4 @@ export { AnvilTestWatcher } 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"}
@@ -1,108 +0,0 @@
1
- import { getInitialTestAccountsData } from '@aztec/accounts/testing';
2
- import { Fr } from '@aztec/aztec.js/fields';
3
- import { getSponsoredFPCAddress } from '@aztec/cli/cli-utils';
4
- import { getL1Config } from '@aztec/cli/config';
5
- import { getPublicClient } from '@aztec/ethereum/client';
6
- import { Agent, makeUndiciFetch } from '@aztec/foundation/json-rpc/undici';
7
- import { ProvingJobConsumerSchema, createProvingJobBrokerClient } from '@aztec/prover-client/broker';
8
- import { createProverNode, getProverNodeConfigFromEnv, proverNodeConfigMappings } from '@aztec/prover-node';
9
- import { P2PApiSchema, ProverNodeApiSchema } from '@aztec/stdlib/interfaces/server';
10
- import { initTelemetryClient, makeTracedFetch, telemetryClientConfigMappings } from '@aztec/telemetry-client';
11
- import { getGenesisValues } from '@aztec/world-state/testing';
12
- import { extractRelevantOptions, preloadCrsDataForVerifying, setupUpdateMonitor } from '../util.js';
13
- import { getVersions } from '../versioning.js';
14
- import { startProverBroker } from './start_prover_broker.js';
15
- export async function startProverNode(options, signalHandlers, services, userLog) {
16
- if (options.node || options.sequencer || options.pxe || options.p2pBootstrap || options.txe) {
17
- userLog(`Starting a prover-node with --node, --sequencer, --pxe, --p2p-bootstrap, or --txe is not supported.`);
18
- process.exit(1);
19
- }
20
- let proverConfig = {
21
- ...getProverNodeConfigFromEnv(),
22
- ...extractRelevantOptions(options, proverNodeConfigMappings, 'proverNode')
23
- };
24
- if (!proverConfig.l1Contracts.registryAddress || proverConfig.l1Contracts.registryAddress.isZero()) {
25
- throw new Error('L1 registry address is required to start a Prover Node');
26
- }
27
- const followsCanonicalRollup = typeof proverConfig.rollupVersion !== 'number';
28
- const { addresses, config } = await getL1Config(proverConfig.l1Contracts.registryAddress, proverConfig.l1RpcUrls, proverConfig.l1ChainId, proverConfig.rollupVersion);
29
- process.env.ROLLUP_CONTRACT_ADDRESS ??= addresses.rollupAddress.toString();
30
- proverConfig.l1Contracts = addresses;
31
- proverConfig = {
32
- ...proverConfig,
33
- ...config
34
- };
35
- const testAccounts = proverConfig.testAccounts ? (await getInitialTestAccountsData()).map((a)=>a.address) : [];
36
- const sponsoredFPCAccounts = proverConfig.sponsoredFPC ? [
37
- await getSponsoredFPCAddress()
38
- ] : [];
39
- const initialFundedAccounts = testAccounts.concat(sponsoredFPCAccounts);
40
- userLog(`Initial funded accounts: ${initialFundedAccounts.map((a)=>a.toString()).join(', ')}`);
41
- const { genesisArchiveRoot, prefilledPublicData } = await getGenesisValues(initialFundedAccounts);
42
- userLog(`Genesis archive root: ${genesisArchiveRoot.toString()}`);
43
- if (!Fr.fromHexString(config.genesisArchiveTreeRoot).equals(genesisArchiveRoot)) {
44
- throw new Error(`The computed genesis archive tree root ${genesisArchiveRoot} does not match the expected genesis archive tree root ${config.genesisArchiveTreeRoot} for the rollup deployed at ${addresses.rollupAddress}`);
45
- }
46
- const telemetry = await initTelemetryClient(extractRelevantOptions(options, telemetryClientConfigMappings, 'tel'));
47
- let broker;
48
- if (proverConfig.proverBrokerUrl) {
49
- // at 1TPS we'd enqueue ~1k chonk verifier proofs and ~1k AVM proofs immediately
50
- // set a lower connection limit such that we don't overload the server
51
- // Keep retrying up to 30s
52
- const fetch = makeTracedFetch([
53
- 1,
54
- 2,
55
- 3,
56
- 3,
57
- 3,
58
- 3,
59
- 3,
60
- 3,
61
- 3,
62
- 3,
63
- 3
64
- ], false, makeUndiciFetch(new Agent({
65
- connections: 100
66
- })));
67
- broker = createProvingJobBrokerClient(proverConfig.proverBrokerUrl, getVersions(proverConfig), fetch);
68
- } else if (options.proverBroker) {
69
- ({ broker } = await startProverBroker(options, signalHandlers, services, userLog));
70
- } else {
71
- userLog(`--prover-broker-url or --prover-broker is required to start a Prover Node`);
72
- process.exit(1);
73
- }
74
- if (proverConfig.proverAgentCount === 0) {
75
- userLog(`Running prover node without local prover agent. Connect one or more prover agents to this node or pass --proverAgent.proverAgentCount`);
76
- }
77
- await preloadCrsDataForVerifying(proverConfig, userLog);
78
- const proverNode = await createProverNode(proverConfig, {
79
- telemetry,
80
- broker
81
- }, {
82
- prefilledPublicData
83
- });
84
- services.proverNode = [
85
- proverNode,
86
- ProverNodeApiSchema
87
- ];
88
- if (proverNode.getP2P()) {
89
- services.p2p = [
90
- proverNode.getP2P(),
91
- P2PApiSchema
92
- ];
93
- }
94
- if (!proverConfig.proverBrokerUrl) {
95
- services.provingJobSource = [
96
- proverNode.getProver().getProvingJobSource(),
97
- ProvingJobConsumerSchema
98
- ];
99
- }
100
- signalHandlers.push(proverNode.stop.bind(proverNode));
101
- await proverNode.start();
102
- if (proverConfig.autoUpdate !== 'disabled' && proverConfig.autoUpdateUrl) {
103
- await setupUpdateMonitor(proverConfig.autoUpdate, new URL(proverConfig.autoUpdateUrl), followsCanonicalRollup, getPublicClient(proverConfig), proverConfig.l1Contracts.registryAddress, signalHandlers);
104
- }
105
- return {
106
- config: proverConfig
107
- };
108
- }
@@ -1,2 +0,0 @@
1
- export declare const getCliVersion: () => any;
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsZWFzZV92ZXJzaW9uLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpL3JlbGVhc2VfdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFLQSxlQUFPLE1BQU0sYUFBYSxXQWV6QixDQUFDIn0=
@@ -1 +0,0 @@
1
- {"version":3,"file":"release_version.d.ts","sourceRoot":"","sources":["../../src/cli/release_version.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,aAAa,WAezB,CAAC"}
@@ -1,14 +0,0 @@
1
- import { fileURLToPath } from '@aztec/foundation/url';
2
- import { readFileSync } from 'fs';
3
- import { dirname, resolve } from 'path';
4
- export const getCliVersion = ()=>{
5
- const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json');
6
- const cliVersion = JSON.parse(readFileSync(packageJsonPath).toString()).version;
7
- // If the version is 0.1.0, this is a placeholder version and we are in a docker container; query release please for the latest version
8
- if (cliVersion === '0.1.0') {
9
- const releasePleasePath = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../.release-please-manifest.json');
10
- const releaseVersion = JSON.parse(readFileSync(releasePleasePath).toString())['.'];
11
- return releaseVersion;
12
- }
13
- return cliVersion;
14
- };
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- NARGO=${NARGO:-nargo}
5
- BB=${BB:-bb}
6
-
7
- # If help is requested, show Aztec-specific info then run nargo compile help and then exit in order to not trigger
8
- # transpilation
9
- for arg in "$@"; do
10
- if [ "$arg" == "--help" ] || [ "$arg" == "-h" ]; then
11
- cat << 'EOF'
12
- Aztec Compile - Compile Aztec Noir contracts
13
-
14
- This command compiles Aztec Noir contracts using nargo and then automatically
15
- postprocesses them to generate Aztec specific artifacts including:
16
- - Transpiled contract artifacts
17
- - Verification keys
18
-
19
- The compiled contracts will be placed in the target/ directory by default.
20
-
21
- ---
22
- Underlying nargo compile options:
23
-
24
- EOF
25
- nargo compile --help
26
- exit 0
27
- fi
28
- done
29
-
30
- # Run nargo compile.
31
- $NARGO compile "$@"
32
-
33
- echo "Postprocessing contract..."
34
- $BB aztec_process
35
-
36
- # Strip internal prefixes from all compiled contract JSONs in target directory
37
- # TODO: This should be part of bb aztec_process!
38
- for json in target/*.json; do
39
- temp_file="${json}.tmp"
40
- jq '.functions |= map(.name |= sub("^__aztec_nr_internals__"; ""))' "$json" > "$temp_file"
41
- mv "$temp_file" "$json"
42
- done
43
-
44
- echo "Compilation complete!"