@tokamak-private-dapps/private-state-cli 0.1.5 → 0.1.8

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.8 - 2026-04-30
4
+
5
+ - Reused common proof backend version helpers for Tokamak and Groth16 compatibility checks.
6
+ - Reused common npm registry metadata lookup during proof backend runtime installation.
7
+
8
+ ## 0.1.7 - 2026-04-29
9
+
10
+ - Required Groth16 channel verifier and installed CRS compatibility versions to use canonical major.minor form.
11
+ - Matched Groth16 channel verifier compatibility against the installed CRS major.minor compatibility version.
12
+ - Required the Groth16 package version with verified public CRS archive selection.
13
+ - Required Tokamak zk-EVM channel verifier and CLI package compatibility versions to use canonical major.minor form.
14
+
15
+ ## 0.1.6 - 2026-04-29
16
+
17
+ - Added `--groth16-cli-version` and `--tokamak-zk-evm-cli-version` install options with npm latest defaults.
18
+ - Installed selected proof backend package versions into managed runtime directories.
19
+ - Downloaded Groth16 CRS artifacts matching the selected Groth16 CLI version.
20
+ - Checked channel verifier compatible backend versions before local proof generation.
21
+ - Reported selected proof backend runtime versions from `--doctor`.
22
+
3
23
  ## 0.1.5 - 2026-04-28
4
24
 
5
25
  - Switched channel balance proof generation to invoke `tokamak-groth16 --prove` instead of importing Groth16 proof internals directly.
package/README.md CHANGED
@@ -15,6 +15,18 @@ artifacts:
15
15
  private-state-cli --install
