@aztec/aztec 5.0.0-rc.1 → 5.0.0-rc.2

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 (41) hide show
  1. package/dest/bin/index.js +2 -0
  2. package/dest/cli/aztec_start_options.js +1 -1
  3. package/dest/cli/cmds/compile.d.ts +1 -1
  4. package/dest/cli/cmds/compile.d.ts.map +1 -1
  5. package/dest/cli/cmds/compile.js +25 -17
  6. package/dest/cli/cmds/prover.d.ts +4 -0
  7. package/dest/cli/cmds/prover.d.ts.map +1 -0
  8. package/dest/cli/cmds/prover.js +24 -0
  9. package/dest/cli/cmds/standby.d.ts +28 -2
  10. package/dest/cli/cmds/standby.d.ts.map +1 -1
  11. package/dest/cli/cmds/standby.js +45 -2
  12. package/dest/cli/cmds/start_node.d.ts +1 -1
  13. package/dest/cli/cmds/start_node.d.ts.map +1 -1
  14. package/dest/cli/cmds/start_node.js +9 -7
  15. package/dest/cli/cmds/utils/artifacts.d.ts +6 -1
  16. package/dest/cli/cmds/utils/artifacts.d.ts.map +1 -1
  17. package/dest/cli/util.d.ts +10 -5
  18. package/dest/cli/util.d.ts.map +1 -1
  19. package/dest/cli/util.js +19 -48
  20. package/dest/local-network/local-network.d.ts +3 -4
  21. package/dest/local-network/local-network.d.ts.map +1 -1
  22. package/dest/local-network/local-network.js +3 -3
  23. package/dest/testing/cheat_codes.d.ts +16 -23
  24. package/dest/testing/cheat_codes.d.ts.map +1 -1
  25. package/dest/testing/cheat_codes.js +20 -80
  26. package/dest/testing/token_allowed_setup.d.ts +9 -4
  27. package/dest/testing/token_allowed_setup.d.ts.map +1 -1
  28. package/dest/testing/token_allowed_setup.js +12 -8
  29. package/package.json +34 -34
  30. package/scripts/templates/counter/contract/src/main.nr +3 -3
  31. package/src/bin/index.ts +2 -0
  32. package/src/cli/aztec_start_options.ts +1 -1
  33. package/src/cli/cmds/compile.ts +29 -16
  34. package/src/cli/cmds/prover.ts +42 -0
  35. package/src/cli/cmds/standby.ts +55 -3
  36. package/src/cli/cmds/start_node.ts +9 -16
  37. package/src/cli/cmds/utils/artifacts.ts +5 -0
  38. package/src/cli/util.ts +20 -61
  39. package/src/local-network/local-network.ts +3 -3
  40. package/src/testing/cheat_codes.ts +19 -100
  41. package/src/testing/token_allowed_setup.ts +15 -8
@@ -1,44 +1,37 @@
1
1
  import { EthCheatCodes, RollupCheatCodes } from '@aztec/ethereum/test';
2
2
  import type { DateProvider } from '@aztec/foundation/timer';
