@tokamak-private-dapps/private-state-cli 0.1.6 → 0.1.9
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 +17 -0
- package/README.md +30 -4
- package/cli-assistant.html +7 -2
- package/package.json +6 -6
- package/private-state-bridge-cli.mjs +482 -84
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.9 - 2026-05-03
|
|
4
|
+
|
|
5
|
+
- Used the bundled Groth16 package version as the default `private-state-cli --install` Groth16 runtime version.
|
|
6
|
+
- Treated stale local Groth16 CRS metadata without `compatibleBackendVersion` as a cache miss so the matching public CRS can be reinstalled.
|
|
7
|
+
|
|
8
|
+
## 0.1.8 - 2026-04-30
|
|
9
|
+
|
|
10
|
+
- Reused common proof backend version helpers for Tokamak and Groth16 compatibility checks.
|
|
11
|
+
- Reused common npm registry metadata lookup during proof backend runtime installation.
|
|
12
|
+
|
|
13
|
+
## 0.1.7 - 2026-04-29
|
|
14
|
+
|
|
15
|
+
- Required Groth16 channel verifier and installed CRS compatibility versions to use canonical major.minor form.
|
|
16
|
+
- Matched Groth16 channel verifier compatibility against the installed CRS major.minor compatibility version.
|
|
17
|
+
- Required the Groth16 package version with verified public CRS archive selection.
|
|
18
|
+
- Required Tokamak zk-EVM channel verifier and CLI package compatibility versions to use canonical major.minor form.
|
|
19
|
+
|
|
3
20
|
## 0.1.6 - 2026-04-29
|
|
4
21
|
|
|
5
22
|
- Added `--groth16-cli-version` and `--tokamak-zk-evm-cli-version` install options with npm latest defaults.
|
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Command-line client for the Tokamak private-state DApp.
|
|
4
4
|
|
|
5
|
+
The full private-state DApp documentation is published with the repository:
|
|
6
|
+
|
|
7
|
+
- https://github.com/tokamak-network/Tokamak-zk-EVM-contracts/tree/main/packages/apps/private-state/docs
|
|
8
|
+
|
|
5
9
|
## Install
|
|
6
10
|
|
|
7
11
|
```bash
|
|
@@ -15,14 +19,18 @@ artifacts:
|
|
|
15
19
|
private-state-cli --install
|
|
16
20
|
```
|
|
17
21
|
|
|
18
|
-
By default, `--install` resolves the latest `@tokamak-zk-evm/cli` and
|
|
19
|
-
|
|
22
|
+
By default, `--install` resolves the latest `@tokamak-zk-evm/cli` from the npm registry and uses the bundled
|
|
23
|
+
`@tokamak-private-dapps/groth16` dependency version selected by the installed private-state CLI package. To pin exact
|
|
24
|
+
proof backend versions for a channel, pass explicit versions:
|
|
20
25
|
|
|
21
26
|
```bash
|
|
22
|
-
private-state-cli --install --tokamak-zk-evm-cli-version 2.0
|
|
27
|
+
private-state-cli --install --tokamak-zk-evm-cli-version 2.1.0 --groth16-cli-version 0.2.0
|
|
23
28
|
```
|
|
24
29
|
|
|
25
|
-
The Groth16 installer downloads the public Google Drive CRS archive
|
|
30
|
+
The Groth16 installer downloads the public Google Drive CRS archive whose major.minor compatibility version matches the
|
|
31
|
+
selected Groth16 CLI package version.
|
|
32
|
+
The Tokamak zk-EVM installer requires the selected CLI package to declare
|
|
33
|
+
`tokamakZkEvm.compatibleBackendVersion` as a canonical major.minor version matching the selected package version.
|
|
26
34
|
|
|
27
35
|
`--install` downloads public deployment artifacts from the configured artifact index. It does not read repository-local
|
|
28
36
|
`deployment/` outputs by default. Repository development workflows that need local anvil artifacts can opt in explicitly:
|
|
@@ -60,6 +68,19 @@ A common private-state flow is:
|
|
|
60
68
|
|
|
61
69
|
Use `private-state-cli --help` for the full command list and required options.
|
|
62
70
|
|
|
71
|
+
Channel policy warning:
|
|
72
|
+
|
|
73
|
+
- `create-channel` commits to an immutable channel policy: verifier bindings, DApp execution metadata, function layout,
|
|
74
|
+
managed storage vector, and refund policy are fixed for that channel.
|
|
75
|
+
- `join-channel` means the user accepts the channel's current policy. Later policy-level fixes require a new channel or
|
|
76
|
+
migration; the existing channel is intentionally not mutated in place without renewed user consent.
|
|
77
|
+
- Before sending a channel-creation transaction or a first channel-registration transaction, the CLI prints the policy
|
|
78
|
+
snapshot that will be accepted: DApp metadata digest, digest schema, Groth16 verifier address, Groth16 compatible
|
|
79
|
+
backend version, Tokamak verifier address, and Tokamak compatible backend version.
|
|
80
|
+
- Users and operators must review this snapshot before signing. If any digest, schema, verifier address, or compatible
|
|
81
|
+
backend version is unexpected or has not been reviewed, do not create or join the channel. A later correction creates
|
|
82
|
+
a new channel; it does not rewrite the policy of an already-created channel.
|
|
83
|
+
|
|
63
84
|
`private-state-cli --doctor` reports the CLI package version, dependency versions recorded by the last
|
|
64
85
|
`private-state-cli --install`, selected proof backend runtime versions, current dependency versions through `tokamak-l2js`, and Tokamak zk-EVM runtime
|
|
65
86
|
install mode, Docker mode, CUDA runtime metadata, live `nvidia-smi` and Docker GPU probe results, and Groth16
|
|
@@ -114,6 +135,9 @@ Operating rules:
|
|
|
114
135
|
telling the user to move funds.
|
|
115
136
|
- Explain that wallet names are local CLI identifiers, while private transfers use notes owned by L2 addresses
|
|
116
137
|
registered in the channel.
|
|
138
|
+
- Before guiding a user through `create-channel` or `join-channel`, explain that channel policy is immutable after
|
|
139
|
+
creation and that joining a channel means accepting its current verifier, DApp metadata, function layout, managed
|
|
140
|
+
storage vector, and refund policy.
|
|
117
141
|
- Do not present one fixed command sequence as universally correct. Some flows start from an existing channel or wallet,
|
|
118
142
|
while others require creating or joining a channel first.
|
|
119
143
|
- When the user asks for a transfer, first determine whether the sender has minted notes available. If not, guide them
|
|
@@ -147,6 +171,8 @@ using bridge-facing commands on a new machine.
|
|
|
147
171
|
Channel balance commands such as `deposit-channel` and `withdraw-channel` use the installed Groth16 runtime workspace
|
|
148
172
|
directly. Proof generation writes to the fixed workspace paths under `~/tokamak-private-channels/groth16/proof`; the CLI
|
|
149
173
|
does not pass custom `--zkey`, proof-output, or public-output paths to the Groth16 prover.
|
|
174
|
+
Before proof generation, the CLI compares the target channel's verifier compatibility versions with the installed
|
|
175
|
+
Tokamak zk-EVM and Groth16 major.minor compatibility versions.
|
|
150
176
|
|
|
151
177
|
Release order matters for npm publication. `@tokamak-private-dapps/common-library` and
|
|
152
178
|
`@tokamak-private-dapps/groth16` must be published before this package version.
|
package/cli-assistant.html
CHANGED
|
@@ -400,6 +400,11 @@
|
|
|
400
400
|
case, you lose ownership of all notes because you can no longer use them, and that ownership cannot be
|
|
401
401
|
recovered.
|
|
402
402
|
</li>
|
|
403
|
+
<li>
|
|
404
|
+
Channel policy is immutable after creation. Joining a channel means accepting its verifier bindings,
|
|
405
|
+
DApp metadata, function layout, managed storage vector, and refund policy; later policy-level fixes
|
|
406
|
+
require a new channel or migration.
|
|
407
|
+
</li>
|
|
403
408
|
</ul>
|
|
404
409
|
</div>
|
|
405
410
|
</section>
|
|
@@ -521,12 +526,12 @@
|
|
|
521
526
|
const commands = [
|
|
522
527
|
{ id: "install-zk-evm", description: "Install the local Tokamak zk-EVM toolchain. Optionally forward --docker for Linux-host Docker installs.", fields: ["docker"] },
|
|
523
528
|
{ id: "uninstall-zk-evm", description: "Remove the Tokamak zk-EVM CLI runtime workspace.", fields: [] },
|
|
524
|
-
{ id: "create-channel", description: "Create
|
|
529
|
+
{ id: "create-channel", description: "Create a channel with an immutable operating policy and initialize its workspace.", fields: ["channelName", "network", "privateKey", "alchemyApiKey"] },
|
|
525
530
|
{ id: "recover-workspace", description: "Rebuild the saved channel workspace from bridge state.", fields: ["channelName", "network", "alchemyApiKey"] },
|
|
526
531
|
{ id: "deposit-bridge", description: "Deposit canonical tokens into the shared bridge vault.", fields: ["amount", "network", "privateKey", "alchemyApiKey"] },
|
|
527
532
|
{ id: "withdraw-bridge", description: "Withdraw shared bridge-vault funds back to the L1 wallet.", fields: ["amount", "network", "privateKey", "alchemyApiKey"] },
|
|
528
533
|
{ id: "get-my-bridge-fund", description: "Read the current bridge-vault balance.", fields: ["network", "privateKey", "alchemyApiKey"] },
|
|
529
|
-
{ id: "join-channel", description: "
|
|
534
|
+
{ id: "join-channel", description: "Accept the channel policy and bind the caller to a channel-specific L2 identity.", fields: ["channelName", "password", "network", "privateKey", "alchemyApiKey"] },
|
|
530
535
|
{ id: "recover-wallet", description: "Rebuild the recoverable portion of a wallet.", fields: ["channelName", "password", "network", "privateKey", "alchemyApiKey"] },
|
|
531
536
|
{ id: "get-my-wallet-meta", description: "Check whether a saved wallet matches on-chain registration.", fields: ["wallet", "password", "network"] },
|
|
532
537
|
{ id: "get-my-l1-address", description: "Derive the L1 address for a private key.", fields: ["privateKey"] },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokamak-private-dapps/private-state-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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,12 +41,12 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@ethereumjs/util": "^10.1.1",
|
|
44
|
-
"@noble/curves": "
|
|
45
|
-
"@tokamak-private-dapps/common-library": "^0.1.
|
|
46
|
-
"@tokamak-private-dapps/groth16": "^0.
|
|
47
|
-
"@tokamak-zk-evm/cli": "^2.0
|
|
44
|
+
"@noble/curves": "1.9.7",
|
|
45
|
+
"@tokamak-private-dapps/common-library": "^0.1.1",
|
|
46
|
+
"@tokamak-private-dapps/groth16": "^0.2.0",
|
|
47
|
+
"@tokamak-zk-evm/cli": "^2.1.0",
|
|
48
48
|
"ethers": "^6.14.1",
|
|
49
|
-
"tokamak-l2js": "^0.1.
|
|
49
|
+
"tokamak-l2js": "^0.1.4"
|
|
50
50
|
},
|
|
51
51
|
"engines": {
|
|
52
52
|
"node": ">=18"
|
|
@@ -44,6 +44,13 @@ 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
55
|
resolveTokamakBlockInputConfig,
|
|
49
56
|
resolveTokamakCliEntryPath,
|
|
@@ -65,6 +72,8 @@ import {
|
|
|
65
72
|
PUBLIC_GROTH16_MPC_DRIVE_FOLDER_ID,
|
|
66
73
|
downloadLatestPublicGroth16MpcArtifacts,
|
|
67
74
|
downloadPublicGroth16MpcArtifactsByVersion,
|
|
75
|
+
readGroth16CompatibleBackendVersionFromPackageJson,
|
|
76
|
+
requireCanonicalGroth16CompatibleBackendVersion,
|
|
68
77
|
} from "@tokamak-private-dapps/groth16/public-drive-crs";
|
|
69
78
|
import {
|
|
70
79
|
CHANNEL_BOUND_L2_DERIVATION_MODE,
|
|
@@ -157,6 +166,68 @@ const DEFAULT_LOG_REQUESTS_PER_SECOND = 5;
|
|
|
157
166
|
const LOG_REQUEST_INTERVAL_MS = Math.ceil(1000 / DEFAULT_LOG_REQUESTS_PER_SECOND);
|
|
158
167
|
let lastLogRequestStartedAtMs = 0;
|
|
159
168
|
|
|
169
|
+
function printImmutableChannelPolicyWarning({
|
|
170
|
+
action,
|
|
171
|
+
channelName,
|
|
172
|
+
channelId,
|
|
173
|
+
channelManager = null,
|
|
174
|
+
policySnapshot = null,
|
|
175
|
+
}) {
|
|
176
|
+
const details = [
|
|
177
|
+
`WARNING: ${action} commits to an immutable channel policy.`,
|
|
178
|
+
`Channel: ${channelName} (${channelId.toString()})`,
|
|
179
|
+
];
|
|
180
|
+
if (channelManager) {
|
|
181
|
+
details.push(`ChannelManager: ${channelManager}`);
|
|
182
|
+
}
|
|
183
|
+
details.push(
|
|
184
|
+
"The channel verifier bindings, DApp execution metadata, function layout, managed storage vector, and refund policy are fixed for this channel.",
|
|
185
|
+
"Those policy fields are intentionally not upgraded in place without channel-user consent.",
|
|
186
|
+
"If a policy bug is discovered later, the expected mitigation is creating or joining a new channel, not mutating this channel.",
|
|
187
|
+
"Review the DApp digest, digest schema, verifier addresses, and compatible backend versions before signing.",
|
|
188
|
+
);
|
|
189
|
+
if (policySnapshot) {
|
|
190
|
+
details.push(
|
|
191
|
+
"Channel policy snapshot:",
|
|
192
|
+
` DApp id: ${policySnapshot.dappId}`,
|
|
193
|
+
` DApp metadata digest schema: ${policySnapshot.dappMetadataDigestSchema}`,
|
|
194
|
+
` DApp metadata digest: ${policySnapshot.dappMetadataDigest}`,
|
|
195
|
+
` DApp function root: ${policySnapshot.functionRoot}`,
|
|
196
|
+
` Groth16 verifier: ${policySnapshot.grothVerifier}`,
|
|
197
|
+
` Groth16 compatible backend version: ${policySnapshot.grothVerifierCompatibleBackendVersion}`,
|
|
198
|
+
` Tokamak verifier: ${policySnapshot.tokamakVerifier}`,
|
|
199
|
+
` Tokamak compatible backend version: ${policySnapshot.tokamakVerifierCompatibleBackendVersion}`,
|
|
200
|
+
"Do not sign if any snapshot value is unexpected or has not been reviewed.",
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
console.error(details.join("\n"));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function normalizeDAppPolicySnapshot({
|
|
207
|
+
dappId,
|
|
208
|
+
metadataDigest,
|
|
209
|
+
metadataDigestSchema,
|
|
210
|
+
functionRoot,
|
|
211
|
+
verifierSnapshot,
|
|
212
|
+
}) {
|
|
213
|
+
return {
|
|
214
|
+
dappId: Number(dappId),
|
|
215
|
+
dappMetadataDigestSchema: normalizeBytes32Hex(metadataDigestSchema),
|
|
216
|
+
dappMetadataDigest: normalizeBytes32Hex(metadataDigest),
|
|
217
|
+
functionRoot: normalizeBytes32Hex(functionRoot),
|
|
218
|
+
grothVerifier: getAddress(verifierSnapshot.grothVerifier),
|
|
219
|
+
grothVerifierCompatibleBackendVersion: requireVersionString(
|
|
220
|
+
verifierSnapshot.grothVerifierCompatibleBackendVersion,
|
|
221
|
+
"registered DApp Groth16 verifier compatibleBackendVersion",
|
|
222
|
+
),
|
|
223
|
+
tokamakVerifier: getAddress(verifierSnapshot.tokamakVerifier),
|
|
224
|
+
tokamakVerifierCompatibleBackendVersion: requireVersionString(
|
|
225
|
+
verifierSnapshot.tokamakVerifierCompatibleBackendVersion,
|
|
226
|
+
"registered DApp Tokamak verifier compatibleBackendVersion",
|
|
227
|
+
),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
160
231
|
async function prepareDeploymentArtifacts(chainId) {
|
|
161
232
|
const normalizedChainId = Number(chainId);
|
|
162
233
|
const existingPaths = flatDeploymentArtifactPathsByChainId.get(normalizedChainId);
|
|
@@ -364,16 +435,25 @@ async function handleChannelCreate({ args, network, provider }) {
|
|
|
364
435
|
);
|
|
365
436
|
const canonicalAsset = getAddress(await bridgeCore.canonicalAsset());
|
|
366
437
|
const canonicalAssetDecimals = await fetchTokenDecimals(provider, canonicalAsset);
|
|
367
|
-
const
|
|
368
|
-
const
|
|
438
|
+
const joinTollInput = requireArg(args.joinToll, "--join-toll");
|
|
439
|
+
const joinToll = parseTokenAmount(joinTollInput, canonicalAssetDecimals);
|
|
369
440
|
const channelId = deriveChannelIdFromName(channelName);
|
|
370
|
-
const
|
|
441
|
+
const dapp = await resolveDAppIdByLabel({
|
|
371
442
|
provider,
|
|
372
443
|
bridgeResources,
|
|
373
444
|
dappLabel: PRIVATE_STATE_DAPP_LABEL,
|
|
374
445
|
});
|
|
446
|
+
const dappId = dapp.dappId;
|
|
447
|
+
const policySnapshot = dapp.policySnapshot;
|
|
375
448
|
|
|
376
|
-
|
|
449
|
+
printImmutableChannelPolicyWarning({
|
|
450
|
+
action: "create-channel",
|
|
451
|
+
channelName,
|
|
452
|
+
channelId,
|
|
453
|
+
policySnapshot,
|
|
454
|
+
});
|
|
455
|
+
const receipt =
|
|
456
|
+
await waitForReceipt(await bridgeCore.createChannel(channelId, dappId, joinToll, dapp.metadataDigest));
|
|
377
457
|
const channelInfo = await bridgeCore.getChannel(channelId);
|
|
378
458
|
|
|
379
459
|
const workspaceResult = await initializeChannelWorkspace({
|
|
@@ -390,9 +470,12 @@ async function handleChannelCreate({ args, network, provider }) {
|
|
|
390
470
|
channelName,
|
|
391
471
|
channelId: channelId.toString(),
|
|
392
472
|
dappId,
|
|
473
|
+
dappMetadataDigest: dapp.metadataDigest,
|
|
474
|
+
dappMetadataDigestSchema: dapp.metadataDigestSchema,
|
|
475
|
+
policySnapshot,
|
|
393
476
|
leader,
|
|
394
|
-
|
|
395
|
-
|
|
477
|
+
joinTollBaseUnits: joinToll.toString(),
|
|
478
|
+
joinTollTokens: ethers.formatUnits(joinToll, canonicalAssetDecimals),
|
|
396
479
|
canonicalAsset,
|
|
397
480
|
canonicalAssetDecimals,
|
|
398
481
|
asset: channelInfo.asset,
|
|
@@ -417,9 +500,21 @@ async function resolveDAppIdByLabel({ provider, bridgeResources, dappLabel }) {
|
|
|
417
500
|
const manifestLabel = typeof manifest.dappLabel === "string" ? manifest.dappLabel : null;
|
|
418
501
|
const manifestDappId = manifest.dappId;
|
|
419
502
|
const manifestManager = typeof manifest.dAppManager === "string" ? getAddress(manifest.dAppManager) : null;
|
|
503
|
+
const manifestMetadataDigest = normalizeBytes32Hex(manifest.registration?.metadataDigest);
|
|
504
|
+
const manifestMetadataDigestSchema = normalizeBytes32Hex(manifest.registration?.metadataDigestSchema);
|
|
505
|
+
const manifestFunctionRoot = normalizeBytes32Hex(manifest.registration?.functionRoot);
|
|
420
506
|
|
|
421
507
|
expect(manifestLabel === dappLabel, `DApp registration manifest label mismatch in ${manifestPath}.`);
|
|
422
508
|
expect(Number.isInteger(manifestDappId), `DApp registration manifest is missing an integer dappId: ${manifestPath}.`);
|
|
509
|
+
expect(manifestMetadataDigest !== null, `DApp registration manifest is missing registration.metadataDigest: ${manifestPath}.`);
|
|
510
|
+
expect(
|
|
511
|
+
manifestMetadataDigestSchema !== null,
|
|
512
|
+
`DApp registration manifest is missing registration.metadataDigestSchema: ${manifestPath}.`,
|
|
513
|
+
);
|
|
514
|
+
expect(
|
|
515
|
+
manifestFunctionRoot !== null,
|
|
516
|
+
`DApp registration manifest is missing registration.functionRoot: ${manifestPath}.`,
|
|
517
|
+
);
|
|
423
518
|
expect(
|
|
424
519
|
manifestManager !== null
|
|
425
520
|
&& ethers.toBigInt(manifestManager) === ethers.toBigInt(getAddress(bridgeResources.bridgeDeployment.dAppManager)),
|
|
@@ -432,7 +527,36 @@ async function resolveDAppIdByLabel({ provider, bridgeResources, dappLabel }) {
|
|
|
432
527
|
ethers.toBigInt(normalizeBytes32Hex(info.labelHash)) === ethers.toBigInt(expectedLabelHash),
|
|
433
528
|
`DApp id ${manifestDappId} from ${manifestPath} does not match label ${dappLabel} on-chain.`,
|
|
434
529
|
);
|
|
435
|
-
|
|
530
|
+
const onchainMetadataDigest = normalizeBytes32Hex(info.metadataDigest);
|
|
531
|
+
const onchainMetadataDigestSchema = normalizeBytes32Hex(info.metadataDigestSchema);
|
|
532
|
+
const onchainFunctionRoot = normalizeBytes32Hex(info.functionRoot);
|
|
533
|
+
const verifierSnapshot = await dAppManager.getDAppVerifierSnapshot(manifestDappId);
|
|
534
|
+
const policySnapshot = normalizeDAppPolicySnapshot({
|
|
535
|
+
dappId: manifestDappId,
|
|
536
|
+
metadataDigest: onchainMetadataDigest,
|
|
537
|
+
metadataDigestSchema: onchainMetadataDigestSchema,
|
|
538
|
+
functionRoot: onchainFunctionRoot,
|
|
539
|
+
verifierSnapshot,
|
|
540
|
+
});
|
|
541
|
+
expect(
|
|
542
|
+
ethers.toBigInt(onchainMetadataDigest) === ethers.toBigInt(manifestMetadataDigest),
|
|
543
|
+
`DApp id ${manifestDappId} metadata digest ${onchainMetadataDigest} does not match ${manifestMetadataDigest} from ${manifestPath}.`,
|
|
544
|
+
);
|
|
545
|
+
expect(
|
|
546
|
+
ethers.toBigInt(onchainMetadataDigestSchema) === ethers.toBigInt(manifestMetadataDigestSchema),
|
|
547
|
+
`DApp id ${manifestDappId} metadata digest schema ${onchainMetadataDigestSchema} does not match ${manifestMetadataDigestSchema} from ${manifestPath}.`,
|
|
548
|
+
);
|
|
549
|
+
expect(
|
|
550
|
+
ethers.toBigInt(onchainFunctionRoot) === ethers.toBigInt(manifestFunctionRoot),
|
|
551
|
+
`DApp id ${manifestDappId} function root ${onchainFunctionRoot} does not match ${manifestFunctionRoot} from ${manifestPath}.`,
|
|
552
|
+
);
|
|
553
|
+
return {
|
|
554
|
+
dappId: Number(manifestDappId),
|
|
555
|
+
metadataDigest: onchainMetadataDigest,
|
|
556
|
+
metadataDigestSchema: onchainMetadataDigestSchema,
|
|
557
|
+
functionRoot: onchainFunctionRoot,
|
|
558
|
+
policySnapshot,
|
|
559
|
+
};
|
|
436
560
|
}
|
|
437
561
|
|
|
438
562
|
async function handleWorkspaceInit({ args, network, provider }) {
|
|
@@ -505,6 +629,10 @@ async function initializeChannelWorkspace({
|
|
|
505
629
|
const currentRootVectorHash = normalizeBytes32Hex(await channelManager.currentRootVectorHash());
|
|
506
630
|
const genesisBlockNumber = Number(await channelManager.genesisBlockNumber());
|
|
507
631
|
const managedStorageAddresses = normalizedAddressVector(await channelManager.getManagedStorageAddresses());
|
|
632
|
+
const policySnapshot = await readChannelPolicySnapshot({
|
|
633
|
+
channelManager,
|
|
634
|
+
dappId: Number(channelInfo.dappId),
|
|
635
|
+
});
|
|
508
636
|
const deploymentManifestPath = dappDeploymentManifestPath(network.chainId);
|
|
509
637
|
const storageLayoutManifestPath = dappStorageLayoutManifestPath(network.chainId);
|
|
510
638
|
const deploymentManifest = readJson(deploymentManifestPath);
|
|
@@ -571,6 +699,10 @@ async function initializeChannelWorkspace({
|
|
|
571
699
|
controller: controllerAddress,
|
|
572
700
|
l2AccountingVault: l2AccountingVaultAddress,
|
|
573
701
|
aPubBlockHash: normalizeBytes32Hex(channelInfo.aPubBlockHash),
|
|
702
|
+
dappMetadataDigestSchema: policySnapshot.dappMetadataDigestSchema,
|
|
703
|
+
dappMetadataDigest: policySnapshot.dappMetadataDigest,
|
|
704
|
+
functionRoot: policySnapshot.functionRoot,
|
|
705
|
+
policySnapshot,
|
|
574
706
|
managedStorageAddresses,
|
|
575
707
|
liquidBalancesSlot: liquidBalancesSlot.toString(),
|
|
576
708
|
};
|
|
@@ -967,7 +1099,7 @@ async function handleInstallZkEvm({ args }) {
|
|
|
967
1099
|
const deploymentArtifacts = await installPrivateStateCliArtifacts({
|
|
968
1100
|
dappName: PRIVATE_STATE_DAPP_LABEL,
|
|
969
1101
|
localDeploymentBaseRoot,
|
|
970
|
-
groth16CrsVersion:
|
|
1102
|
+
groth16CrsVersion: groth16Runtime.compatibleBackendVersion,
|
|
971
1103
|
});
|
|
972
1104
|
const installManifest = writePrivateStateCliInstallManifest({
|
|
973
1105
|
dockerRequested: Boolean(args.docker),
|
|
@@ -1185,20 +1317,27 @@ async function handleJoinChannel({ args, network, provider, rpcUrl }) {
|
|
|
1185
1317
|
let resolvedLeafIndex = leafIndex;
|
|
1186
1318
|
let approveReceipt = null;
|
|
1187
1319
|
let receipt = null;
|
|
1188
|
-
let
|
|
1320
|
+
let joinToll = 0n;
|
|
1189
1321
|
let status = null;
|
|
1190
1322
|
|
|
1191
1323
|
if (!existingRegistration.exists) {
|
|
1192
|
-
|
|
1324
|
+
joinToll = ethers.toBigInt(await context.channelManager.joinToll());
|
|
1193
1325
|
const asset = new Contract(
|
|
1194
1326
|
context.workspace.canonicalAsset,
|
|
1195
1327
|
context.bridgeAbiManifest.contracts.erc20.abi,
|
|
1196
1328
|
signer,
|
|
1197
1329
|
);
|
|
1198
1330
|
let nextNonce = await provider.getTransactionCount(signer.address, "pending");
|
|
1199
|
-
|
|
1331
|
+
printImmutableChannelPolicyWarning({
|
|
1332
|
+
action: "join-channel",
|
|
1333
|
+
channelName: context.workspace.channelName,
|
|
1334
|
+
channelId: ethers.toBigInt(context.workspace.channelId),
|
|
1335
|
+
channelManager: context.workspace.channelManager,
|
|
1336
|
+
policySnapshot: context.workspace.policySnapshot,
|
|
1337
|
+
});
|
|
1338
|
+
if (joinToll !== 0n) {
|
|
1200
1339
|
approveReceipt = await waitForReceipt(
|
|
1201
|
-
await asset.approve(context.workspace.bridgeTokenVault,
|
|
1340
|
+
await asset.approve(context.workspace.bridgeTokenVault, joinToll, { nonce: nextNonce++ }),
|
|
1202
1341
|
);
|
|
1203
1342
|
}
|
|
1204
1343
|
receipt = await waitForReceipt(
|
|
@@ -1232,7 +1371,7 @@ async function handleJoinChannel({ args, network, provider, rpcUrl }) {
|
|
|
1232
1371
|
"The existing note-receive public key parity does not match the derived note-receive public key.",
|
|
1233
1372
|
);
|
|
1234
1373
|
resolvedLeafIndex = existingRegistration.leafIndex;
|
|
1235
|
-
|
|
1374
|
+
joinToll = ethers.toBigInt(existingRegistration.joinTollPaid);
|
|
1236
1375
|
status = "already-registered";
|
|
1237
1376
|
}
|
|
1238
1377
|
|
|
@@ -1258,9 +1397,10 @@ async function handleJoinChannel({ args, network, provider, rpcUrl }) {
|
|
|
1258
1397
|
l2Address: l2Identity.l2Address,
|
|
1259
1398
|
l2StorageKey: storageKey,
|
|
1260
1399
|
leafIndex: resolvedLeafIndex.toString(),
|
|
1261
|
-
|
|
1262
|
-
|
|
1400
|
+
joinTollBaseUnits: joinToll.toString(),
|
|
1401
|
+
joinTollTokens: ethers.formatUnits(joinToll, Number(context.workspace.canonicalAssetDecimals)),
|
|
1263
1402
|
noteReceivePubKey: noteReceiveKeyMaterial.noteReceivePubKey,
|
|
1403
|
+
policySnapshot: context.workspace.policySnapshot,
|
|
1264
1404
|
approveGasUsed: approveReceipt ? receiptGasUsed(approveReceipt) : null,
|
|
1265
1405
|
gasUsed: receipt ? receiptGasUsed(receipt) : null,
|
|
1266
1406
|
approveTxUrl: approveReceipt ? explorerTxUrl(network, approveReceipt.hash) : null,
|
|
@@ -1287,7 +1427,7 @@ async function handleExitChannel({ args, provider }) {
|
|
|
1287
1427
|
"Run withdraw-channel first, or rerun exit-channel with --force to bypass this CLI check.",
|
|
1288
1428
|
].join(" "),
|
|
1289
1429
|
);
|
|
1290
|
-
const [refundAmount, refundBps] = await context.channelManager.
|
|
1430
|
+
const [refundAmount, refundBps] = await context.channelManager.getExitTollRefundQuote(signer.address);
|
|
1291
1431
|
const receipt = await waitForReceipt(
|
|
1292
1432
|
await context.bridgeTokenVault.connect(signer).exitChannel(ethers.toBigInt(context.workspace.channelId)),
|
|
1293
1433
|
);
|
|
@@ -1393,8 +1533,9 @@ async function handleGrothVaultMove({ args, provider, direction }) {
|
|
|
1393
1533
|
nextValue,
|
|
1394
1534
|
});
|
|
1395
1535
|
|
|
1536
|
+
const methodName = direction === "deposit" ? "depositToChannelVault" : "withdrawFromChannelVault";
|
|
1396
1537
|
const receipt = await waitForReceipt(
|
|
1397
|
-
await bridgeTokenVault[
|
|
1538
|
+
await bridgeTokenVault[methodName](ethers.toBigInt(context.workspace.channelId), transition.proof, transition.update),
|
|
1398
1539
|
);
|
|
1399
1540
|
const onchainRootVectorHash = normalizeBytes32Hex(await context.channelManager.currentRootVectorHash());
|
|
1400
1541
|
expect(
|
|
@@ -1453,6 +1594,63 @@ async function handleWithdrawBridge({ args, network, provider }) {
|
|
|
1453
1594
|
});
|
|
1454
1595
|
}
|
|
1455
1596
|
|
|
1597
|
+
function resolveFunctionMetadataProofForExecution({
|
|
1598
|
+
chainId,
|
|
1599
|
+
controllerAddress,
|
|
1600
|
+
functionSelector,
|
|
1601
|
+
preprocessInputHash,
|
|
1602
|
+
expectedFunctionRoot,
|
|
1603
|
+
}) {
|
|
1604
|
+
const manifestPath = requireFlatDeploymentArtifactPathsForChainId(chainId).dappRegistrationPath;
|
|
1605
|
+
const manifest = readJson(manifestPath);
|
|
1606
|
+
const proofRoot = normalizeBytes32Hex(manifest.functionMetadataProofs?.root);
|
|
1607
|
+
const expectedRoot = normalizeBytes32Hex(expectedFunctionRoot);
|
|
1608
|
+
expect(
|
|
1609
|
+
ethers.toBigInt(proofRoot) === ethers.toBigInt(expectedRoot),
|
|
1610
|
+
`DApp function proof root ${proofRoot} does not match channel function root ${expectedRoot}.`,
|
|
1611
|
+
);
|
|
1612
|
+
|
|
1613
|
+
const functions = manifest.functionMetadataProofs?.functions;
|
|
1614
|
+
expect(Array.isArray(functions), `DApp registration manifest is missing functionMetadataProofs.functions: ${manifestPath}.`);
|
|
1615
|
+
const normalizedController = getAddress(controllerAddress);
|
|
1616
|
+
const normalizedSelector = normalizeBytesHex(functionSelector, 4);
|
|
1617
|
+
const normalizedPreprocessInputHash = normalizeBytes32Hex(preprocessInputHash);
|
|
1618
|
+
const entry = functions.find((candidate) => {
|
|
1619
|
+
const metadata = candidate?.metadata;
|
|
1620
|
+
return metadata
|
|
1621
|
+
&& getAddress(metadata.entryContract) === normalizedController
|
|
1622
|
+
&& normalizeBytesHex(metadata.functionSig, 4) === normalizedSelector
|
|
1623
|
+
&& normalizeBytes32Hex(metadata.preprocessInputHash) === normalizedPreprocessInputHash;
|
|
1624
|
+
});
|
|
1625
|
+
expect(
|
|
1626
|
+
entry !== undefined,
|
|
1627
|
+
[
|
|
1628
|
+
`No DApp function metadata proof found for ${normalizedController} ${normalizedSelector}.`,
|
|
1629
|
+
`Expected preprocess input hash: ${normalizedPreprocessInputHash}.`,
|
|
1630
|
+
`Manifest: ${manifestPath}.`,
|
|
1631
|
+
].join(" "),
|
|
1632
|
+
);
|
|
1633
|
+
|
|
1634
|
+
return {
|
|
1635
|
+
metadata: {
|
|
1636
|
+
entryContract: getAddress(entry.metadata.entryContract),
|
|
1637
|
+
functionSig: normalizeBytesHex(entry.metadata.functionSig, 4),
|
|
1638
|
+
preprocessInputHash: normalizeBytes32Hex(entry.metadata.preprocessInputHash),
|
|
1639
|
+
instanceLayout: {
|
|
1640
|
+
entryContractOffsetWords: Number(entry.metadata.instanceLayout.entryContractOffsetWords),
|
|
1641
|
+
functionSigOffsetWords: Number(entry.metadata.instanceLayout.functionSigOffsetWords),
|
|
1642
|
+
currentRootVectorOffsetWords: Number(entry.metadata.instanceLayout.currentRootVectorOffsetWords),
|
|
1643
|
+
updatedRootVectorOffsetWords: Number(entry.metadata.instanceLayout.updatedRootVectorOffsetWords),
|
|
1644
|
+
eventLogs: entry.metadata.instanceLayout.eventLogs.map((eventLog) => ({
|
|
1645
|
+
startOffsetWords: Number(eventLog.startOffsetWords),
|
|
1646
|
+
topicCount: Number(eventLog.topicCount),
|
|
1647
|
+
})),
|
|
1648
|
+
},
|
|
1649
|
+
},
|
|
1650
|
+
siblings: entry.merkleProof.map((sibling) => normalizeBytes32Hex(sibling)),
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1456
1654
|
async function handleMintNotes({ args, provider }) {
|
|
1457
1655
|
const { wallet } = loadUnlockedWalletWithMetadata(args);
|
|
1458
1656
|
const canonicalAssetDecimals = Number(wallet.wallet.canonicalAssetDecimals);
|
|
@@ -3109,6 +3307,16 @@ async function executeWalletTemplateSend({
|
|
|
3109
3307
|
writeJson(path.join(operationDir, "resource", "synthesizer", "output", "state_snapshot.normalized.json"), nextSnapshot);
|
|
3110
3308
|
|
|
3111
3309
|
const payload = loadTokamakPayloadFromStep(operationDir);
|
|
3310
|
+
const functionProof = resolveFunctionMetadataProofForExecution({
|
|
3311
|
+
chainId: context.workspace.chainId,
|
|
3312
|
+
controllerAddress: context.workspace.controller,
|
|
3313
|
+
functionSelector: calldata.slice(0, 10),
|
|
3314
|
+
preprocessInputHash: hashTokamakPointEncoding(
|
|
3315
|
+
payload.functionPreprocessPart1,
|
|
3316
|
+
payload.functionPreprocessPart2,
|
|
3317
|
+
),
|
|
3318
|
+
expectedFunctionRoot: context.workspace.functionRoot ?? context.workspace.policySnapshot?.functionRoot,
|
|
3319
|
+
});
|
|
3112
3320
|
const noteLifecycle = extractControllerStorageDelta({
|
|
3113
3321
|
previousSnapshot: context.currentSnapshot,
|
|
3114
3322
|
nextSnapshot,
|
|
@@ -3123,7 +3331,9 @@ async function executeWalletTemplateSend({
|
|
|
3123
3331
|
);
|
|
3124
3332
|
|
|
3125
3333
|
const receipt =
|
|
3126
|
-
await waitForReceipt(
|
|
3334
|
+
await waitForReceipt(
|
|
3335
|
+
await context.channelManager.connect(signer).executeChannelTransaction(payload, functionProof),
|
|
3336
|
+
);
|
|
3127
3337
|
|
|
3128
3338
|
const onchainRootVectorHash = normalizeBytes32Hex(await context.channelManager.currentRootVectorHash());
|
|
3129
3339
|
expect(
|
|
@@ -3445,14 +3655,22 @@ async function assertChannelProofBackendVersionCompatibility({ context, operatio
|
|
|
3445
3655
|
{
|
|
3446
3656
|
label: "Groth16",
|
|
3447
3657
|
packageName: GROTH16_PACKAGE_NAME,
|
|
3448
|
-
|
|
3449
|
-
|
|
3658
|
+
versionKind: "compatible backend version",
|
|
3659
|
+
channelVersion: requireCanonicalGroth16CompatibleBackendVersion(
|
|
3660
|
+
channelVersions.groth16,
|
|
3661
|
+
"channel Groth16 verifier compatibleBackendVersion",
|
|
3662
|
+
),
|
|
3663
|
+
localVersion: localVersions.groth16.compatibleBackendVersion,
|
|
3450
3664
|
},
|
|
3451
3665
|
{
|
|
3452
3666
|
label: "Tokamak zk-EVM",
|
|
3453
3667
|
packageName: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
|
|
3454
|
-
|
|
3455
|
-
|
|
3668
|
+
versionKind: "compatible backend version",
|
|
3669
|
+
channelVersion: requireCanonicalCompatibleBackendVersion(
|
|
3670
|
+
channelVersions.tokamak,
|
|
3671
|
+
"channel Tokamak verifier compatibleBackendVersion",
|
|
3672
|
+
),
|
|
3673
|
+
localVersion: localVersions.tokamak.compatibleBackendVersion,
|
|
3456
3674
|
},
|
|
3457
3675
|
];
|
|
3458
3676
|
const mismatches = checks.filter(({ channelVersion, localVersion }) => channelVersion !== localVersion);
|
|
@@ -3464,10 +3682,11 @@ async function assertChannelProofBackendVersionCompatibility({ context, operatio
|
|
|
3464
3682
|
[
|
|
3465
3683
|
`Channel proof backend version mismatch before ${operationName} proof generation.`,
|
|
3466
3684
|
`Channel: ${context.workspace.channelName ?? context.workspaceName ?? context.workspace.channelId}.`,
|
|
3467
|
-
...mismatches.map(({ label, packageName, channelVersion, localVersion }) => (
|
|
3468
|
-
`${label} verifier expects ${packageName} ${
|
|
3685
|
+
...mismatches.map(({ label, packageName, versionKind, channelVersion, localVersion }) => (
|
|
3686
|
+
`${label} verifier expects ${packageName} ${versionKind} ${channelVersion}, `
|
|
3687
|
+
+ `but the local installed ${versionKind} is ${localVersion ?? "<missing>"}.`
|
|
3469
3688
|
)),
|
|
3470
|
-
"Install
|
|
3689
|
+
"Install proof backend runtimes compatible with this channel before generating proofs.",
|
|
3471
3690
|
].join(" "),
|
|
3472
3691
|
);
|
|
3473
3692
|
}
|
|
@@ -3499,29 +3718,92 @@ async function readChannelVerifierCompatibleBackendVersions(context) {
|
|
|
3499
3718
|
}
|
|
3500
3719
|
}
|
|
3501
3720
|
|
|
3721
|
+
async function readChannelPolicySnapshot({ channelManager, dappId }) {
|
|
3722
|
+
const channelManagerAddress = getAddress(await channelManager.getAddress());
|
|
3723
|
+
try {
|
|
3724
|
+
const [
|
|
3725
|
+
dappMetadataDigestSchema,
|
|
3726
|
+
dappMetadataDigest,
|
|
3727
|
+
functionRoot,
|
|
3728
|
+
grothVerifier,
|
|
3729
|
+
grothVerifierCompatibleBackendVersion,
|
|
3730
|
+
tokamakVerifier,
|
|
3731
|
+
tokamakVerifierCompatibleBackendVersion,
|
|
3732
|
+
] = await Promise.all([
|
|
3733
|
+
channelManager.dappMetadataDigestSchema(),
|
|
3734
|
+
channelManager.dappMetadataDigest(),
|
|
3735
|
+
channelManager.functionRoot(),
|
|
3736
|
+
channelManager.grothVerifier(),
|
|
3737
|
+
channelManager.grothVerifierCompatibleBackendVersion(),
|
|
3738
|
+
channelManager.tokamakVerifier(),
|
|
3739
|
+
channelManager.tokamakVerifierCompatibleBackendVersion(),
|
|
3740
|
+
]);
|
|
3741
|
+
return {
|
|
3742
|
+
dappId: Number(dappId),
|
|
3743
|
+
dappMetadataDigestSchema: normalizeBytes32Hex(dappMetadataDigestSchema),
|
|
3744
|
+
dappMetadataDigest: normalizeBytes32Hex(dappMetadataDigest),
|
|
3745
|
+
functionRoot: normalizeBytes32Hex(functionRoot),
|
|
3746
|
+
grothVerifier: getAddress(grothVerifier),
|
|
3747
|
+
grothVerifierCompatibleBackendVersion: requireVersionString(
|
|
3748
|
+
grothVerifierCompatibleBackendVersion,
|
|
3749
|
+
"channel Groth16 verifier compatibleBackendVersion",
|
|
3750
|
+
),
|
|
3751
|
+
tokamakVerifier: getAddress(tokamakVerifier),
|
|
3752
|
+
tokamakVerifierCompatibleBackendVersion: requireVersionString(
|
|
3753
|
+
tokamakVerifierCompatibleBackendVersion,
|
|
3754
|
+
"channel Tokamak verifier compatibleBackendVersion",
|
|
3755
|
+
),
|
|
3756
|
+
};
|
|
3757
|
+
} catch (error) {
|
|
3758
|
+
throw new Error(
|
|
3759
|
+
[
|
|
3760
|
+
`Unable to read immutable policy snapshot from channel manager ${channelManagerAddress}.`,
|
|
3761
|
+
"The target channel must expose DApp digest, verifier address, and compatibleBackendVersion getters.",
|
|
3762
|
+
].join(" "),
|
|
3763
|
+
{ cause: error },
|
|
3764
|
+
);
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
|
|
3502
3768
|
function readLocalProofBackendPackageVersions() {
|
|
3769
|
+
const groth16Runtime = inspectGroth16Runtime();
|
|
3770
|
+
const tokamakPackageReport = readTokamakCliPackageReport();
|
|
3503
3771
|
return {
|
|
3504
|
-
groth16:
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3772
|
+
groth16: {
|
|
3773
|
+
packageVersion: groth16Runtime.packageVersion,
|
|
3774
|
+
compatibleBackendVersion: groth16Runtime.crsCompatibleBackendVersion
|
|
3775
|
+
?? groth16Runtime.compatibleBackendVersion,
|
|
3776
|
+
},
|
|
3777
|
+
tokamak: {
|
|
3778
|
+
packageVersion: requirePackageReportVersion(tokamakPackageReport),
|
|
3779
|
+
compatibleBackendVersion: requirePackageReportCompatibleBackendVersion(tokamakPackageReport),
|
|
3780
|
+
},
|
|
3511
3781
|
};
|
|
3512
3782
|
}
|
|
3513
3783
|
|
|
3514
|
-
function readTokamakCliPackageReport() {
|
|
3784
|
+
function readTokamakCliPackageReport(packageRoot = null) {
|
|
3515
3785
|
try {
|
|
3516
|
-
|
|
3786
|
+
const resolvedPackageRoot = packageRoot ?? resolveActiveTokamakCliPackageRoot();
|
|
3787
|
+
const packageJsonPath = path.join(resolvedPackageRoot, "package.json");
|
|
3788
|
+
const packageJson = readJson(packageJsonPath);
|
|
3789
|
+
const report = readPackageReport({
|
|
3517
3790
|
name: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
|
|
3518
|
-
packageJsonPath
|
|
3791
|
+
packageJsonPath,
|
|
3792
|
+
packageJson,
|
|
3519
3793
|
});
|
|
3794
|
+
return {
|
|
3795
|
+
...report,
|
|
3796
|
+
compatibleBackendVersion: readTokamakZkEvmCompatibleBackendVersionFromPackageJson(
|
|
3797
|
+
packageJson,
|
|
3798
|
+
TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
|
|
3799
|
+
),
|
|
3800
|
+
};
|
|
3520
3801
|
} catch (error) {
|
|
3521
3802
|
return {
|
|
3522
3803
|
name: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
|
|
3523
3804
|
version: null,
|
|
3524
3805
|
packageRoot: null,
|
|
3806
|
+
compatibleBackendVersion: null,
|
|
3525
3807
|
error: error.message,
|
|
3526
3808
|
ok: false,
|
|
3527
3809
|
};
|
|
@@ -3537,6 +3819,15 @@ function requirePackageReportVersion(report) {
|
|
|
3537
3819
|
return requireVersionString(report.version, `${report.name} package version`);
|
|
3538
3820
|
}
|
|
3539
3821
|
|
|
3822
|
+
function requirePackageReportCompatibleBackendVersion(report) {
|
|
3823
|
+
if (!report.compatibleBackendVersion) {
|
|
3824
|
+
throw new Error(
|
|
3825
|
+
`Unable to determine local ${report.name} compatible backend version${report.error ? `: ${report.error}` : "."}`,
|
|
3826
|
+
);
|
|
3827
|
+
}
|
|
3828
|
+
return requireVersionString(report.compatibleBackendVersion, `${report.name} compatible backend version`);
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3540
3831
|
function requireVersionString(value, label) {
|
|
3541
3832
|
const normalized = String(value ?? "").trim();
|
|
3542
3833
|
expect(normalized.length > 0, `${label} is missing.`);
|
|
@@ -3864,10 +4155,6 @@ function normalizeBytes16Hex(value) {
|
|
|
3864
4155
|
return normalizeBytesHex(value, 16);
|
|
3865
4156
|
}
|
|
3866
4157
|
|
|
3867
|
-
function normalizeBytes20Hex(value) {
|
|
3868
|
-
return normalizeBytesHex(value, 20);
|
|
3869
|
-
}
|
|
3870
|
-
|
|
3871
4158
|
function normalizeBytes32Hex(hexValue) {
|
|
3872
4159
|
return normalizeBytesHex(hexValue, 32);
|
|
3873
4160
|
}
|
|
@@ -3888,6 +4175,10 @@ function hashTokamakPublicInputs(values) {
|
|
|
3888
4175
|
return keccak256(abiCoder.encode(["uint256[]"], [values]));
|
|
3889
4176
|
}
|
|
3890
4177
|
|
|
4178
|
+
function hashTokamakPointEncoding(part1, part2) {
|
|
4179
|
+
return keccak256(abiCoder.encode(["uint128[]", "uint256[]"], [part1, part2]));
|
|
4180
|
+
}
|
|
4181
|
+
|
|
3891
4182
|
function encodeTokamakBlockInfo(blockInfo) {
|
|
3892
4183
|
const values = new Array(TOKAMAK_APUB_BLOCK_LENGTH).fill(0n);
|
|
3893
4184
|
appendSplitWord(values, 0, ethers.toBigInt(blockInfo.coinBase));
|
|
@@ -4774,15 +5065,15 @@ function assertGetMyNotesArgs(args) {
|
|
|
4774
5065
|
|
|
4775
5066
|
function assertCreateChannelArgs(args) {
|
|
4776
5067
|
requireArg(args.channelName, "--channel-name");
|
|
4777
|
-
requireArg(args.
|
|
5068
|
+
requireArg(args.joinToll, "--join-toll");
|
|
4778
5069
|
requireNetworkName(args);
|
|
4779
5070
|
requireAlchemyApiKeyForPublicNetwork(args, "create-channel");
|
|
4780
5071
|
requireArg(args.privateKey, "--private-key");
|
|
4781
5072
|
assertAllowedCommandKeys(
|
|
4782
5073
|
args,
|
|
4783
5074
|
"create-channel",
|
|
4784
|
-
new Set(["command", "positional", "channelName", "
|
|
4785
|
-
"--channel-name, --join-
|
|
5075
|
+
new Set(["command", "positional", "channelName", "joinToll", "network", "alchemyApiKey", "privateKey"]),
|
|
5076
|
+
"--channel-name, --join-toll, --network, --private-key, and --alchemy-api-key on public networks",
|
|
4786
5077
|
);
|
|
4787
5078
|
}
|
|
4788
5079
|
|
|
@@ -4944,8 +5235,9 @@ Commands:
|
|
|
4944
5235
|
--doctor
|
|
4945
5236
|
Check private-state CLI package versions, runtime install state, Docker mode, CUDA mode, and deployment artifacts
|
|
4946
5237
|
|
|
4947
|
-
create-channel --channel-name <NAME> --join-
|
|
5238
|
+
create-channel --channel-name <NAME> --join-toll <TOKENS> --network <NAME> --private-key <HEX> --alchemy-api-key <KEY>
|
|
4948
5239
|
Create a bridge channel and initialize its workspace
|
|
5240
|
+
Prints the immutable policy snapshot before sending the transaction
|
|
4949
5241
|
|
|
4950
5242
|
recover-workspace --channel-name <NAME> --network <NAME> --alchemy-api-key <KEY>
|
|
4951
5243
|
Rebuild the local channel workspace from bridge state
|
|
@@ -4963,7 +5255,8 @@ Commands:
|
|
|
4963
5255
|
Rebuild a recoverable local wallet from on-chain channel state
|
|
4964
5256
|
|
|
4965
5257
|
join-channel --channel-name <NAME> --password <PASSWORD> --network <NAME> --private-key <HEX> --alchemy-api-key <KEY>
|
|
4966
|
-
Pay the channel join
|
|
5258
|
+
Pay the channel join toll and bind a wallet to a channel-specific L2 identity
|
|
5259
|
+
Prints the immutable policy snapshot before first registration
|
|
4967
5260
|
|
|
4968
5261
|
get-my-wallet-meta --wallet <NAME> --password <PASSWORD> --network <NAME>
|
|
4969
5262
|
Check whether a wallet matches the on-chain channel registration
|
|
@@ -5198,11 +5491,7 @@ function expect(condition, message) {
|
|
|
5198
5491
|
}
|
|
5199
5492
|
|
|
5200
5493
|
function requireSemverVersion(value, label) {
|
|
5201
|
-
|
|
5202
|
-
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.]+)?(?:\+[0-9A-Za-z.]+)?$/.test(normalized)) {
|
|
5203
|
-
throw new Error(`${label} must be an exact semantic version. Received: ${normalized}`);
|
|
5204
|
-
}
|
|
5205
|
-
return normalized;
|
|
5494
|
+
return requireExactSemverVersion(value, label);
|
|
5206
5495
|
}
|
|
5207
5496
|
|
|
5208
5497
|
function resolveArtifactCacheBaseRoot(
|
|
@@ -5386,22 +5675,41 @@ function buildDoctorReport() {
|
|
|
5386
5675
|
|
|
5387
5676
|
function buildSelectedRuntimeVersionCheck({ installManifest, tokamakCli, groth16Runtime }) {
|
|
5388
5677
|
const selectedVersions = installManifest?.install?.selectedVersions ?? null;
|
|
5678
|
+
const selectedTokamakCompatibleBackendVersion = selectedVersions?.tokamak
|
|
5679
|
+
? normalizePackageVersionToCompatibleBackendVersion(
|
|
5680
|
+
selectedVersions.tokamak,
|
|
5681
|
+
"selected Tokamak zk-EVM CLI version",
|
|
5682
|
+
)
|
|
5683
|
+
: null;
|
|
5684
|
+
const selectedGroth16CompatibleBackendVersion = selectedVersions?.groth16
|
|
5685
|
+
? normalizePackageVersionToCompatibleBackendVersion(selectedVersions.groth16, "selected Groth16 CLI version")
|
|
5686
|
+
: null;
|
|
5389
5687
|
const details = [
|
|
5390
5688
|
{
|
|
5391
5689
|
name: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
|
|
5392
5690
|
selectedVersion: selectedVersions?.tokamak ?? null,
|
|
5691
|
+
selectedCompatibleBackendVersion: selectedTokamakCompatibleBackendVersion,
|
|
5393
5692
|
installedVersion: tokamakCli.packageVersion ?? null,
|
|
5394
|
-
|
|
5693
|
+
compatibleBackendVersion: tokamakCli.compatibleBackendVersion ?? null,
|
|
5694
|
+
ok: !selectedVersions?.tokamak
|
|
5695
|
+
|| (
|
|
5696
|
+
selectedVersions.tokamak === tokamakCli.packageVersion
|
|
5697
|
+
&& selectedTokamakCompatibleBackendVersion === tokamakCli.compatibleBackendVersion
|
|
5698
|
+
),
|
|
5395
5699
|
},
|
|
5396
5700
|
{
|
|
5397
5701
|
name: GROTH16_PACKAGE_NAME,
|
|
5398
5702
|
selectedVersion: selectedVersions?.groth16 ?? null,
|
|
5703
|
+
selectedCompatibleBackendVersion: selectedGroth16CompatibleBackendVersion,
|
|
5399
5704
|
installedVersion: groth16Runtime.packageVersion ?? null,
|
|
5705
|
+
compatibleBackendVersion: groth16Runtime.compatibleBackendVersion ?? null,
|
|
5400
5706
|
crsVersion: groth16Runtime.crsVersion ?? null,
|
|
5707
|
+
crsCompatibleBackendVersion: groth16Runtime.crsCompatibleBackendVersion ?? null,
|
|
5401
5708
|
ok: !selectedVersions?.groth16
|
|
5402
5709
|
|| (
|
|
5403
5710
|
selectedVersions.groth16 === groth16Runtime.packageVersion
|
|
5404
|
-
&&
|
|
5711
|
+
&& selectedGroth16CompatibleBackendVersion === groth16Runtime.compatibleBackendVersion
|
|
5712
|
+
&& selectedGroth16CompatibleBackendVersion === groth16Runtime.crsCompatibleBackendVersion
|
|
5405
5713
|
),
|
|
5406
5714
|
},
|
|
5407
5715
|
];
|
|
@@ -5414,11 +5722,7 @@ function buildSelectedRuntimeVersionCheck({ installManifest, tokamakCli, groth16
|
|
|
5414
5722
|
|
|
5415
5723
|
async function resolvePrivateStateInstallRuntimeVersions(args) {
|
|
5416
5724
|
const [groth16, tokamak] = await Promise.all([
|
|
5417
|
-
|
|
5418
|
-
packageName: GROTH16_PACKAGE_NAME,
|
|
5419
|
-
requestedVersion: args.groth16CliVersion,
|
|
5420
|
-
optionName: "--groth16-cli-version",
|
|
5421
|
-
}),
|
|
5725
|
+
resolveRequestedGroth16PackageVersion(args.groth16CliVersion),
|
|
5422
5726
|
resolveRequestedNpmPackageVersion({
|
|
5423
5727
|
packageName: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
|
|
5424
5728
|
requestedVersion: args.tokamakZkEvmCliVersion,
|
|
@@ -5428,6 +5732,19 @@ async function resolvePrivateStateInstallRuntimeVersions(args) {
|
|
|
5428
5732
|
return { groth16, tokamak };
|
|
5429
5733
|
}
|
|
5430
5734
|
|
|
5735
|
+
async function resolveRequestedGroth16PackageVersion(requestedVersion) {
|
|
5736
|
+
if (requestedVersion !== undefined && requestedVersion !== null) {
|
|
5737
|
+
return resolveRequestedNpmPackageVersion({
|
|
5738
|
+
packageName: GROTH16_PACKAGE_NAME,
|
|
5739
|
+
requestedVersion,
|
|
5740
|
+
optionName: "--groth16-cli-version",
|
|
5741
|
+
});
|
|
5742
|
+
}
|
|
5743
|
+
|
|
5744
|
+
const bundledPackageJson = readJson(path.join(resolveGroth16PackageRoot(), "package.json"));
|
|
5745
|
+
return requireSemverVersion(bundledPackageJson.version, `${GROTH16_PACKAGE_NAME} bundled package version`);
|
|
5746
|
+
}
|
|
5747
|
+
|
|
5431
5748
|
async function resolveRequestedNpmPackageVersion({ packageName, requestedVersion, optionName }) {
|
|
5432
5749
|
const metadata = await fetchNpmPackageMetadata(packageName);
|
|
5433
5750
|
if (requestedVersion === undefined || requestedVersion === null) {
|
|
@@ -5441,20 +5758,6 @@ async function resolveRequestedNpmPackageVersion({ packageName, requestedVersion
|
|
|
5441
5758
|
return normalizedVersion;
|
|
5442
5759
|
}
|
|
5443
5760
|
|
|
5444
|
-
async function fetchNpmPackageMetadata(packageName) {
|
|
5445
|
-
const normalizedPackageName = requireNonEmptyString(packageName, "packageName");
|
|
5446
|
-
const registryUrl = `https://registry.npmjs.org/${encodeURIComponent(normalizedPackageName)}`;
|
|
5447
|
-
const response = await fetch(registryUrl, { redirect: "follow" });
|
|
5448
|
-
if (!response.ok) {
|
|
5449
|
-
throw new Error(`Failed to read npm package metadata for ${normalizedPackageName}: HTTP ${response.status}.`);
|
|
5450
|
-
}
|
|
5451
|
-
try {
|
|
5452
|
-
return await response.json();
|
|
5453
|
-
} catch (error) {
|
|
5454
|
-
throw new Error(`npm package metadata for ${normalizedPackageName} is not valid JSON: ${error.message}`);
|
|
5455
|
-
}
|
|
5456
|
-
}
|
|
5457
|
-
|
|
5458
5761
|
async function installTokamakCliRuntimeForPrivateState({ version, docker }) {
|
|
5459
5762
|
const packageInstall = installManagedNpmPackage({
|
|
5460
5763
|
packageName: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
|
|
@@ -5471,6 +5774,7 @@ async function installTokamakCliRuntimeForPrivateState({ version, docker }) {
|
|
|
5471
5774
|
});
|
|
5472
5775
|
const doctorOutput = stripAnsi(`${doctor.stdout}${doctor.stderr}`);
|
|
5473
5776
|
const runtimeRoot = parseRuntimeRootFromTokamakDoctorOutput(doctorOutput);
|
|
5777
|
+
const compatibleBackendVersion = readTokamakCliPackageCompatibleBackendVersion(packageInstall.packageRoot);
|
|
5474
5778
|
expect(
|
|
5475
5779
|
doctor.status === 0 && runtimeRoot,
|
|
5476
5780
|
[
|
|
@@ -5481,6 +5785,7 @@ async function installTokamakCliRuntimeForPrivateState({ version, docker }) {
|
|
|
5481
5785
|
return {
|
|
5482
5786
|
packageName: TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
|
|
5483
5787
|
packageVersion: version,
|
|
5788
|
+
compatibleBackendVersion,
|
|
5484
5789
|
packageRoot: packageInstall.packageRoot,
|
|
5485
5790
|
entryPath: invocation.entryPath,
|
|
5486
5791
|
installPrefix: packageInstall.installPrefix,
|
|
@@ -5490,10 +5795,7 @@ async function installTokamakCliRuntimeForPrivateState({ version, docker }) {
|
|
|
5490
5795
|
}
|
|
5491
5796
|
|
|
5492
5797
|
async function installGroth16RuntimeForPrivateState({ version, docker }) {
|
|
5493
|
-
const packageInstall =
|
|
5494
|
-
packageName: GROTH16_PACKAGE_NAME,
|
|
5495
|
-
version,
|
|
5496
|
-
});
|
|
5798
|
+
const packageInstall = resolveGroth16RuntimePackageInstall(version);
|
|
5497
5799
|
const packageRoot = packageInstall.packageRoot;
|
|
5498
5800
|
const entryPath = resolveGroth16CliEntryPath(packageRoot);
|
|
5499
5801
|
const args = [entryPath, "--install", "--no-setup"];
|
|
@@ -5501,13 +5803,15 @@ async function installGroth16RuntimeForPrivateState({ version, docker }) {
|
|
|
5501
5803
|
args.push("--docker");
|
|
5502
5804
|
}
|
|
5503
5805
|
run(process.execPath, args, { cwd: packageRoot });
|
|
5504
|
-
const
|
|
5806
|
+
const compatibleBackendVersion = readGroth16PackageCompatibleBackendVersion(packageRoot);
|
|
5807
|
+
const crsInstall = await installGroth16CrsForPrivateStateVersion(compatibleBackendVersion);
|
|
5505
5808
|
const runtime = inspectGroth16Runtime({ packageRoot });
|
|
5506
5809
|
expect(runtime.installed, "Groth16 runtime install completed, but tokamak-groth16 --doctor still reports an unhealthy runtime.");
|
|
5507
5810
|
return {
|
|
5508
5811
|
...runtime,
|
|
5509
5812
|
packageName: GROTH16_PACKAGE_NAME,
|
|
5510
5813
|
packageVersion: version,
|
|
5814
|
+
compatibleBackendVersion,
|
|
5511
5815
|
packageRoot,
|
|
5512
5816
|
entryPath,
|
|
5513
5817
|
installPrefix: packageInstall.installPrefix,
|
|
@@ -5517,9 +5821,32 @@ async function installGroth16RuntimeForPrivateState({ version, docker }) {
|
|
|
5517
5821
|
};
|
|
5518
5822
|
}
|
|
5519
5823
|
|
|
5824
|
+
function resolveGroth16RuntimePackageInstall(version) {
|
|
5825
|
+
const normalizedVersion = requireSemverVersion(version, `${GROTH16_PACKAGE_NAME} version`);
|
|
5826
|
+
const bundledPackageRoot = resolveGroth16PackageRoot();
|
|
5827
|
+
const bundledPackageJson = readJson(path.join(bundledPackageRoot, "package.json"));
|
|
5828
|
+
if (bundledPackageJson.name === GROTH16_PACKAGE_NAME && bundledPackageJson.version === normalizedVersion) {
|
|
5829
|
+
return {
|
|
5830
|
+
packageName: GROTH16_PACKAGE_NAME,
|
|
5831
|
+
version: normalizedVersion,
|
|
5832
|
+
installPrefix: null,
|
|
5833
|
+
packageRoot: bundledPackageRoot,
|
|
5834
|
+
};
|
|
5835
|
+
}
|
|
5836
|
+
|
|
5837
|
+
return installManagedNpmPackage({
|
|
5838
|
+
packageName: GROTH16_PACKAGE_NAME,
|
|
5839
|
+
version: normalizedVersion,
|
|
5840
|
+
});
|
|
5841
|
+
}
|
|
5842
|
+
|
|
5520
5843
|
async function installGroth16CrsForPrivateStateVersion(version) {
|
|
5521
5844
|
const workspaceRoot = defaultGroth16WorkspaceRoot();
|
|
5522
5845
|
const crsDir = path.join(workspaceRoot, "crs");
|
|
5846
|
+
const existingInstall = readExistingGroth16CrsInstall({ version, crsDir });
|
|
5847
|
+
if (existingInstall) {
|
|
5848
|
+
return existingInstall;
|
|
5849
|
+
}
|
|
5523
5850
|
const crsInstall = await downloadPublicGroth16MpcArtifactsByVersion({
|
|
5524
5851
|
version,
|
|
5525
5852
|
outputDir: crsDir,
|
|
@@ -5541,6 +5868,56 @@ async function installGroth16CrsForPrivateStateVersion(version) {
|
|
|
5541
5868
|
return crsInstall;
|
|
5542
5869
|
}
|
|
5543
5870
|
|
|
5871
|
+
function readExistingGroth16CrsInstall({ version, crsDir }) {
|
|
5872
|
+
const normalizedVersion = requireCanonicalGroth16CompatibleBackendVersion(version, "Groth16 MPC CRS version");
|
|
5873
|
+
const selectedFiles = [
|
|
5874
|
+
"circuit_final.zkey",
|
|
5875
|
+
"verification_key.json",
|
|
5876
|
+
"metadata.json",
|
|
5877
|
+
"zkey_provenance.json",
|
|
5878
|
+
];
|
|
5879
|
+
const targetPaths = selectedFiles.map((fileName) => path.join(crsDir, fileName));
|
|
5880
|
+
if (!targetPaths.every((targetPath) => fs.existsSync(targetPath))) {
|
|
5881
|
+
return null;
|
|
5882
|
+
}
|
|
5883
|
+
const metadata = readJson(path.join(crsDir, "metadata.json"));
|
|
5884
|
+
let metadataVersion;
|
|
5885
|
+
try {
|
|
5886
|
+
metadataVersion = requireCanonicalGroth16CompatibleBackendVersion(
|
|
5887
|
+
metadata.compatibleBackendVersion,
|
|
5888
|
+
"installed Groth16 MPC CRS version",
|
|
5889
|
+
);
|
|
5890
|
+
} catch {
|
|
5891
|
+
return null;
|
|
5892
|
+
}
|
|
5893
|
+
if (metadataVersion !== normalizedVersion) {
|
|
5894
|
+
return null;
|
|
5895
|
+
}
|
|
5896
|
+
const provenance = readJson(path.join(crsDir, "zkey_provenance.json"));
|
|
5897
|
+
return {
|
|
5898
|
+
source: "local-cache",
|
|
5899
|
+
archiveName: provenance.published_archive_name ?? null,
|
|
5900
|
+
archiveFileId: parseDriveFileIdFromDownloadUrl(provenance.zkey_download_url),
|
|
5901
|
+
folderUrl: provenance.published_folder_url ?? null,
|
|
5902
|
+
version: normalizedVersion,
|
|
5903
|
+
installedFiles: selectedFiles.map((archivePath, index) => ({
|
|
5904
|
+
archivePath,
|
|
5905
|
+
targetPath: targetPaths[index],
|
|
5906
|
+
})),
|
|
5907
|
+
};
|
|
5908
|
+
}
|
|
5909
|
+
|
|
5910
|
+
function parseDriveFileIdFromDownloadUrl(value) {
|
|
5911
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
5912
|
+
return null;
|
|
5913
|
+
}
|
|
5914
|
+
try {
|
|
5915
|
+
return new URL(value).searchParams.get("id");
|
|
5916
|
+
} catch {
|
|
5917
|
+
return null;
|
|
5918
|
+
}
|
|
5919
|
+
}
|
|
5920
|
+
|
|
5544
5921
|
function installManagedNpmPackage({ packageName, version, cacheBaseRoot = resolveArtifactCacheBaseRoot() }) {
|
|
5545
5922
|
const normalizedPackageName = requireNonEmptyString(packageName, "packageName");
|
|
5546
5923
|
const normalizedVersion = requireSemverVersion(version, `${normalizedPackageName} version`);
|
|
@@ -5625,15 +6002,15 @@ function collectDependencyPackageReports(installManifest = null) {
|
|
|
5625
6002
|
});
|
|
5626
6003
|
}
|
|
5627
6004
|
|
|
5628
|
-
function readPackageReport({ name, packageJsonPath = null, resolveTarget = null }) {
|
|
6005
|
+
function readPackageReport({ name, packageJsonPath = null, packageJson = null, resolveTarget = null }) {
|
|
5629
6006
|
try {
|
|
5630
6007
|
const resolvedPackageJsonPath = packageJsonPath
|
|
5631
6008
|
? path.resolve(packageJsonPath)
|
|
5632
6009
|
: findPackageJsonForName(path.dirname(require.resolve(resolveTarget ?? name)), name);
|
|
5633
|
-
const
|
|
6010
|
+
const resolvedPackageJson = packageJson ?? readJson(resolvedPackageJsonPath);
|
|
5634
6011
|
return {
|
|
5635
|
-
name:
|
|
5636
|
-
version:
|
|
6012
|
+
name: resolvedPackageJson.name ?? name,
|
|
6013
|
+
version: resolvedPackageJson.version ?? null,
|
|
5637
6014
|
packageRoot: path.dirname(resolvedPackageJsonPath),
|
|
5638
6015
|
error: null,
|
|
5639
6016
|
};
|
|
@@ -5668,6 +6045,20 @@ function resolveGroth16PackageRoot() {
|
|
|
5668
6045
|
return path.dirname(findPackageJsonForName(path.dirname(publicDriveCrsPath), "@tokamak-private-dapps/groth16"));
|
|
5669
6046
|
}
|
|
5670
6047
|
|
|
6048
|
+
function readGroth16PackageCompatibleBackendVersion(packageRoot = resolveActiveGroth16PackageRoot()) {
|
|
6049
|
+
return readGroth16CompatibleBackendVersionFromPackageJson(
|
|
6050
|
+
readJson(path.join(packageRoot, "package.json")),
|
|
6051
|
+
GROTH16_PACKAGE_NAME,
|
|
6052
|
+
);
|
|
6053
|
+
}
|
|
6054
|
+
|
|
6055
|
+
function readTokamakCliPackageCompatibleBackendVersion(packageRoot = resolveActiveTokamakCliPackageRoot()) {
|
|
6056
|
+
return readTokamakZkEvmCompatibleBackendVersionFromPackageJson(
|
|
6057
|
+
readJson(path.join(packageRoot, "package.json")),
|
|
6058
|
+
TOKAMAK_ZKEVM_CLI_PACKAGE_NAME,
|
|
6059
|
+
);
|
|
6060
|
+
}
|
|
6061
|
+
|
|
5671
6062
|
function resolveActiveGroth16PackageRoot() {
|
|
5672
6063
|
const manifestPackageRoot = readPrivateStateCliInstallManifest()?.install?.groth16Runtime?.packageRoot;
|
|
5673
6064
|
if (manifestPackageRoot && fs.existsSync(path.join(manifestPackageRoot, "package.json"))) {
|
|
@@ -5692,17 +6083,24 @@ function inspectGroth16Runtime({ packageRoot = resolveActiveGroth16PackageRoot()
|
|
|
5692
6083
|
const report = parseJsonReport(stdout);
|
|
5693
6084
|
const workspaceRoot = report?.workspaceRoot ?? defaultGroth16WorkspaceRoot();
|
|
5694
6085
|
const workspaceManifest = readJsonIfExists(path.join(workspaceRoot, "install-manifest.json"));
|
|
6086
|
+
const crsVersion = workspaceManifest?.crs?.version ?? null;
|
|
5695
6087
|
const packageReport = readPackageReport({
|
|
5696
6088
|
name: GROTH16_PACKAGE_NAME,
|
|
5697
6089
|
packageJsonPath: path.join(packageRoot, "package.json"),
|
|
5698
6090
|
});
|
|
6091
|
+
const compatibleBackendVersion = readGroth16PackageCompatibleBackendVersion(packageRoot);
|
|
6092
|
+
const crsCompatibleBackendVersion = crsVersion
|
|
6093
|
+
? requireCanonicalGroth16CompatibleBackendVersion(crsVersion, "installed Groth16 CRS version")
|
|
6094
|
+
: null;
|
|
5699
6095
|
return {
|
|
5700
6096
|
installed: doctor.status === 0 && report?.ok === true,
|
|
5701
6097
|
packageVersion: packageReport.version,
|
|
6098
|
+
compatibleBackendVersion,
|
|
5702
6099
|
packageRoot,
|
|
5703
6100
|
entryPath,
|
|
5704
6101
|
workspaceRoot: report?.workspaceRoot ?? null,
|
|
5705
|
-
crsVersion
|
|
6102
|
+
crsVersion,
|
|
6103
|
+
crsCompatibleBackendVersion,
|
|
5706
6104
|
crs: workspaceManifest?.crs ?? null,
|
|
5707
6105
|
checks: report?.checks ?? [],
|
|
5708
6106
|
doctor: {
|
|
@@ -5746,6 +6144,7 @@ function requireActiveTokamakCliRuntimeRoot() {
|
|
|
5746
6144
|
|
|
5747
6145
|
function inspectTokamakCliRuntime({ packageRoot = resolveActiveTokamakCliPackageRoot() } = {}) {
|
|
5748
6146
|
const invocation = buildTokamakCliInvocationForPackageRoot(packageRoot);
|
|
6147
|
+
const packageReport = readTokamakCliPackageReport(invocation.packageRoot);
|
|
5749
6148
|
const doctor = runCaptured(invocation.command, [...invocation.args, "--doctor"], {
|
|
5750
6149
|
cwd: invocation.packageRoot,
|
|
5751
6150
|
});
|
|
@@ -5762,10 +6161,9 @@ function inspectTokamakCliRuntime({ packageRoot = resolveActiveTokamakCliPackage
|
|
|
5762
6161
|
entryPath: invocation.entryPath,
|
|
5763
6162
|
cacheRoot,
|
|
5764
6163
|
runtimeRoot,
|
|
5765
|
-
packageVersion:
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
}).version,
|
|
6164
|
+
packageVersion: packageReport.version,
|
|
6165
|
+
compatibleBackendVersion: packageReport.compatibleBackendVersion,
|
|
6166
|
+
packageError: packageReport.error,
|
|
5769
6167
|
dockerModeInstalled,
|
|
5770
6168
|
cudaCompatible,
|
|
5771
6169
|
doctor: {
|