16
16
  ```
17
17
 
18
+ By default, `--install` resolves the latest `@tokamak-zk-evm/cli` and `@tokamak-private-dapps/groth16` versions from
19
+ the npm registry. To pin exact proof backend versions for a channel, pass explicit versions:
20
+
21
+ ```bash
22
+ private-state-cli --install --tokamak-zk-evm-cli-version 2.0.8 --groth16-cli-version 0.1.1
23
+ ```
24
+
25
+ The Groth16 installer downloads the public Google Drive CRS archive whose major.minor compatibility version matches the
26
+ selected Groth16 CLI package version.
27
+ The Tokamak zk-EVM installer requires the selected CLI package to declare
28
+ `tokamakZkEvm.compatibleBackendVersion` as a canonical major.minor version matching the selected package version.
29
+
18
30
  `--install` downloads public deployment artifacts from the configured artifact index. It does not read repository-local
19
31
  `deployment/` outputs by default. Repository development workflows that need local anvil artifacts can opt in explicitly:
20
32
 
@@ -52,7 +64,7 @@ A common private-state flow is:
52
64
  Use `private-state-cli --help` for the full command list and required options.
53
65
 
54
66
  `private-state-cli --doctor` reports the CLI package version, dependency versions recorded by the last
55
- `private-state-cli --install`, current dependency versions through `tokamak-l2js`, and Tokamak zk-EVM runtime
67
+ `private-state-cli --install`, selected proof backend runtime versions, current dependency versions through `tokamak-l2js`, and Tokamak zk-EVM runtime
56
68
  install mode, Docker mode, CUDA runtime metadata, live `nvidia-smi` and Docker GPU probe results, and Groth16
57
69
  runtime health. The doctor check fails when the Tokamak Docker `useGpus` metadata does not match the live GPU probes.
58
70
 
@@ -138,6 +150,8 @@ using bridge-facing commands on a new machine.
138
150
  Channel balance commands such as `deposit-channel` and `withdraw-channel` use the installed Groth16 runtime workspace
139
151
  directly. Proof generation writes to the fixed workspace paths under `~/tokamak-private-channels/groth16/proof`; the CLI
140
152
  does not pass custom `--zkey`, proof-output, or public-output paths to the Groth16 prover.
153
+ Before proof generation, the CLI compares the target channel's verifier compatibility versions with the installed
154
+ Tokamak zk-EVM and Groth16 major.minor compatibility versions.
141
155
 
142
156
  Release order matters for npm publication. `@tokamak-private-dapps/common-library` and
143
157
  `@tokamak-private-dapps/groth16` must be published before this package version.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokamak-private-dapps/private-state-cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.8",
4
4
  "description": "Command-line client for the Tokamak private-state DApp.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "author": "Tokamak Network",
@@ -41,10 +41,10 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@ethereumjs/util": "^10.1.1",
44
- "@noble/curves": "^1.2.0",
45
- "@tokamak-private-dapps/common-library": "^0.1.0",
46
- "@tokamak-private-dapps/groth16": "^0.1.1",
47
- "@tokamak-zk-evm/cli": "^2.0.8",
44
+ "@noble/curves": "1.9.7",
45
+ "@tokamak-private-dapps/common-library": "^0.1.1",
46
+ "@tokamak-private-dapps/groth16": "^0.1.4",
47
+ "@tokamak-zk-evm/cli": "^2.0.13",
48
48
  "ethers": "^6.14.1",
49
49
  "tokamak-l2js": "^0.1.3"
50
50
  },
@@ -44,12 +44,17 @@ import {
44
44
  hexToBytes,
45
45
  } from "@ethereumjs/util";
46
46
  import { deriveRpcUrl, resolveCliNetwork } from "@tokamak-private-dapps/common-library/network-config";
47
+ import { fetchNpmPackageMetadata } from "@tokamak-private-dapps/common-library/npm-registry";
48
+ import {
49
+ normalizePackageVersionToCompatibleBackendVersion,
50
+ readTokamakZkEvmCompatibleBackendVersionFromPackageJson,
51
+ requireCanonicalCompatibleBackendVersion,
52
+ requireExactSemverVersion,
53
+ } from "@tokamak-private-dapps/common-library/proof-backend-versioning";
47
54
  import {
48
- buildTokamakCliInvocation,
49
55
  resolveTokamakBlockInputConfig,
50
- resolveTokamakCliPackageRoot,
51
- resolveTokamakCliResourceDir,
52
- resolveTokamakCliRuntimeRoot,
56
+ resolveTokamakCliEntryPath,
57
+ resolveTokamakCliPackageRoot as resolveBundledTokamakCliPackageRoot,
53
58
  } from "@tokamak-private-dapps/common-library/tokamak-runtime-paths";
54
59
  import {
55
60
  DEFAULT_PUBLIC_ARTIFACT_INDEX_FILE_ID,
@@ -66,6 +71,9 @@ import { toGroth16SolidityProof } from "@tokamak-private-dapps/common-library/gr
66
71
  import {
67
72
  PUBLIC_GROTH16_MPC_DRIVE_FOLDER_ID,
68
73
  downloadLatestPublicGroth16MpcArtifacts,
74
+ downloadPublicGroth16MpcArtifactsByVersion,
75
+ readGroth16CompatibleBackendVersionFromPackageJson,
76
+ requireCanonicalGroth16CompatibleBackendVersion,
69
77
  } from "@tokamak-private-dapps/groth16/public-drive-crs";
70
78
  import {
71
79
  CHANNEL_BOUND_L2_DERIVATION_MODE,
@@ -85,17 +93,20 @@ const require = createRequire(import.meta.url);
85
93
  const defaultCommandCwd = process.cwd();
86
94
  const privateStateCliPackageRoot = path.dirname(require.resolve("./package.json"));
87
95
  const workspaceRoot = path.resolve(os.homedir(), "tokamak-private-channels", "workspace");
88
- const tokamakCliInvocation = buildTokamakCliInvocation();
89
- const tokamakCliCommand = tokamakCliInvocation.command;
90
- const tokamakCliBaseArgs = tokamakCliInvocation.args;
91
96
  const flatDeploymentArtifactPathsByChainId = new Map();
92
97
  const DOCKER_CUDA_PROBE_IMAGE = "nvidia/cuda:12.2.0-base-ubuntu22.04";
93
98
  const DOCTOR_GPU_PROBE_TIMEOUT_MS = 120000;
99
+ const GROTH16_PACKAGE_NAME = "@tokamak-private-dapps/groth16";
100
+ const TOKAMAK_ZKEVM_CLI_PACKAGE_NAME = "@tokamak-zk-evm/cli";
94
101
 
95
102
  const abiCoder = AbiCoder.defaultAbiCoder();
96
103
  const erc20MetadataAbi = [
97
104
  "function decimals() view returns (uint8)",
98
105
  ];
106
+ const channelVerifierVersionAbi = [
107
+ "function grothVerifierCompatibleBackendVersion() view returns (string)",
108
+ "function tokamakVerifierCompatibleBackendVersion() view returns (string)",
109
+ ];
99
110
  const {
100
111
  aPubBlockLength: TOKAMAK_APUB_BLOCK_LENGTH,
101
112
  previousBlockHashCount: TOKAMAK_PREVIOUS_BLOCK_HASH_COUNT,
@@ -952,31 +963,36 @@ function clearWalletRecoveryArtifacts(walletDir) {
952
963
  }
953
964
 
954
965
  async function handleInstallZkEvm({ args }) {
955
- const installArgs = [...tokamakCliBaseArgs, "--install"];
956
- if (args.docker) {
957
- installArgs.push("--docker");
958
- }
959
- run(tokamakCliCommand, installArgs);
960
- const tokamakRuntimeRoot = resolveTokamakCliRuntimeRoot();
961
- const groth16Runtime = installGroth16RuntimeForPrivateState({
966
+ const selectedVersions = await resolvePrivateStateInstallRuntimeVersions(args);
967
+ const tokamakCliRuntime = await installTokamakCliRuntimeForPrivateState({
968
+ version: selectedVersions.tokamak,
969
+ docker: Boolean(args.docker),
970
+ });
971
+ const groth16Runtime = await installGroth16RuntimeForPrivateState({
972
+ version: selectedVersions.groth16,
962
973
  docker: Boolean(args.docker),
963
974
  });
964
975
  const localDeploymentBaseRoot = args.includeLocalArtifacts ? process.cwd() : null;
965
976
  const deploymentArtifacts = await installPrivateStateCliArtifacts({
966
977
  dappName: PRIVATE_STATE_DAPP_LABEL,
967
978
  localDeploymentBaseRoot,
979
+ groth16CrsVersion: groth16Runtime.compatibleBackendVersion,
968
980
  });
969
981
  const installManifest = writePrivateStateCliInstallManifest({
970
982
  dockerRequested: Boolean(args.docker),
971
983
  includeLocalArtifacts: Boolean(args.includeLocalArtifacts),
972
984
  localDeploymentBaseRoot,
973
985
  deploymentArtifacts,
986
+ selectedVersions,
987
+ tokamakCliRuntime,
974
988
  groth16Runtime,
975
989
  });
976
990
  printJson({
977
991
  action: "install",
978
- tokamakCli: tokamakCliBaseArgs[0],
979
- runtimeRoot: tokamakRuntimeRoot,
992
+ selectedVersions,
993
+ tokamakCli: tokamakCliRuntime.entryPath,
994
+ runtimeRoot: tokamakCliRuntime.runtimeRoot,
995
+ tokamakCliRuntime,
980
996
  groth16Runtime,
981
997
  docker: Boolean(args.docker),
982
998
  includeLocalArtifacts: Boolean(args.includeLocalArtifacts),
@@ -996,12 +1012,13 @@ async function handleInstallZkEvm({ args }) {
996
1012
 
997
1013
  async function handleUninstallZkEvm() {
998
1014
  let runtimeRoot = null;
1015
+ const invocation = buildTokamakCliInvocationForPackageRoot();
999
1016
  try {
1000
- runtimeRoot = resolveTokamakCliRuntimeRoot();
1017
+ runtimeRoot = inspectTokamakCliRuntime({ packageRoot: invocation.packageRoot }).runtimeRoot;
1001
1018
  } catch {
1002
1019
  runtimeRoot = null;
1003
1020
  }
1004
- run(tokamakCliCommand, [...tokamakCliBaseArgs, "--uninstall"]);
1021
+ run(invocation.command, [...invocation.args, "--uninstall"], { cwd: invocation.packageRoot });
1005
1022
 
1006
1023
  printJson({
1007
1024
  action: "uninstall-zk-evm",
@@ -1309,10 +1326,16 @@ async function handleGrothVaultMove({ args, provider, direction }) {
1309
1326
  const contextResult = await loadPreferredWalletChannelContext({ walletContext, provider });
1310
1327
  const context = contextResult.context;
1311
1328
  const network = contextResult.network;
1329
+ const operationName = args.command === "withdraw-channel"
1330
+ ? "withdraw-channel"
1331
+ : direction === "deposit"
1332
+ ? "deposit-channel"
1333
+ : "withdraw";
1312
1334
  expect(
1313
1335
  ethers.toBigInt(walletContext.wallet.channelId) === ethers.toBigInt(context.workspace.channelId),
1314
1336
  "The provided wallet does not belong to the selected channel.",
1315
1337
  );
1338
+ await assertChannelProofBackendVersionCompatibility({ context, operationName });
1316
1339
 
1317
1340
  const { signer, l2Identity } = restoreWalletParticipant(walletContext, provider);
1318
1341
  const amountInput = requireArg(args.amount, "--amount");
@@ -1364,11 +1387,6 @@ async function handleGrothVaultMove({ args, provider, direction }) {
1364
1387
  nextValue = currentValue - amount;
1365
1388
  }
1366
1389
 
1367
- const operationName = args.command === "withdraw-channel"
1368
- ? "withdraw-channel"
1369
- : direction === "deposit"
1370
- ? "deposit-channel"
1371
- : "withdraw";
1372
1390
  const operationDir = createWalletOperationDir(
1373
1391
  walletContext.walletName,
1374
1392
  walletContext.wallet.network,
@@ -3057,6 +3075,7 @@ async function executeWalletTemplateSend({
3057
3075
  }) {
3058
3076
  await assertWorkspaceAlignedWithChain(context, signer.provider);
3059
3077
  assertWalletMatchesChannelContext(wallet, l2Identity, context);
3078
+ await assertChannelProofBackendVersionCompatibility({ context, operationName });
3060
3079
 
3061
3080
  const controllerAbi = readJson(
3062
3081
  requireLatestDappDeployArtifactPath(context.workspace.chainId, path.basename(templatePayload.abiFile)),
@@ -3428,6 +3447,145 @@ async function assertWorkspaceAlignedWithChain(context) {
3428
3447
  );
3429
3448
  }
3430
3449
 
3450
+ async function assertChannelProofBackendVersionCompatibility({ context, operationName }) {
3451
+ const channelVersions = await readChannelVerifierCompatibleBackendVersions(context);
3452
+ const localVersions = readLocalProofBackendPackageVersions();
3453
+ const checks = [
3454
+ {
3455
+ label: "Groth16",
3456
+ packageName: GROTH16_PACKAGE_NAME,
3457
+ versionKind: "compatible backend version",
3458
+ channelVersion: requireCanonicalGroth16CompatibleBackendVersion(
3459
+ channelVersions.groth16,
3460
+ "channel Groth16 verifier compatibleBackendVersion",
3461
+ ),
3462
+ localVersion: localVersions.groth16.compatibleBackendVersion,
3463
+ },
3464
+ {
3465
+ label: "Tokamak zk-EVM",
3466
+ packageName: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
3467
+ versionKind: "compatible backend version",
3468
+ channelVersion: requireCanonicalCompatibleBackendVersion(
3469
+ channelVersions.tokamak,
3470
+ "channel Tokamak verifier compatibleBackendVersion",
3471
+ ),
3472
+ localVersion: localVersions.tokamak.compatibleBackendVersion,
3473
+ },
3474
+ ];
3475
+ const mismatches = checks.filter(({ channelVersion, localVersion }) => channelVersion !== localVersion);
3476
+ if (mismatches.length === 0) {
3477
+ return;
3478
+ }
3479
+
3480
+ throw new Error(
3481
+ [
3482
+ `Channel proof backend version mismatch before ${operationName} proof generation.`,
3483
+ `Channel: ${context.workspace.channelName ?? context.workspaceName ?? context.workspace.channelId}.`,
3484
+ ...mismatches.map(({ label, packageName, versionKind, channelVersion, localVersion }) => (
3485
+ `${label} verifier expects ${packageName} ${versionKind} ${channelVersion}, `
3486
+ + `but the local installed ${versionKind} is ${localVersion ?? "<missing>"}.`
3487
+ )),
3488
+ "Install proof backend runtimes compatible with this channel before generating proofs.",
3489
+ ].join(" "),
3490
+ );
3491
+ }
3492
+
3493
+ async function readChannelVerifierCompatibleBackendVersions(context) {
3494
+ const channelManagerAddress = getAddress(context.workspace.channelManager);
3495
+ const channelManager = new Contract(
3496
+ channelManagerAddress,
3497
+ channelVerifierVersionAbi,
3498
+ context.channelManager.runner,
3499
+ );
3500
+ try {
3501
+ const [groth16, tokamak] = await Promise.all([
3502
+ channelManager.grothVerifierCompatibleBackendVersion(),
3503
+ channelManager.tokamakVerifierCompatibleBackendVersion(),
3504
+ ]);
3505
+ return {
3506
+ groth16: requireVersionString(groth16, "channel Groth16 verifier compatibleBackendVersion"),
3507
+ tokamak: requireVersionString(tokamak, "channel Tokamak verifier compatibleBackendVersion"),
3508
+ };
3509
+ } catch (error) {
3510
+ throw new Error(
3511
+ [
3512
+ `Unable to read verifier compatibleBackendVersion values from channel manager ${channelManagerAddress}.`,
3513
+ "The target channel must expose grothVerifierCompatibleBackendVersion() and tokamakVerifierCompatibleBackendVersion().",
3514
+ ].join(" "),
3515
+ { cause: error },
3516
+ );
3517
+ }
3518
+ }
3519
+
3520
+ function readLocalProofBackendPackageVersions() {
3521
+ const groth16Runtime = inspectGroth16Runtime();
3522
+ const tokamakPackageReport = readTokamakCliPackageReport();
3523
+ return {
3524
+ groth16: {
3525
+ packageVersion: groth16Runtime.packageVersion,
3526
+ compatibleBackendVersion: groth16Runtime.crsCompatibleBackendVersion
3527
+ ?? groth16Runtime.compatibleBackendVersion,
3528
+ },
3529
+ tokamak: {
3530
+ packageVersion: requirePackageReportVersion(tokamakPackageReport),
3531
+ compatibleBackendVersion: requirePackageReportCompatibleBackendVersion(tokamakPackageReport),
3532
+ },
3533
+ };
3534
+ }
3535
+
3536
+ function readTokamakCliPackageReport(packageRoot = null) {
3537
+ try {
3538
+ const resolvedPackageRoot = packageRoot ?? resolveActiveTokamakCliPackageRoot();
3539
+ const packageJsonPath = path.join(resolvedPackageRoot, "package.json");
3540
+ const packageJson = readJson(packageJsonPath);
3541
+ const report = readPackageReport({
3542
+ name: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
3543
+ packageJsonPath,
3544
+ packageJson,
3545
+ });
3546
+ return {
3547
+ ...report,
3548
+ compatibleBackendVersion: readTokamakZkEvmCompatibleBackendVersionFromPackageJson(
3549
+ packageJson,
3550
+ TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
3551
+ ),
3552
+ };
3553
+ } catch (error) {
3554
+ return {
3555
+ name: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
3556
+ version: null,
3557
+ packageRoot: null,
3558
+ compatibleBackendVersion: null,
3559
+ error: error.message,
3560
+ ok: false,
3561
+ };
3562
+ }
3563
+ }
3564
+
3565
+ function requirePackageReportVersion(report) {
3566
+ if (!report.version) {
3567
+ throw new Error(
3568
+ `Unable to determine local ${report.name} package version${report.error ? `: ${report.error}` : "."}`,
3569
+ );
3570
+ }
3571
+ return requireVersionString(report.version, `${report.name} package version`);
3572
+ }
3573
+
3574
+ function requirePackageReportCompatibleBackendVersion(report) {
3575
+ if (!report.compatibleBackendVersion) {
3576
+ throw new Error(
3577
+ `Unable to determine local ${report.name} compatible backend version${report.error ? `: ${report.error}` : "."}`,
3578
+ );
3579
+ }
3580
+ return requireVersionString(report.compatibleBackendVersion, `${report.name} compatible backend version`);
3581
+ }
3582
+
3583
+ function requireVersionString(value, label) {
3584
+ const normalized = String(value ?? "").trim();
3585
+ expect(normalized.length > 0, `${label} is missing.`);
3586
+ return normalized;
3587
+ }
3588
+
3431
3589
  async function buildGrothTransition({ operationDir, workspace, stateManager, vaultAddress, keyHex, nextValue }) {
3432
3590
  const vaultAddressObj = createAddressFromString(vaultAddress);
3433
3591
  const keyBigInt = ethers.toBigInt(keyHex);
@@ -3504,7 +3662,7 @@ function runCaptured(command, args, { cwd = defaultCommandCwd, env = process.env
3504
3662
  }
3505
3663
 
3506
3664
  function runGroth16UpdateTreeProof(inputPath) {
3507
- const packageRoot = resolveGroth16PackageRoot();
3665
+ const packageRoot = resolveActiveGroth16PackageRoot();
3508
3666
  const entryPath = resolveGroth16CliEntryPath(packageRoot);
3509
3667
  run(process.execPath, [entryPath, "--prove", inputPath], { cwd: packageRoot });
3510
3668
  const manifestPath = groth16ProofManifestPath();
@@ -3557,7 +3715,8 @@ function printLocalProofGenerationNotice(operationName) {
3557
3715
  }
3558
3716
 
3559
3717
  function runTokamakCliStage({ operationDir, stageName, args }) {
3560
- const result = runCaptured(tokamakCliCommand, [...tokamakCliBaseArgs, ...args]);
3718
+ const invocation = buildTokamakCliInvocationForPackageRoot();
3719
+ const result = runCaptured(invocation.command, [...invocation.args, ...args], { cwd: invocation.packageRoot });
3561
3720
  const logPath = writeTokamakCliStageLog(operationDir, stageName, result);
3562
3721
  if (result.status !== 0) {
3563
3722
  throw new Error(
@@ -3616,6 +3775,7 @@ function findTokamakConsoleError({ stdout, stderr }) {
3616
3775
  function copyTokamakOperationArtifacts(operationDir) {
3617
3776
  const resourceRoot = path.join(operationDir, "resource");
3618
3777
  fs.rmSync(resourceRoot, { recursive: true, force: true });
3778
+ const runtimeRoot = requireActiveTokamakCliRuntimeRoot();
3619
3779
 
3620
3780
  const requiredFiles = [
3621
3781
  ["preprocess", "output", "preprocess.json"],
@@ -3625,7 +3785,7 @@ function copyTokamakOperationArtifacts(operationDir) {
3625
3785
  ];
3626
3786
 
3627
3787
  for (const segments of requiredFiles) {
3628
- const sourcePath = resolveTokamakCliResourceDir(...segments);
3788
+ const sourcePath = resolveTokamakCliResourceDirForRuntimeRoot(runtimeRoot, ...segments);
3629
3789
  const targetPath = path.join(resourceRoot, ...segments);
3630
3790
  ensureDir(path.dirname(targetPath));
3631
3791
  fs.copyFileSync(sourcePath, targetPath);
@@ -3747,10 +3907,6 @@ function normalizeBytes16Hex(value) {
3747
3907
  return normalizeBytesHex(value, 16);
3748
3908
  }
3749
3909
 
3750
- function normalizeBytes20Hex(value) {
3751
- return normalizeBytesHex(value, 20);
3752
- }
3753
-
3754
3910
  function normalizeBytes32Hex(hexValue) {
3755
3911
  return normalizeBytesHex(hexValue, 32);
3756
3912
  }
@@ -4589,9 +4745,23 @@ function assertInstallZkEvmArgs(args) {
4589
4745
  assertAllowedCommandKeys(
4590
4746
  args,
4591
4747
  "--install",
4592
- new Set(["command", "positional", "install", "docker", "includeLocalArtifacts"]),
4593
- "optional --docker and --include-local-artifacts",
4748
+ new Set([
4749
+ "command",
4750
+ "positional",
4751
+ "install",
4752
+ "docker",
4753
+ "includeLocalArtifacts",
4754
+ "groth16CliVersion",
4755
+ "tokamakZkEvmCliVersion",
4756
+ ]),
4757
+ "optional --docker, --include-local-artifacts, --groth16-cli-version, and --tokamak-zk-evm-cli-version",
4594
4758
  );
4759
+ if (args.groth16CliVersion !== undefined) {
4760
+ requireSemverVersion(args.groth16CliVersion, "--groth16-cli-version");
4761
+ }
4762
+ if (args.tokamakZkEvmCliVersion !== undefined) {
4763
+ requireSemverVersion(args.tokamakZkEvmCliVersion, "--tokamak-zk-evm-cli-version");
4764
+ }
4595
4765
  }
4596
4766
 
4597
4767
  function assertUninstallZkEvmArgs(args) {
@@ -4801,8 +4971,9 @@ function persistCurrentState(context) {
4801
4971
  function printHelp() {
4802
4972
  console.log(`