3
- import type { AutomineSequencer } from '@aztec/sequencer-client/automine';
4
3
  import type { AztecNode, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
5
4
  /**
6
- * A class that provides utility functions for interacting with the chain.
7
- * @deprecated There used to be 3 kinds of cheat codes: eth, rollup and aztec. We have nuked the Aztec ones because
8
- * they became unused (we now have better testing tools). If you are introducing a new functionality to the cheat
9
- * codes, please consider whether it makes sense to just introduce new utils in your tests instead.
5
+ * Wrapper for Aztec Debug API.
6
+ * @deprecated use the AztecNode debug API directly.
10
7
  */
11
8
  export declare class CheatCodes {
12
9
  /** Cheat codes for L1.*/
13
10
  eth: EthCheatCodes;
14
11
  /** Cheat codes for the Aztec Rollup contract on L1. */
15
12
  rollup: RollupCheatCodes;
16
- /** When wired, redirects time-warps through the AutomineSequencer queue (test-only). */
17
- private automine?;
18
- private logger;
19
13
  constructor(
20
14
  /** Cheat codes for L1.*/
21
15
  eth: EthCheatCodes,
22
16
  /** Cheat codes for the Aztec Rollup contract on L1. */
23
- rollup: RollupCheatCodes,
24
- /** When wired, redirects time-warps through the AutomineSequencer queue (test-only). */
25
- automine?: AutomineSequencer | undefined);
26
- static create(rpcUrls: string[], node: AztecNode, dateProvider: DateProvider, automine?: AutomineSequencer): Promise<CheatCodes>;
17
+ rollup: RollupCheatCodes);
18
+ static create(rpcUrls: string[], node: AztecNode, dateProvider: DateProvider): Promise<CheatCodes>;
27
19
  /**
28
- * Warps the L1 timestamp to a target timestamp and mines an L2 block that advances the L2 timestamp to at least
29
- * the target timestamp. If the target timestamp falls within the current L2 slot (which already has a block),
30
- * the timestamp is automatically adjusted forward to the start of the next slot so that `mineBlock()` succeeds.
31
- * @param node - The Aztec node used to force an empty block to be mined.
32
- * @param targetTimestamp - The target timestamp to warp to (in seconds)
20
+ * Warps the L1 timestamp to at least `targetTimestamp` and mines an L2 block advancing the L2 timestamp to at least
21
+ * the target. Forwards to the node's debug API, which serializes the warp through the automine sequencer queue.
22
+ * @param node - The Aztec node whose debug API performs the warp. Must run an automine sequencer.
23
+ * @param targetTimestamp - The target timestamp to warp to (in seconds).
24
+ * @deprecated Call `node.warpL2TimeAtLeastTo(targetTimestamp)` on the node debug API directly.
33
25
  */
34
26
  warpL2TimeAtLeastTo(node: AztecNode & AztecNodeDebug, targetTimestamp: bigint | number): Promise<void>;
35
27
  /**
36
- * Warps the L1 timestamp forward by a specified duration and mines an L2 block that advances the L2 timestamp at
37
- * least by the duration. If the duration is too short to cross an L2 slot boundary, the warp is automatically
38
- * extended to the start of the next slot so that `mineBlock()` succeeds.
39
- * @param node - The Aztec node used to force an empty block to be mined.
40
- * @param duration - The duration to advance time by (in seconds)
28
+ * Warps the L1 timestamp forward by at least `duration` seconds and mines an L2 block advancing the L2 timestamp at
29
+ * least by the duration. Forwards to the node's debug API, which serializes the warp through the automine sequencer
30
+ * queue.
31
+ * @param node - The Aztec node whose debug API performs the warp. Must run an automine sequencer.
32
+ * @param duration - The duration to advance time by (in seconds).
33
+ * @deprecated Call `node.warpL2TimeAtLeastBy(duration)` on the node debug API directly.
41
34
  */
42
35
  warpL2TimeAtLeastBy(node: AztecNode & AztecNodeDebug, duration: bigint | number): Promise<void>;
43
36
  }