4803
4973
  Commands:
4804
- --install [--docker] [--include-local-artifacts]
4974
+ --install [--docker] [--include-local-artifacts] [--groth16-cli-version <VERSION>] [--tokamak-zk-evm-cli-version <VERSION>]
4805
4975
  Install the Tokamak zk-EVM CLI runtime, Groth16 runtime, and private-state deployment artifacts
4976
+ Version options install exact CLI package versions; omitted versions resolve to npm registry latest
4806
4977
  Use --docker on Linux to forward Docker mode to the Tokamak zk-EVM and Groth16 runtimes
4807
4978
  Use --include-local-artifacts to also install local deployment/ artifacts from the current working directory
4808
4979
 
@@ -5065,6 +5236,10 @@ function expect(condition, message) {
5065
5236
  }
5066
5237
  }
5067
5238
 
5239
+ function requireSemverVersion(value, label) {
5240
+ return requireExactSemverVersion(value, label);
5241
+ }
5242
+
5068
5243
  function resolveArtifactCacheBaseRoot(
5069
5244
  cacheBaseRoot = process.env.PRIVATE_STATE_ARTIFACT_CACHE_ROOT
5070
5245
  ?? process.env.TOKAMAK_PRIVATE_CHANNELS_ROOT
@@ -5077,6 +5252,10 @@ function privateStateCliArtifactRoot(cacheBaseRoot = resolveArtifactCacheBaseRoo
5077
5252
  return path.join(resolveArtifactCacheBaseRoot(cacheBaseRoot), "dapps", "private-state");
5078
5253
  }
5079
5254
 
5255
+ function privateStateCliRuntimeRoot(cacheBaseRoot = resolveArtifactCacheBaseRoot()) {
5256
+ return path.join(privateStateCliArtifactRoot(cacheBaseRoot), "runtimes");
5257
+ }
5258
+
5080
5259
  function privateStateCliArtifactChainDir(cacheBaseRoot = resolveArtifactCacheBaseRoot(), chainId) {
5081
5260
  return path.join(privateStateCliArtifactRoot(cacheBaseRoot), `chain-id-${requireChainId(chainId)}`);
5082
5261
  }
@@ -5101,11 +5280,17 @@ function privateStateCliInstallManifestPath(cacheBaseRoot = resolveArtifactCache
5101
5280
  return path.join(privateStateCliArtifactRoot(cacheBaseRoot), "install-manifest.json");
5102
5281
  }
5103
5282
 
5283
+ function readPrivateStateCliInstallManifest(cacheBaseRoot = resolveArtifactCacheBaseRoot()) {
5284
+ return readJsonIfExists(privateStateCliInstallManifestPath(cacheBaseRoot));
5285
+ }
5286
+
5104
5287
  function writePrivateStateCliInstallManifest({
5105
5288
  dockerRequested,
5106
5289
  includeLocalArtifacts,
5107
5290
  localDeploymentBaseRoot,
5108
5291
  deploymentArtifacts,
5292
+ selectedVersions,
5293
+ tokamakCliRuntime,
5109
5294
  groth16Runtime,
5110
5295
  }) {
5111
5296
  const manifestPath = privateStateCliInstallManifestPath(deploymentArtifacts.cacheBaseRoot);
@@ -5121,6 +5306,8 @@ function writePrivateStateCliInstallManifest({
5121
5306
  includeLocalArtifacts,
5122
5307
  localDeploymentBaseRoot,
5123
5308
  artifactCacheRoot: deploymentArtifacts.cacheBaseRoot,
5309
+ selectedVersions,
5310
+ tokamakCliRuntime,
5124
5311
  groth16Runtime,
5125
5312
  installedDeploymentArtifacts: deploymentArtifacts.installed.map((entry) => ({
5126
5313
  chainId: entry.chainId,
@@ -5149,6 +5336,11 @@ function buildDoctorReport() {
5149
5336
  const tokamakCli = inspectTokamakCliRuntime();
5150
5337
  const groth16Runtime = inspectGroth16Runtime();
5151
5338
  const gpuDockerReadiness = inspectGpuDockerReadiness(tokamakCli);
5339
+ const selectedRuntimeVersionCheck = buildSelectedRuntimeVersionCheck({
5340
+ installManifest,
5341
+ tokamakCli,
5342
+ groth16Runtime,
5343
+ });
5152
5344
  const checks = [
5153
5345
  {
5154
5346
  name: "dependency package versions",
@@ -5161,6 +5353,7 @@ function buildDoctorReport() {
5161
5353
  error: entry.error,
5162
5354
  })),
5163
5355
  },
5356
+ selectedRuntimeVersionCheck,
5164
5357
  {
5165
5358
  name: "tokamak zk-evm runtime",
5166
5359
  ok: tokamakCli.installed,
@@ -5214,6 +5407,9 @@ function buildDoctorReport() {
5214
5407
  installedAt: installManifest?.installedAt ?? null,
5215
5408
  dockerRequested: installManifest?.install?.dockerRequested ?? null,
5216
5409
  includeLocalArtifacts: installManifest?.install?.includeLocalArtifacts ?? null,
5410
+ selectedVersions: installManifest?.install?.selectedVersions ?? null,
5411
+ tokamakCliRuntime: installManifest?.install?.tokamakCliRuntime ?? null,
5412
+ groth16Runtime: installManifest?.install?.groth16Runtime ?? null,
5217
5413
  },
5218
5414
  dependencies: dependencyReports,
5219
5415
  tokamakCli,
@@ -5223,17 +5419,221 @@ function buildDoctorReport() {
5223
5419
  };
5224
5420
  }
5225
5421
 
5226
- function installGroth16RuntimeForPrivateState({ docker }) {
5227
- const packageRoot = resolveGroth16PackageRoot();
5422
+ function buildSelectedRuntimeVersionCheck({ installManifest, tokamakCli, groth16Runtime }) {
5423
+ const selectedVersions = installManifest?.install?.selectedVersions ?? null;
5424
+ const selectedTokamakCompatibleBackendVersion = selectedVersions?.tokamak
5425
+ ? normalizePackageVersionToCompatibleBackendVersion(
5426
+ selectedVersions.tokamak,
5427
+ "selected Tokamak zk-EVM CLI version",
5428
+ )
5429
+ : null;
5430
+ const selectedGroth16CompatibleBackendVersion = selectedVersions?.groth16
5431
+ ? normalizePackageVersionToCompatibleBackendVersion(selectedVersions.groth16, "selected Groth16 CLI version")
5432
+ : null;
5433
+ const details = [
5434
+ {
5435
+ name: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
5436
+ selectedVersion: selectedVersions?.tokamak ?? null,
5437
+ selectedCompatibleBackendVersion: selectedTokamakCompatibleBackendVersion,
5438
+ installedVersion: tokamakCli.packageVersion ?? null,
5439
+ compatibleBackendVersion: tokamakCli.compatibleBackendVersion ?? null,
5440
+ ok: !selectedVersions?.tokamak
5441
+ || (
5442
+ selectedVersions.tokamak === tokamakCli.packageVersion
5443
+ && selectedTokamakCompatibleBackendVersion === tokamakCli.compatibleBackendVersion
5444
+ ),
5445
+ },
5446
+ {
5447
+ name: GROTH16_PACKAGE_NAME,
5448
+ selectedVersion: selectedVersions?.groth16 ?? null,
5449
+ selectedCompatibleBackendVersion: selectedGroth16CompatibleBackendVersion,
5450
+ installedVersion: groth16Runtime.packageVersion ?? null,
5451
+ compatibleBackendVersion: groth16Runtime.compatibleBackendVersion ?? null,
5452
+ crsVersion: groth16Runtime.crsVersion ?? null,
5453
+ crsCompatibleBackendVersion: groth16Runtime.crsCompatibleBackendVersion ?? null,
5454
+ ok: !selectedVersions?.groth16
5455
+ || (
5456
+ selectedVersions.groth16 === groth16Runtime.packageVersion
5457
+ && selectedGroth16CompatibleBackendVersion === groth16Runtime.compatibleBackendVersion
5458
+ && selectedGroth16CompatibleBackendVersion === groth16Runtime.crsCompatibleBackendVersion
5459
+ ),
5460
+ },
5461
+ ];
5462
+ return {
5463
+ name: "selected proof backend runtime versions",
5464
+ ok: details.every((entry) => entry.ok),
5465
+ details,
5466
+ };
5467
+ }
5468
+
5469
+ async function resolvePrivateStateInstallRuntimeVersions(args) {
5470
+ const [groth16, tokamak] = await Promise.all([
5471
+ resolveRequestedNpmPackageVersion({
5472
+ packageName: GROTH16_PACKAGE_NAME,
5473
+ requestedVersion: args.groth16CliVersion,
5474
+ optionName: "--groth16-cli-version",
5475
+ }),
5476
+ resolveRequestedNpmPackageVersion({
5477
+ packageName: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
5478
+ requestedVersion: args.tokamakZkEvmCliVersion,
5479
+ optionName: "--tokamak-zk-evm-cli-version",
5480
+ }),
5481
+ ]);
5482
+ return { groth16, tokamak };
5483
+ }
5484
+
5485
+ async function resolveRequestedNpmPackageVersion({ packageName, requestedVersion, optionName }) {
5486
+ const metadata = await fetchNpmPackageMetadata(packageName);
5487
+ if (requestedVersion === undefined || requestedVersion === null) {
5488
+ return requireSemverVersion(metadata?.["dist-tags"]?.latest, `${packageName} npm latest version`);
5489
+ }
5490
+
5491
+ const normalizedVersion = requireSemverVersion(requestedVersion, optionName);
5492
+ if (!metadata.versions?.[normalizedVersion]) {
5493
+ throw new Error(`npm package ${packageName} does not contain version ${normalizedVersion}.`);
5494
+ }
5495
+ return normalizedVersion;
5496
+ }
5497
+
5498
+ async function installTokamakCliRuntimeForPrivateState({ version, docker }) {
5499
+ const packageInstall = installManagedNpmPackage({
5500
+ packageName: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
5501
+ version,
5502
+ });
5503
+ const invocation = buildTokamakCliInvocationForPackageRoot(packageInstall.packageRoot);
5504
+ const installArgs = [...invocation.args, "--install"];
5505
+ if (docker) {
5506
+ installArgs.push("--docker");
5507
+ }
5508
+ run(invocation.command, installArgs, { cwd: packageInstall.packageRoot });
5509
+ const doctor = runCaptured(invocation.command, [...invocation.args, "--doctor"], {
5510
+ cwd: packageInstall.packageRoot,
5511
+ });
5512
+ const doctorOutput = stripAnsi(`${doctor.stdout}${doctor.stderr}`);
5513
+ const runtimeRoot = parseRuntimeRootFromTokamakDoctorOutput(doctorOutput);
5514
+ const compatibleBackendVersion = readTokamakCliPackageCompatibleBackendVersion(packageInstall.packageRoot);
5515
+ expect(
5516
+ doctor.status === 0 && runtimeRoot,
5517
+ [
5518
+ "Tokamak zk-EVM CLI install completed, but tokamak-cli --doctor did not report a healthy runtime.",
5519
+ doctorOutput.trim(),
5520
+ ].filter(Boolean).join(" "),
5521
+ );
5522
+ return {
5523
+ packageName: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
5524
+ packageVersion: version,
5525
+ compatibleBackendVersion,
5526
+ packageRoot: packageInstall.packageRoot,
5527
+ entryPath: invocation.entryPath,
5528
+ installPrefix: packageInstall.installPrefix,
5529
+ runtimeRoot,
5530
+ dockerRequested: Boolean(docker),
5531
+ };
5532
+ }
5533
+
5534
+ async function installGroth16RuntimeForPrivateState({ version, docker }) {
5535
+ const packageInstall = installManagedNpmPackage({
5536
+ packageName: GROTH16_PACKAGE_NAME,
5537
+ version,
5538
+ });
5539
+ const packageRoot = packageInstall.packageRoot;
5228
5540
  const entryPath = resolveGroth16CliEntryPath(packageRoot);
5229
- const args = [entryPath, "--install"];
5541
+ const args = [entryPath, "--install", "--no-setup"];
5230
5542
  if (docker) {
5231
5543
  args.push("--docker");
5232
5544
  }
5233
5545
  run(process.execPath, args, { cwd: packageRoot });
5234
- const runtime = inspectGroth16Runtime();
5546
+ const compatibleBackendVersion = readGroth16PackageCompatibleBackendVersion(packageRoot);
5547
+ const crsInstall = await installGroth16CrsForPrivateStateVersion(compatibleBackendVersion);
5548
+ const runtime = inspectGroth16Runtime({ packageRoot });
5235
5549
  expect(runtime.installed, "Groth16 runtime install completed, but tokamak-groth16 --doctor still reports an unhealthy runtime.");
5236
- return runtime;
5550
+ return {
5551
+ ...runtime,
5552
+ packageName: GROTH16_PACKAGE_NAME,
5553
+ packageVersion: version,
5554
+ compatibleBackendVersion,
5555
+ packageRoot,
5556
+ entryPath,
5557
+ installPrefix: packageInstall.installPrefix,
5558
+ crsVersion: crsInstall.version,
5559
+ crs: crsInstall,
5560
+ dockerRequested: Boolean(docker),
5561
+ };
5562
+ }
5563
+
5564
+ async function installGroth16CrsForPrivateStateVersion(version) {
5565
+ const workspaceRoot = defaultGroth16WorkspaceRoot();
5566
+ const crsDir = path.join(workspaceRoot, "crs");
5567
+ const crsInstall = await downloadPublicGroth16MpcArtifactsByVersion({
5568
+ version,
5569
+ outputDir: crsDir,
5570
+ selectedFiles: [
5571
+ "circuit_final.zkey",
5572
+ "verification_key.json",
5573
+ "metadata.json",
5574
+ "zkey_provenance.json",
5575
+ ],
5576
+ });
5577
+ const manifestPath = path.join(workspaceRoot, "install-manifest.json");
5578
+ const manifest = readJsonIfExists(manifestPath) ?? {};
5579
+ writeJson(manifestPath, {
5580
+ ...manifest,
5581
+ workspaceRoot,
5582
+ crsSource: "public-drive-mpc",
5583
+ crs: crsInstall,
5584
+ });
5585
+ return crsInstall;
5586
+ }
5587
+
5588
+ function installManagedNpmPackage({ packageName, version, cacheBaseRoot = resolveArtifactCacheBaseRoot() }) {
5589
+ const normalizedPackageName = requireNonEmptyString(packageName, "packageName");
5590
+ const normalizedVersion = requireSemverVersion(version, `${normalizedPackageName} version`);
5591
+ const installPrefix = managedNpmPackageInstallPrefix({
5592
+ packageName: normalizedPackageName,
5593
+ version: normalizedVersion,
5594
+ cacheBaseRoot,
5595
+ });
5596
+ fs.mkdirSync(installPrefix, { recursive: true });
5597
+ run("npm", [
5598
+ "install",
5599
+ "--prefix",
5600
+ installPrefix,
5601
+ "--omit=dev",
5602
+ "--no-audit",
5603
+ "--fund=false",
5604
+ `${normalizedPackageName}@${normalizedVersion}`,
5605
+ ]);
5606
+ const packageRoot = path.join(installPrefix, "node_modules", ...normalizedPackageName.split("/"));
5607
+ const packageJsonPath = path.join(packageRoot, "package.json");
5608
+ const packageJson = readJson(packageJsonPath);
5609
+ expect(
5610
+ packageJson.name === normalizedPackageName && packageJson.version === normalizedVersion,
5611
+ `Installed package ${packageJsonPath} does not match ${normalizedPackageName}@${normalizedVersion}.`,
5612
+ );
5613
+ return {
5614
+ packageName: normalizedPackageName,
5615
+ version: normalizedVersion,
5616
+ installPrefix,
5617
+ packageRoot,
5618
+ };
5619
+ }
5620
+
5621
+ function managedNpmPackageInstallPrefix({ packageName, version, cacheBaseRoot = resolveArtifactCacheBaseRoot() }) {
5622
+ const safePackageName = requireNonEmptyString(packageName, "packageName")
5623
+ .replace(/^@/, "")
5624
+ .replace(/[^A-Za-z0-9._-]+/g, "__");
5625
+ return path.join(privateStateCliRuntimeRoot(cacheBaseRoot), "npm", safePackageName, requireSemverVersion(version, "version"));
5626
+ }
5627
+
5628
+ async function downloadGroth16CrsArtifactsForPrivateState({
5629
+ version,
5630
+ outputDir,
5631
+ selectedFiles,
5632
+ }) {
5633
+ if (version === undefined || version === null) {
5634
+ return downloadLatestPublicGroth16MpcArtifacts({ outputDir, selectedFiles });
5635
+ }
5636
+ return downloadPublicGroth16MpcArtifactsByVersion({ version, outputDir, selectedFiles });
5237
5637
  }
5238
5638
 
5239
5639
  function collectDependencyPackageReports(installManifest = null) {
@@ -5244,11 +5644,11 @@ function collectDependencyPackageReports(installManifest = null) {
5244
5644
  );
5245
5645
  const targets = [
5246
5646
  {
5247
- name: "@tokamak-zk-evm/cli",
5248
- packageJsonPath: path.join(resolveTokamakCliPackageRoot(), "package.json"),
5647
+ name: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
5648
+ packageJsonPath: path.join(resolveBundledTokamakCliPackageRoot(), "package.json"),
5249
5649
  },
5250
5650
  {
5251
- name: "@tokamak-private-dapps/groth16",
5651
+ name: GROTH16_PACKAGE_NAME,
5252
5652
  resolveTarget: "@tokamak-private-dapps/groth16/public-drive-crs",
5253
5653
  },
5254
5654
  {
@@ -5269,15 +5669,15 @@ function collectDependencyPackageReports(installManifest = null) {
5269
5669
  });
5270
5670
  }
5271
5671
 
5272
- function readPackageReport({ name, packageJsonPath = null, resolveTarget = null }) {
5672
+ function readPackageReport({ name, packageJsonPath = null, packageJson = null, resolveTarget = null }) {
5273
5673
  try {
5274
5674
  const resolvedPackageJsonPath = packageJsonPath
5275
5675
  ? path.resolve(packageJsonPath)
5276
5676
  : findPackageJsonForName(path.dirname(require.resolve(resolveTarget ?? name)), name);
5277
- const packageJson = readJson(resolvedPackageJsonPath);
5677
+ const resolvedPackageJson = packageJson ?? readJson(resolvedPackageJsonPath);
5278
5678
  return {
5279
- name: packageJson.name ?? name,
5280
- version: packageJson.version ?? null,
5679
+ name: resolvedPackageJson.name ?? name,
5680
+ version: resolvedPackageJson.version ?? null,
5281
5681
  packageRoot: path.dirname(resolvedPackageJsonPath),
5282
5682
  error: null,
5283
5683
  };
@@ -5312,21 +5712,63 @@ function resolveGroth16PackageRoot() {
5312
5712
  return path.dirname(findPackageJsonForName(path.dirname(publicDriveCrsPath), "@tokamak-private-dapps/groth16"));
5313
5713
  }
5314
5714
 
5715
+ function readGroth16PackageCompatibleBackendVersion(packageRoot = resolveActiveGroth16PackageRoot()) {
5716
+ return readGroth16CompatibleBackendVersionFromPackageJson(
5717
+ readJson(path.join(packageRoot, "package.json")),
5718
+ GROTH16_PACKAGE_NAME,
5719
+ );
5720
+ }
5721
+
5722
+ function readTokamakCliPackageCompatibleBackendVersion(packageRoot = resolveActiveTokamakCliPackageRoot()) {
5723
+ return readTokamakZkEvmCompatibleBackendVersionFromPackageJson(
5724
+ readJson(path.join(packageRoot, "package.json")),
5725
+ TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
5726
+ );
5727
+ }
5728
+
5729
+ function resolveActiveGroth16PackageRoot() {
5730
+ const manifestPackageRoot = readPrivateStateCliInstallManifest()?.install?.groth16Runtime?.packageRoot;
5731
+ if (manifestPackageRoot && fs.existsSync(path.join(manifestPackageRoot, "package.json"))) {
5732
+ return manifestPackageRoot;
5733
+ }
5734
+ return resolveGroth16PackageRoot();
5735
+ }
5736
+
5315
5737
  function resolveGroth16CliEntryPath(packageRoot = resolveGroth16PackageRoot()) {
5316
5738
  return path.join(packageRoot, "cli", "tokamak-groth16-cli.mjs");
5317
5739
  }
5318
5740
 
5319
- function inspectGroth16Runtime() {
5320
- const packageRoot = resolveGroth16PackageRoot();
5741
+ function defaultGroth16WorkspaceRoot() {
5742
+ return path.join(os.homedir(), "tokamak-private-channels", "groth16");
5743
+ }
5744
+
5745
+ function inspectGroth16Runtime({ packageRoot = resolveActiveGroth16PackageRoot() } = {}) {
5321
5746
  const entryPath = resolveGroth16CliEntryPath(packageRoot);
5322
5747
  const doctor = runCaptured(process.execPath, [entryPath, "--doctor", "--verbose"], { cwd: packageRoot });
5323
5748
  const stdout = stripAnsi(doctor.stdout).trim();
5324
5749
  const stderr = stripAnsi(doctor.stderr).trim();
5325
5750
  const report = parseJsonReport(stdout);
5751
+ const workspaceRoot = report?.workspaceRoot ?? defaultGroth16WorkspaceRoot();
5752
+ const workspaceManifest = readJsonIfExists(path.join(workspaceRoot, "install-manifest.json"));
5753
+ const crsVersion = workspaceManifest?.crs?.version ?? null;
5754
+ const packageReport = readPackageReport({
5755
+ name: GROTH16_PACKAGE_NAME,
5756
+ packageJsonPath: path.join(packageRoot, "package.json"),
5757
+ });
5758
+ const compatibleBackendVersion = readGroth16PackageCompatibleBackendVersion(packageRoot);
5759
+ const crsCompatibleBackendVersion = crsVersion
5760
+ ? requireCanonicalGroth16CompatibleBackendVersion(crsVersion, "installed Groth16 CRS version")
5761
+ : null;
5326
5762
  return {
5327
5763
  installed: doctor.status === 0 && report?.ok === true,
5764
+ packageVersion: packageReport.version,
5765
+ compatibleBackendVersion,
5328
5766
  packageRoot,
5767
+ entryPath,
5329
5768
  workspaceRoot: report?.workspaceRoot ?? null,
5769
+ crsVersion,
5770
+ crsCompatibleBackendVersion,
5771
+ crs: workspaceManifest?.crs ?? null,
5330
5772
  checks: report?.checks ?? [],
5331
5773
  doctor: {
5332
5774
  status: doctor.status,
@@ -5336,9 +5778,42 @@ function inspectGroth16Runtime() {
5336
5778
  };
5337
5779
  }
5338
5780
 
5339
- function inspectTokamakCliRuntime() {
5340
- const doctor = runCaptured(tokamakCliCommand, [...tokamakCliBaseArgs, "--doctor"], {
5341
- cwd: resolveTokamakCliPackageRoot(),
5781
+ function resolveActiveTokamakCliPackageRoot() {
5782
+ const manifestPackageRoot = readPrivateStateCliInstallManifest()?.install?.tokamakCliRuntime?.packageRoot;
5783
+ if (manifestPackageRoot && fs.existsSync(path.join(manifestPackageRoot, "package.json"))) {
5784
+ return manifestPackageRoot;
5785
+ }
5786
+ return resolveBundledTokamakCliPackageRoot();
5787
+ }
5788
+
5789
+ function buildTokamakCliInvocationForPackageRoot(packageRoot = resolveActiveTokamakCliPackageRoot()) {
5790
+ const resolvedPackageRoot = path.resolve(packageRoot);
5791
+ const entryPath = resolvedPackageRoot === resolveBundledTokamakCliPackageRoot()
5792
+ ? resolveTokamakCliEntryPath()
5793
+ : path.join(resolvedPackageRoot, "dist", "cli.js");
5794
+ return {
5795
+ command: process.execPath,
5796
+ args: [entryPath],
5797
+ entryPath,
5798
+ packageRoot: resolvedPackageRoot,
5799
+ };
5800
+ }
5801
+
5802
+ function resolveTokamakCliResourceDirForRuntimeRoot(runtimeRoot, ...segments) {
5803
+ return path.join(runtimeRoot, "resource", ...segments);
5804
+ }
5805
+
5806
+ function requireActiveTokamakCliRuntimeRoot() {
5807
+ const runtime = inspectTokamakCliRuntime();
5808
+ expect(runtime.runtimeRoot, "Unable to resolve the installed Tokamak zk-EVM runtime root. Run --install first.");
5809
+ return runtime.runtimeRoot;
5810
+ }
5811
+
5812
+ function inspectTokamakCliRuntime({ packageRoot = resolveActiveTokamakCliPackageRoot() } = {}) {
5813
+ const invocation = buildTokamakCliInvocationForPackageRoot(packageRoot);
5814
+ const packageReport = readTokamakCliPackageReport(invocation.packageRoot);
5815
+ const doctor = runCaptured(invocation.command, [...invocation.args, "--doctor"], {
5816
+ cwd: invocation.packageRoot,
5342
5817
  });
5343
5818
  const doctorOutput = stripAnsi(`${doctor.stdout}${doctor.stderr}`);
5344
5819
  const runtimeRoot = parseRuntimeRootFromTokamakDoctorOutput(doctorOutput);
@@ -5349,13 +5824,13 @@ function inspectTokamakCliRuntime() {
5349
5824
 
5350
5825
  return {
5351
5826
  installed: doctor.status === 0 || installations.length > 0,
5352
- packageRoot: resolveTokamakCliPackageRoot(),
5827
+ packageRoot: invocation.packageRoot,
5828
+ entryPath: invocation.entryPath,
5353
5829
  cacheRoot,
5354
5830
  runtimeRoot,
5355
- packageVersion: readPackageReport({
5356
- name: "@tokamak-zk-evm/cli",
5357
- packageJsonPath: path.join(resolveTokamakCliPackageRoot(), "package.json"),
5358
- }).version,
5831
+ packageVersion: packageReport.version,
5832
+ compatibleBackendVersion: packageReport.compatibleBackendVersion,
5833
+ packageError: packageReport.error,
5359
5834
  dockerModeInstalled,
5360
5835
  cudaCompatible,
5361
5836
  doctor: {
@@ -5495,6 +5970,7 @@ async function installPrivateStateCliArtifacts({
5495
5970
  cacheBaseRoot,
5496
5971
  localDeploymentBaseRoot,
5497
5972
  localChainIds = [31337],
5973
+ groth16CrsVersion,
5498
5974
  } = {}) {
5499
5975
  const normalizedDappName = requireNonEmptyString(dappName, "dappName");
5500
5976
  const normalizedCacheBaseRoot = resolveArtifactCacheBaseRoot(cacheBaseRoot);
@@ -5515,6 +5991,7 @@ async function installPrivateStateCliArtifacts({
5515
5991
  dappName: normalizedDappName,
5516
5992
  cacheBaseRoot: normalizedCacheBaseRoot,
5517
5993
  source: "drive",
5994
+ groth16CrsVersion,
5518
5995
  }));
5519
5996
  }
5520
5997
 
@@ -5525,6 +6002,7 @@ async function installPrivateStateCliArtifacts({
5525
6002
  dappName: normalizedDappName,
5526
6003
  cacheBaseRoot: normalizedCacheBaseRoot,
5527
6004
  localDeploymentBaseRoot: normalizedLocalDeploymentBaseRoot,
6005
+ groth16CrsVersion,
5528
6006
  }));
5529
6007
  }
5530
6008
  }
@@ -5546,6 +6024,7 @@ async function materializePrivateStateCliDeployment({
5546
6024
  dappName,
5547
6025
  cacheBaseRoot,
5548
6026
  source,
6027
+ groth16CrsVersion,
5549
6028
  }) {
5550
6029
  const normalizedChainId = String(requireChainId(chainId));
5551
6030
  const normalizedDappName = requireNonEmptyString(dappName, "dappName");
@@ -5577,7 +6056,8 @@ async function materializePrivateStateCliDeployment({
5577
6056
  [`groth16.${normalizedChainId}.latest.json`, path.basename(paths.grothManifestPath)],
5578
6057
  ],
5579
6058
  });
5580
- await downloadLatestPublicGroth16MpcArtifacts({
6059
+ await downloadGroth16CrsArtifactsForPrivateState({
6060
+ version: groth16CrsVersion,
5581
6061
  outputDir: paths.rootDir,
5582
6062
  selectedFiles: [
5583
6063
  ["circuit_final.zkey", path.basename(paths.grothZkeyPath)],
@@ -5609,6 +6089,7 @@ async function materializeLocalPrivateStateCliDeployment({
5609
6089
  dappName,
5610
6090
  cacheBaseRoot,
5611
6091
  localDeploymentBaseRoot,
6092
+ groth16CrsVersion,
5612
6093
  }) {
5613
6094
  const normalizedChainId = String(requireChainId(chainId));
5614
6095
  const normalizedDappName = requireNonEmptyString(dappName, "dappName");
@@ -5645,7 +6126,8 @@ async function materializeLocalPrivateStateCliDeployment({
5645
6126
  [path.join(dappDir, `dapp-registration.${normalizedChainId}.json`), path.basename(paths.dappRegistrationPath)],
5646
6127
  ],
5647
6128
  });
5648
- await downloadLatestPublicGroth16MpcArtifacts({
6129
+ await downloadGroth16CrsArtifactsForPrivateState({
6130
+ version: groth16CrsVersion,
5649
6131
  outputDir: paths.rootDir,
5650
6132
  selectedFiles: [
5651
6133
  ["circuit_final.zkey", path.basename(paths.grothZkeyPath)],