44
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlYXRfY29kZXMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nL2NoZWF0X2NvZGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxhQUFhLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUd2RSxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM1RCxPQUFPLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQzFFLE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxjQUFjLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVqRjs7Ozs7R0FLRztBQUNILHFCQUFhLFVBQVU7SUFJbkIseUJBQXlCO0lBQ2xCLEdBQUcsRUFBRSxhQUFhO0lBQ3pCLHVEQUF1RDtJQUNoRCxNQUFNLEVBQUUsZ0JBQWdCO0lBQy9CLHdGQUF3RjtJQUN4RixPQUFPLENBQUMsUUFBUSxDQUFDO0lBUm5CLE9BQU8sQ0FBQyxNQUFNLENBQXVDO0lBRXJEO0lBQ0UseUJBQXlCO0lBQ2xCLEdBQUcsRUFBRSxhQUFhO0lBQ3pCLHVEQUF1RDtJQUNoRCxNQUFNLEVBQUUsZ0JBQWdCO0lBQy9CLHdGQUF3RjtJQUNoRixRQUFRLENBQUMsK0JBQW1CLEVBQ2xDO0lBRUosT0FBYSxNQUFNLENBQ2pCLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFDakIsSUFBSSxFQUFFLFNBQVMsRUFDZixZQUFZLEVBQUUsWUFBWSxFQUMxQixRQUFRLENBQUMsRUFBRSxpQkFBaUIsR0FDM0IsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQU9yQjtJQUVEOzs7Ozs7T0FNRztJQUNHLG1CQUFtQixDQUFDLElBQUksRUFBRSxTQUFTLEdBQUcsY0FBYyxFQUFFLGVBQWUsRUFBRSxNQUFNLEdBQUcsTUFBTSxpQkF5RDNGO0lBRUQ7Ozs7OztPQU1HO0lBQ0csbUJBQW1CLENBQUMsSUFBSSxFQUFFLFNBQVMsR0FBRyxjQUFjLEVBQUUsUUFBUSxFQUFFLE1BQU0sR0FBRyxNQUFNLGlCQWVwRjtDQUNGIn0=
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlYXRfY29kZXMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nL2NoZWF0X2NvZGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxhQUFhLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN2RSxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM1RCxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsY0FBYyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFakY7OztHQUdHO0FBQ0gscUJBQWEsVUFBVTtJQUVuQix5QkFBeUI7SUFDbEIsR0FBRyxFQUFFLGFBQWE7SUFDekIsdURBQXVEO0lBQ2hELE1BQU0sRUFBRSxnQkFBZ0I7SUFKakM7SUFDRSx5QkFBeUI7SUFDbEIsR0FBRyxFQUFFLGFBQWE7SUFDekIsdURBQXVEO0lBQ2hELE1BQU0sRUFBRSxnQkFBZ0IsRUFDN0I7SUFFSixPQUFhLE1BQU0sQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsWUFBWSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FPdkc7SUFFRDs7Ozs7O09BTUc7SUFDSCxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsU0FBUyxHQUFHLGNBQWMsRUFBRSxlQUFlLEVBQUUsTUFBTSxHQUFHLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBRXJHO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILG1CQUFtQixDQUFDLElBQUksRUFBRSxTQUFTLEdBQUcsY0FBYyxFQUFFLFFBQVEsRUFBRSxNQUFNLEdBQUcsTUFBTSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FFOUY7Q0FDRiJ9
@@ -1 +1 @@
1
- {"version":3,"file":"cheat_codes.d.ts","sourceRoot":"","sources":["../../src/testing/cheat_codes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjF;;;;;GAKG;AACH,qBAAa,UAAU;IAInB,yBAAyB;IAClB,GAAG,EAAE,aAAa;IACzB,uDAAuD;IAChD,MAAM,EAAE,gBAAgB;IAC/B,wFAAwF;IACxF,OAAO,CAAC,QAAQ,CAAC;IARnB,OAAO,CAAC,MAAM,CAAuC;IAErD;IACE,yBAAyB;IAClB,GAAG,EAAE,aAAa;IACzB,uDAAuD;IAChD,MAAM,EAAE,gBAAgB;IAC/B,wFAAwF;IAChF,QAAQ,CAAC,+BAAmB,EAClC;IAEJ,OAAa,MAAM,CACjB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,SAAS,EACf,YAAY,EAAE,YAAY,EAC1B,QAAQ,CAAC,EAAE,iBAAiB,GAC3B,OAAO,CAAC,UAAU,CAAC,CAOrB;IAED;;;;;;OAMG;IACG,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,iBAyD3F;IAED;;;;;;OAMG;IACG,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,iBAepF;CACF"}
1
+ {"version":3,"file":"cheat_codes.d.ts","sourceRoot":"","sources":["../../src/testing/cheat_codes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjF;;;GAGG;AACH,qBAAa,UAAU;IAEnB,yBAAyB;IAClB,GAAG,EAAE,aAAa;IACzB,uDAAuD;IAChD,MAAM,EAAE,gBAAgB;IAJjC;IACE,yBAAyB;IAClB,GAAG,EAAE,aAAa;IACzB,uDAAuD;IAChD,MAAM,EAAE,gBAAgB,EAC7B;IAEJ,OAAa,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAOvG;IAED;;;;;;OAMG;IACH,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErG;IAED;;;;;;;OAOG;IACH,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9F;CACF"}
@@ -1,96 +1,36 @@
1
1
  import { EthCheatCodes, RollupCheatCodes } from '@aztec/ethereum/test';
2
- import { SlotNumber } from '@aztec/foundation/branded-types';
3
- import { createLogger } from '@aztec/foundation/log';
4
2
  /**
5
- * A class that provides utility functions for interacting with the chain.
6
- * @deprecated There used to be 3 kinds of cheat codes: eth, rollup and aztec. We have nuked the Aztec ones because
7
- * they became unused (we now have better testing tools). If you are introducing a new functionality to the cheat
8
- * codes, please consider whether it makes sense to just introduce new utils in your tests instead.
3
+ * Wrapper for Aztec Debug API.
4
+ * @deprecated use the AztecNode debug API directly.
9
5
  */ export class CheatCodes {
10
6
  eth;
11
7
  rollup;
12
- automine;
13
- logger;
14
- constructor(/** Cheat codes for L1.*/ eth, /** Cheat codes for the Aztec Rollup contract on L1. */ rollup, /** When wired, redirects time-warps through the AutomineSequencer queue (test-only). */ automine){
8
+ constructor(/** Cheat codes for L1.*/ eth, /** Cheat codes for the Aztec Rollup contract on L1. */ rollup){
15
9
  this.eth = eth;
16
10
  this.rollup = rollup;
17
- this.automine = automine;
18
- this.logger = createLogger('aztecjs:cheat_codes');
19
11
  }
20
- static async create(rpcUrls, node, dateProvider, automine) {
12
+ static async create(rpcUrls, node, dateProvider) {
21
13
  const ethCheatCodes = new EthCheatCodes(rpcUrls, dateProvider);
22
14
  const rollupCheatCodes = new RollupCheatCodes(ethCheatCodes, await node.getNodeInfo().then((n)=>n.l1ContractAddresses));
23
- return new CheatCodes(ethCheatCodes, rollupCheatCodes, automine);
15
+ return new CheatCodes(ethCheatCodes, rollupCheatCodes);
24
16
  }
25
17
  /**
26
- * Warps the L1 timestamp to a target timestamp and mines an L2 block that advances the L2 timestamp to at least
27
- * the target timestamp. If the target timestamp falls within the current L2 slot (which already has a block),
28
- * the timestamp is automatically adjusted forward to the start of the next slot so that `mineBlock()` succeeds.
29
- * @param node - The Aztec node used to force an empty block to be mined.
30
- * @param targetTimestamp - The target timestamp to warp to (in seconds)
31
- */ async warpL2TimeAtLeastTo(node, targetTimestamp) {
32
- const targetBigInt = BigInt(targetTimestamp);
33
- const currentTimestamp = BigInt(await this.eth.lastBlockTimestamp());
34
- if (targetBigInt <= currentTimestamp) {
35
- throw new Error(`warpL2TimeAtLeastTo: target timestamp ${targetBigInt} is not in the future (current L1 timestamp is ${currentTimestamp}).`);
36
- }
37
- // AutomineSequencer owns time control through its serial queue — delegate to keep warps atomic
38
- // with respect to any in-flight build, and avoid the mineBlock-loop hack below.
39
- // `warpTo` internally builds an empty L2 checkpoint, which auto-mines exactly one L1 block at
40
- // the target slot boundary, so no separate `node.mineBlock()` is needed here.
41
- if (this.automine) {
42
- await this.automine.warpTo(Number(targetBigInt));
43
- return;
44
- }
45
- const currentSlot = await this.rollup.getSlot();
46
- let effectiveTargetSlot = await this.rollup.getSlotAt(targetBigInt);
47
- let effectiveTimestamp = await this.rollup.getTimestampForSlot(effectiveTargetSlot);
48
- if (effectiveTimestamp < targetBigInt || effectiveTargetSlot <= currentSlot) {
49
- const adjustedSlot = SlotNumber(Math.max(effectiveTargetSlot + 1, currentSlot + 1));
50
- const adjustedTimestamp = await this.rollup.getTimestampForSlot(adjustedSlot);
51
- this.logger.warn(`warpL2TimeAtLeastTo: target timestamp ${targetBigInt} does not align with a future L2 slot boundary. ` + `Auto-adjusting to start of slot ${adjustedSlot} at timestamp ${adjustedTimestamp}.`);
52
- effectiveTimestamp = adjustedTimestamp;
53
- effectiveTargetSlot = adjustedSlot;
54
- }
55
- await this.eth.warp(effectiveTimestamp, {
56
- resetBlockInterval: true
57
- });
58
- // The sequencer's polling loop may have a `work()` cycle in flight that captured pre-warp slot/timestamp values
59
- // just before our warp landed. That cycle would mine an L2 block at the stale slot — the L1 sync prunes such a
60
- // block from the canonical chain, but it lingers in local world state and the PXE will use it as the anchor for
61
- // subsequent txs, leading to `expiration_timestamp` values that are already in the past relative to L1. Mine
62
- // until we observe an L2 block at (or past) the post-warp slot, ensuring the next tx anchors to a fresh block.
63
- const maxAttempts = 5;
64
- for(let attempt = 1; attempt <= maxAttempts; attempt++){
65
- await node.mineBlock();
66
- const blockData = await node.getBlockData('latest');
67
- const blockSlot = blockData?.header.globalVariables.slotNumber;
68
- if (blockSlot !== undefined && BigInt(blockSlot) >= BigInt(effectiveTargetSlot)) {
69
- return;
70
- }
71
- this.logger.warn(`warpL2TimeAtLeastTo: mined L2 block at slot ${blockSlot}, expected at least ${effectiveTargetSlot}. ` + `Retrying mineBlock (attempt ${attempt}/${maxAttempts}).`);
72
- }
73
- throw new Error(`warpL2TimeAtLeastTo: failed to mine an L2 block at or past slot ${effectiveTargetSlot} after ${maxAttempts} attempts.`);
18
+ * Warps the L1 timestamp to at least `targetTimestamp` and mines an L2 block advancing the L2 timestamp to at least
19
+ * the target. Forwards to the node's debug API, which serializes the warp through the automine sequencer queue.
20
+ * @param node - The Aztec node whose debug API performs the warp. Must run an automine sequencer.
21
+ * @param targetTimestamp - The target timestamp to warp to (in seconds).
22
+ * @deprecated Call `node.warpL2TimeAtLeastTo(targetTimestamp)` on the node debug API directly.
23
+ */ warpL2TimeAtLeastTo(node, targetTimestamp) {
24
+ return node.warpL2TimeAtLeastTo(Number(targetTimestamp));
74
25
  }
75
26
  /**
76
- * Warps the L1 timestamp forward by a specified duration and mines an L2 block that advances the L2 timestamp at
77
- * least by the duration. If the duration is too short to cross an L2 slot boundary, the warp is automatically
78
- * extended to the start of the next slot so that `mineBlock()` succeeds.
79
- * @param node - The Aztec node used to force an empty block to be mined.
80
- * @param duration - The duration to advance time by (in seconds)
81
- */ async warpL2TimeAtLeastBy(node, duration) {
82
- if (BigInt(duration) <= 0n) {
83
- throw new Error(`warpL2TimeAtLeastBy: duration must be positive, got ${duration} seconds.`);
84
- }
85
- // Advance relative to whichever clock leads. A live sequencer mines L2 blocks at slot boundaries that can run
86
- // ahead of anvil's L1 timestamp, so basing the target on L1 alone would advance the L2 timestamp by less than
87
- // `duration`. Anchoring to the latest L2 block timestamp when it leads guarantees the post-warp L2 block is at
88
- // least `duration` ahead of the current one.
89
- const currentL1Timestamp = BigInt(await this.eth.lastBlockTimestamp());
90
- const latestBlockData = await node.getBlockData('latest');
91
- const latestL2Timestamp = latestBlockData ? BigInt(latestBlockData.header.globalVariables.timestamp) : 0n;
92
- const baseTimestamp = latestL2Timestamp > currentL1Timestamp ? latestL2Timestamp : currentL1Timestamp;
93
- const targetTimestamp = baseTimestamp + BigInt(duration);
94
- await this.warpL2TimeAtLeastTo(node, targetTimestamp);
27
+ * Warps the L1 timestamp forward by at least `duration` seconds and mines an L2 block advancing the L2 timestamp at
28
+ * least by the duration. Forwards to the node's debug API, which serializes the warp through the automine sequencer
29
+ * queue.
30
+ * @param node - The Aztec node whose debug API performs the warp. Must run an automine sequencer.
31
+ * @param duration - The duration to advance time by (in seconds).
32
+ * @deprecated Call `node.warpL2TimeAtLeastBy(duration)` on the node debug API directly.
33
+ */ warpL2TimeAtLeastBy(node, duration) {
34
+ return node.warpL2TimeAtLeastBy(Number(duration));
95
35
  }
96
36
  }
@@ -1,7 +1,12 @@
1
+ import type { ContractArtifact } from '@aztec/stdlib/abi';
1
2
  import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
2
3
  /**
3
- * Returns Token-specific allowlist entries needed for FPC-based fee payments.
4
- * These are test-only: FPC-based fee payment with custom tokens won't work on mainnet alpha.
4
+ * Returns the allowlist entries needed for FPC-based fee payments, keyed by the contract class of
5
+ * the `artifact` actually deployed as the fee token (defaults to canonical Token). The setup-phase
6
+ * validator matches these entries by class id, so a test deploying the codegen'd TestToken as its
7
+ * fee vehicle must pass `TestTokenContract.artifact` here -- otherwise the FPC fee calls are matched
8
+ * against the wrong class and rejected. Test-only: FPC fee payment with custom tokens won't work on
9
+ * mainnet alpha.
5
10
  */
6
- export declare function getTokenAllowedSetupFunctions(): Promise<AllowedElement[]>;
7
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW5fYWxsb3dlZF9zZXR1cC5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3RpbmcvdG9rZW5fYWxsb3dlZF9zZXR1cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEtBQUssRUFBRSxjQUFjLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUV0RTs7O0dBR0c7QUFDSCx3QkFBc0IsNkJBQTZCLElBQUksT0FBTyxDQUFDLGNBQWMsRUFBRSxDQUFDLENBUy9FIn0=
11
+ export declare function getTokenAllowedSetupFunctions(artifact?: ContractArtifact): Promise<AllowedElement[]>;
12
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW5fYWxsb3dlZF9zZXR1cC5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3RpbmcvdG9rZW5fYWxsb3dlZF9zZXR1cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRTFELE9BQU8sS0FBSyxFQUFFLGNBQWMsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRXRFOzs7Ozs7O0dBT0c7QUFDSCx3QkFBc0IsNkJBQTZCLENBQ2pELFFBQVEsR0FBRSxnQkFBd0MsR0FDakQsT0FBTyxDQUFDLGNBQWMsRUFBRSxDQUFDLENBUzNCIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"token_allowed_setup.d.ts","sourceRoot":"","sources":["../../src/testing/token_allowed_setup.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE;;;GAGG;AACH,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAS/E"}
1
+ {"version":3,"file":"token_allowed_setup.d.ts","sourceRoot":"","sources":["../../src/testing/token_allowed_setup.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE;;;;;;;GAOG;AACH,wBAAsB,6BAA6B,CACjD,QAAQ,GAAE,gBAAwC,GACjD,OAAO,CAAC,cAAc,EAAE,CAAC,CAS3B"}
@@ -2,19 +2,23 @@ import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
2
2
  import { buildAllowedElement } from '@aztec/p2p/msg_validators';
3
3
  import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
4
4
  /**
5
- * Returns Token-specific allowlist entries needed for FPC-based fee payments.
6
- * These are test-only: FPC-based fee payment with custom tokens won't work on mainnet alpha.
7
- */ export async function getTokenAllowedSetupFunctions() {
8
- const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id;
5
+ * Returns the allowlist entries needed for FPC-based fee payments, keyed by the contract class of
6
+ * the `artifact` actually deployed as the fee token (defaults to canonical Token). The setup-phase
7
+ * validator matches these entries by class id, so a test deploying the codegen'd TestToken as its
8
+ * fee vehicle must pass `TestTokenContract.artifact` here -- otherwise the FPC fee calls are matched
9
+ * against the wrong class and rejected. Test-only: FPC fee payment with custom tokens won't work on
10
+ * mainnet alpha.
11
+ */ export async function getTokenAllowedSetupFunctions(artifact = TokenContractArtifact) {
12
+ const tokenClassId = (await getContractClassFromArtifact(artifact)).id;
9
13
  const target = {
10
14
  classId: tokenClassId
11
15
  };
12
16
  return Promise.all([
13
- // Token: needed for private transfers via FPC (transfer_to_public enqueues this)
14
- buildAllowedElement(TokenContractArtifact, target, '_increase_public_balance', {
17
+ // needed for private transfers via FPC (transfer_to_public enqueues this)
18
+ buildAllowedElement(artifact, target, '_increase_public_balance', {
15
19
  onlySelf: true
16
20
  }),
17
- // Token: needed for public transfers via FPC (fee_entrypoint_public enqueues this)
18
- buildAllowedElement(TokenContractArtifact, target, 'transfer_in_public')
21
+ // needed for public transfers via FPC (fee_entrypoint_public enqueues this)
22
+ buildAllowedElement(artifact, target, 'transfer_in_public')
19
23
  ]);
20
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/aztec",
3
- "version": "5.0.0-rc.1",
3
+ "version": "5.0.0-rc.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -28,39 +28,39 @@
28
28
  "../package.common.json"
29
29
  ],
30
30
  "dependencies": {
31
- "@aztec/accounts": "5.0.0-rc.1",
32
- "@aztec/archiver": "5.0.0-rc.1",
33
- "@aztec/aztec-node": "5.0.0-rc.1",
34
- "@aztec/aztec.js": "5.0.0-rc.1",
35
- "@aztec/bb-prover": "5.0.0-rc.1",
36
- "@aztec/bb.js": "5.0.0-rc.1",
37
- "@aztec/blob-client": "5.0.0-rc.1",
38
- "@aztec/bot": "5.0.0-rc.1",
39
- "@aztec/builder": "5.0.0-rc.1",
40
- "@aztec/cli": "5.0.0-rc.1",
41
- "@aztec/constants": "5.0.0-rc.1",
42
- "@aztec/entrypoints": "5.0.0-rc.1",
43
- "@aztec/ethereum": "5.0.0-rc.1",
44
- "@aztec/foundation": "5.0.0-rc.1",
45
- "@aztec/kv-store": "5.0.0-rc.1",
46
- "@aztec/l1-artifacts": "5.0.0-rc.1",
47
- "@aztec/node-lib": "5.0.0-rc.1",
48
- "@aztec/noir-contracts.js": "5.0.0-rc.1",
49
- "@aztec/noir-protocol-circuits-types": "5.0.0-rc.1",
50
- "@aztec/p2p": "5.0.0-rc.1",
51
- "@aztec/p2p-bootstrap": "5.0.0-rc.1",
52
- "@aztec/protocol-contracts": "5.0.0-rc.1",
53
- "@aztec/prover-client": "5.0.0-rc.1",
54
- "@aztec/prover-node": "5.0.0-rc.1",
55
- "@aztec/pxe": "5.0.0-rc.1",
56
- "@aztec/sequencer-client": "5.0.0-rc.1",
57
- "@aztec/standard-contracts": "5.0.0-rc.1",
58
- "@aztec/stdlib": "5.0.0-rc.1",
59
- "@aztec/telemetry-client": "5.0.0-rc.1",
60
- "@aztec/txe": "5.0.0-rc.1",
61
- "@aztec/validator-ha-signer": "5.0.0-rc.1",
62
- "@aztec/wallets": "5.0.0-rc.1",
63
- "@aztec/world-state": "5.0.0-rc.1",
31
+ "@aztec/accounts": "5.0.0-rc.2",
32
+ "@aztec/archiver": "5.0.0-rc.2",
33
+ "@aztec/aztec-node": "5.0.0-rc.2",
34
+ "@aztec/aztec.js": "5.0.0-rc.2",
35
+ "@aztec/bb-prover": "5.0.0-rc.2",
36
+ "@aztec/bb.js": "5.0.0-rc.2",
37
+ "@aztec/blob-client": "5.0.0-rc.2",
38
+ "@aztec/bot": "5.0.0-rc.2",
39
+ "@aztec/builder": "5.0.0-rc.2",
40
+ "@aztec/cli": "5.0.0-rc.2",
41
+ "@aztec/constants": "5.0.0-rc.2",
42
+ "@aztec/entrypoints": "5.0.0-rc.2",
43
+ "@aztec/ethereum": "5.0.0-rc.2",
44
+ "@aztec/foundation": "5.0.0-rc.2",
45
+ "@aztec/kv-store": "5.0.0-rc.2",
46
+ "@aztec/l1-artifacts": "5.0.0-rc.2",
47
+ "@aztec/node-lib": "5.0.0-rc.2",
48
+ "@aztec/noir-contracts.js": "5.0.0-rc.2",
49
+ "@aztec/noir-protocol-circuits-types": "5.0.0-rc.2",
50
+ "@aztec/p2p": "5.0.0-rc.2",
51
+ "@aztec/p2p-bootstrap": "5.0.0-rc.2",
52
+ "@aztec/protocol-contracts": "5.0.0-rc.2",
53
+ "@aztec/prover-client": "5.0.0-rc.2",
54
+ "@aztec/prover-node": "5.0.0-rc.2",
55
+ "@aztec/pxe": "5.0.0-rc.2",
56
+ "@aztec/sequencer-client": "5.0.0-rc.2",
57
+ "@aztec/standard-contracts": "5.0.0-rc.2",
58
+ "@aztec/stdlib": "5.0.0-rc.2",
59
+ "@aztec/telemetry-client": "5.0.0-rc.2",
60
+ "@aztec/txe": "5.0.0-rc.2",
61
+ "@aztec/validator-ha-signer": "5.0.0-rc.2",
62
+ "@aztec/wallets": "5.0.0-rc.2",
63
+ "@aztec/world-state": "5.0.0-rc.2",
64
64
  "@iarna/toml": "^2.2.5",
65
65
  "@types/chalk": "^2.2.0",
66
66
  "abitype": "^0.8.11",
@@ -24,17 +24,17 @@ pub contract Counter {
24
24
  #[initializer]
25
25
  #[external("private")]
26
26
  fn constructor(initial_value: u128, owner: AztecAddress) {
27
- // Delivers the note to the recipient onchain with provable correctness.
27
+ // Delivers the note to the recipient onchain.
28
28
  // Without delivery, the recipient can't find or decrypt the note.
29
29
  self.storage.counters.at(owner).add(initial_value).deliver(
30
- MessageDelivery::onchain_constrained(),
30
+ MessageDelivery::onchain_unconstrained(),
31
31
  );
32
32
  }
33
33
 
34
34
  // Adds 1 to the owner's counter.
35
35
  #[external("private")]
36
36
  fn increment(owner: AztecAddress) {
37
- self.storage.counters.at(owner).add(1).deliver(MessageDelivery::onchain_constrained());
37
+ self.storage.counters.at(owner).add(1).deliver(MessageDelivery::onchain_unconstrained());
38
38
  }
39
39
 
40
40
  // Returns the current value of the owner's counter.
package/src/bin/index.ts CHANGED
@@ -18,6 +18,7 @@ import { Command } from 'commander';
18
18
  import { injectCompileCommand } from '../cli/cmds/compile.js';
19
19
  import { injectMigrateCommand } from '../cli/cmds/migrate_ha_db.js';
20
20
  import { injectProfileCommand } from '../cli/cmds/profile.js';
21
+ import { injectProverCommand } from '../cli/cmds/prover.js';
21
22
  import { injectAztecCommands } from '../cli/index.js';
22
23
 
23
24
  const NETWORK_FLAG = 'network';
@@ -61,6 +62,7 @@ async function main() {
61
62
  program = injectCompileCommand(program, userLog);
62
63
  program = injectProfileCommand(program, userLog);
63
64
  program = injectMigrateCommand(program, userLog);
65
+ program = injectProverCommand(program, userLog);
64
66
 
65
67
  await program.parseAsync(process.argv);
66
68
  }
@@ -109,7 +109,7 @@ export const aztecStartOptions: { [key: string]: AztecStartOption[] } = {
109
109
  env: 'NETWORK',
110
110
  },
111
111
 
112
- configToFlag('--enable-version-check', sharedNodeConfigMappings.enableVersionCheck),
112
+ configToFlag('--enable-auto-shutdown', sharedNodeConfigMappings.enableAutoShutdown),
113
113
 
114
114
  configToFlag('--sync-mode', sharedNodeConfigMappings.syncMode),
115
115
  configToFlag('--snapshots-urls', sharedNodeConfigMappings.snapshotsUrls),
@@ -12,8 +12,8 @@ import { needsRecompile } from './utils/needs_recompile.js';
12
12
  import { run } from './utils/spawn.js';
13
13
  import { warnIfAztecVersionMismatch } from './utils/warn_if_aztec_version_mismatch.js';
14
14
 
15
- /** Returns paths to contract artifacts in the target directory. */
16
- async function collectContractArtifacts(): Promise<string[]> {
15
+ /** Returns contract artifacts in the target directory along with whether each has already been postprocessed. */
16
+ async function collectContractArtifacts(): Promise<ContractArtifactInfo[]> {
17
17
  let files;
18
18
  try {
19
19
  files = await readArtifactFiles('target');
@@ -23,7 +23,9 @@ async function collectContractArtifacts(): Promise<string[]> {
23
23
  }
24
24
  throw err;
25
25
  }
26
- return files.filter(f => Array.isArray(f.content.functions)).map(f => f.filePath);
26
+ return files
27
+ .filter(f => Array.isArray(f.content.functions))
28
+ .map(f => ({ filePath: f.filePath, transpiled: f.content.transpiled === true }));
27
29
  }
28
30
 
29
31
  /** Stamps the Aztec stack version into the contract artifacts. */
@@ -141,30 +143,34 @@ async function checkNoTestsInContracts(nargo: string, log: LogFn): Promise<void>
141
143
  async function compileAztecContract(nargoArgs: string[], log: LogFn): Promise<void> {
142
144
  await warnIfAztecVersionMismatch(log);
143
145
 
144
- if (!(await needsRecompile())) {
145
- log('No source changes detected, skipping compilation.');
146
- return;
147
- }
148
-
149
146
  const nargo = process.env.NARGO ?? 'nargo';
150
147
  const bb = process.env.BB ?? findBbBinary() ?? 'bb';
151
148
 
152
- await run(nargo, ['compile', ...nargoArgs]);
149
+ const shouldRecompile = await needsRecompile();
150
+ if (shouldRecompile) {
151
+ await run(nargo, ['compile', ...nargoArgs]);
153
152
 
154
- // Ensure contract crates contain no tests (tests belong in the test crate).
155
- await checkNoTestsInContracts(nargo, log);
153
+ // Ensure contract crates contain no tests (tests belong in the test crate).
154
+ await checkNoTestsInContracts(nargo, log);
155
+ }
156
156
 
157
- const artifacts = await collectContractArtifacts();
157
+ // Postprocess any untranspiled artifacts: those just produced by nargo above, and any left behind by a bare
158
+ // `nargo compile` run outside `aztec compile`.
159
+ const unprocessed = (await collectContractArtifacts()).filter(a => !a.transpiled).map(a => a.filePath);
158
160
 
159
- if (artifacts.length > 0) {
161
+ if (unprocessed.length > 0) {
160
162
  log('Postprocessing contracts...');
161
- const bbArgs = artifacts.flatMap(a => ['-i', a]);
163
+ const bbArgs = unprocessed.flatMap(a => ['-i', a]);
162
164
  await run(bb, ['aztec_process', ...bbArgs]);
163
165
 
164
- await stampAztecVersion(artifacts);
166
+ await stampAztecVersion(unprocessed);
165
167
  }
166
168
 
167
- log('Compilation complete!');
169
+ if (shouldRecompile || unprocessed.length > 0) {
170
+ log('Compilation complete!');
171
+ } else {
172
+ log('No source changes detected, skipping compilation.');
173
+ }
168
174
  }
169
175
 
170
176
  export function injectCompileCommand(program: Command, log: LogFn): Command {
@@ -190,3 +196,10 @@ export function injectCompileCommand(program: Command, log: LogFn): Command {
190
196
 
191
197
  return program;
192
198
  }
199
+
200
+ interface ContractArtifactInfo {
201
+ /** Path to the artifact JSON in the target directory. */
202
+ filePath: string;
203
+ /** Whether the artifact has already been transpiled and had its verification keys generated. */
204
+ transpiled: boolean;
205
+ }
@@ -0,0 +1,42 @@
1
+ import { jsonStringify } from '@aztec/foundation/json-rpc';
2
+ import type { LogFn } from '@aztec/foundation/log';
3
+ import { createProverNodeAdminClient } from '@aztec/stdlib/interfaces/server';
4
+
5
+ import { type Command, InvalidArgumentError } from 'commander';
6
+
7
+ function parseEpoch(value: string): number {
8
+ const parsed = Number(value);
9
+ if (!Number.isInteger(parsed) || parsed < 0) {
10
+ throw new InvalidArgumentError('Epoch must be a non-negative integer.');
11
+ }
12
+ return parsed;
13
+ }
14
+
15
+ export function injectProverCommand(program: Command, log: LogFn): Command {
16
+ const proverCommand = program.command('prover').description('Operate a prover node via its admin JSON-RPC endpoint');
17
+
18
+ proverCommand
19
+ .command('start-proof')
20
+ .description('Schedules proving for the given epoch')
21
+ .requiredOption('--epoch <n>', 'Epoch number to prove', parseEpoch)
22
+ .requiredOption('--admin-url <url>', 'URL of the prover node admin JSON-RPC endpoint')
23
+ .option('--api-key <key>', 'Admin API key', process.env.AZTEC_ADMIN_API_KEY)
24
+ .action(async options => {
25
+ const client = createProverNodeAdminClient(options.adminUrl, {}, undefined, options.apiKey);
26
+ const jobId = await client.startProof(options.epoch);
27
+ log(`Started proving job ${jobId} for epoch ${options.epoch}`);
28
+ });
29
+
30
+ proverCommand
31
+ .command('get-jobs')
32
+ .description('Lists the prover node proving jobs')
33
+ .requiredOption('--admin-url <url>', 'URL of the prover node admin JSON-RPC endpoint')
34
+ .option('--api-key <key>', 'Admin API key', process.env.AZTEC_ADMIN_API_KEY)
35
+ .action(async options => {
36
+ const client = createProverNodeAdminClient(options.adminUrl, {}, undefined, options.apiKey);
37
+ const jobs = await client.getJobs();
38
+ log(jsonStringify(jobs, true));
39
+ });
40
+
41
+ return program;
42
+ }
@@ -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
+ }