@tokamak-private-dapps/private-state-cli 0.1.2 → 0.1.3
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 +7 -0
- package/README.md +71 -4
- package/cli-assistant.html +3 -1
- package/package.json +1 -1
- package/private-state-bridge-cli.mjs +281 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.3 - 2026-04-28
|
|
4
|
+
|
|
5
|
+
- Installed the Groth16 runtime during `private-state-cli --install` and reported Groth16 readiness from `--doctor`.
|
|
6
|
+
- Added live NVIDIA and Docker GPU probes to `--doctor`, with a hard failure when live Docker GPU readiness does not match the recorded Tokamak CLI metadata.
|
|
7
|
+
- Renamed `get-my-address` to `get-my-wallet-meta`, added `get-my-l1-address`, and added `list-local-wallets`.
|
|
8
|
+
- Documented the private-state CLI helper commands, common flow examples, and LLM agent guidance.
|
|
9
|
+
|
|
3
10
|
## 0.1.2 - 2026-04-28
|
|
4
11
|
|
|
5
12
|
- Added `private-state-cli --doctor` to report CLI and install-time dependency versions through `tokamak-l2js`.
|
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ Command-line client for the Tokamak private-state DApp.
|
|
|
8
8
|
npm install -g @tokamak-private-dapps/private-state-cli
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Install the local Tokamak zk-EVM runtime workspace and public private-state deployment
|
|
11
|
+
Install the local Tokamak zk-EVM runtime workspace, Groth16 runtime workspace, and public private-state deployment
|
|
12
|
+
artifacts:
|
|
12
13
|
|
|
13
14
|
```bash
|
|
14
15
|
private-state-cli --install
|
|
@@ -35,7 +36,7 @@ private-state-cli --doctor
|
|
|
35
36
|
|
|
36
37
|
## Commands
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
A common private-state flow is:
|
|
39
40
|
|
|
40
41
|
1. `create-channel`
|
|
41
42
|
2. `deposit-bridge`
|
|
@@ -52,7 +53,21 @@ Use `private-state-cli --help` for the full command list and required options.
|
|
|
52
53
|
|
|
53
54
|
`private-state-cli --doctor` reports the CLI package version, dependency versions recorded by the last
|
|
54
55
|
`private-state-cli --install`, current dependency versions through `tokamak-l2js`, and Tokamak zk-EVM runtime
|
|
55
|
-
install mode, Docker mode,
|
|
56
|
+
install mode, Docker mode, CUDA runtime metadata, live `nvidia-smi` and Docker GPU probe results, and Groth16
|
|
57
|
+
runtime health. The doctor check fails when the Tokamak Docker `useGpus` metadata does not match the live GPU probes.
|
|
58
|
+
|
|
59
|
+
Local helper commands:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
private-state-cli list-local-wallets --network sepolia --channel-name cuda
|
|
63
|
+
private-state-cli get-my-wallet-meta --wallet <WALLET_NAME> --password <PASSWORD> --network sepolia
|
|
64
|
+
private-state-cli get-my-l1-address --private-key <HEX>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`list-local-wallets` reads only the local workspace and prints saved wallet names that can be reused with `--wallet`.
|
|
68
|
+
`get-my-wallet-meta` opens an encrypted local wallet and reports the stored L1/L2 identity metadata plus the current
|
|
69
|
+
on-chain channel registration match state. `get-my-l1-address` is a simple offline helper that derives the L1 address
|
|
70
|
+
for a private key.
|
|
56
71
|
|
|
57
72
|
## Workspace
|
|
58
73
|
|
|
@@ -64,6 +79,57 @@ The CLI stores user workspaces under:
|
|
|
64
79
|
|
|
65
80
|
Wallet data is encrypted with the password supplied to `join-channel` or `recover-wallet`.
|
|
66
81
|
|
|
82
|
+
## LLM Agent Guidance
|
|
83
|
+
|
|
84
|
+
You may act as an interactive guide for users who do not understand this CLI or the private-state DApp. Assume the
|
|
85
|
+
user only knows that the DApp is a way to send funds privately. Translate the user's intent into safe, step-by-step CLI
|
|
86
|
+
actions.
|
|
87
|
+
|
|
88
|
+
Primary goal: help the user privately send funds by guiding them through the required private-state CLI commands,
|
|
89
|
+
explaining each step only as much as needed to proceed safely.
|
|
90
|
+
|
|
91
|
+
Operating rules:
|
|
92
|
+
|
|
93
|
+
- Do not ask the user to reveal raw private keys in chat. Use environment variable placeholders such as `$ADDR6`,
|
|
94
|
+
`$CREATOR`, or `$PRIVATE_STATE_TEST_PK`.
|
|
95
|
+
- Prefer testnet examples unless the user explicitly asks for mainnet.
|
|
96
|
+
- Before any proof-backed or bridge-facing workflow, ask the user to run `private-state-cli --doctor` and inspect
|
|
97
|
+
whether the runtime, Docker mode, CUDA/GPU probes, Groth16 runtime, and deployment artifacts are healthy.
|
|
98
|
+
- Use `private-state-cli list-local-wallets` to discover local wallet names instead of asking the user to inspect
|
|
99
|
+
filesystem paths manually.
|
|
100
|
+
- Use `private-state-cli get-my-l1-address --private-key "$KEY_ENV"` to derive the L1 address for a private-key
|
|
101
|
+
environment variable when wallet ownership needs to be identified.
|
|
102
|
+
- Use `private-state-cli get-my-wallet-meta --wallet <WALLET> --password <PASSWORD> --network <NETWORK>` to inspect
|
|
103
|
+
local wallet metadata and on-chain channel registration state.
|
|
104
|
+
- Use `private-state-cli get-my-bridge-fund` and `private-state-cli get-my-channel-fund` to check balances before
|
|
105
|
+
telling the user to move funds.
|
|
106
|
+
- Explain that wallet names are local CLI identifiers, while private transfers use notes owned by L2 addresses
|
|
107
|
+
registered in the channel.
|
|
108
|
+
- Do not present one fixed command sequence as universally correct. Some flows start from an existing channel or wallet,
|
|
109
|
+
while others require creating or joining a channel first.
|
|
110
|
+
- When the user asks for a transfer, first determine whether the sender has minted notes available. If not, guide them
|
|
111
|
+
through funding the bridge, joining or recovering the channel wallet, depositing into the channel, and minting notes.
|
|
112
|
+
- When generating commands, use placeholders for secrets and explicit values for public fields. Show one command at a
|
|
113
|
+
time unless the user asks for a batch.
|
|
114
|
+
|
|
115
|
+
Suggested interaction flow:
|
|
116
|
+
|
|
117
|
+
1. Identify the target network, usually `sepolia` for testing.
|
|
118
|
+
2. Identify whether a channel already exists.
|
|
119
|
+
3. Identify the sender and recipient wallets or private-key environment variables.
|
|
120
|
+
4. Run `--doctor`.
|
|
121
|
+
5. Run `list-local-wallets` and relevant metadata or balance checks.
|
|
122
|
+
6. If needed, guide the user through `create-channel`, `deposit-bridge`, `join-channel`, `deposit-channel`, and
|
|
123
|
+
`mint-notes`.
|
|
124
|
+
7. For a private transfer, select available note IDs from `get-my-notes`, find the recipient L2 address from
|
|
125
|
+
`get-my-wallet-meta`, then build `transfer-notes`.
|
|
126
|
+
8. After transfer, guide the recipient to run `get-my-notes` to recover received notes from event logs.
|
|
127
|
+
|
|
128
|
+
Example style: if the user says, "ADDR6 sends 10 tokens privately to ADDR8", do not assume the required note exists.
|
|
129
|
+
First ask or check which channel and network to use, whether ADDR6 and ADDR8 are already joined, what the local wallet
|
|
130
|
+
names are, and whether ADDR6 has an unused note worth exactly 10 or notes that sum to 10. Then provide the next concrete
|
|
131
|
+
command.
|
|
132
|
+
|
|
67
133
|
## Artifacts
|
|
68
134
|
|
|
69
135
|
Proof-backed commands require installed bridge, DApp, and Groth16 artifacts. Run `private-state-cli --install` before
|
|
@@ -81,7 +147,8 @@ Release order matters for npm publication. `@tokamak-private-dapps/common-librar
|
|
|
81
147
|
### What does this package install?
|
|
82
148
|
|
|
83
149
|
It installs the `private-state-cli` terminal command and the local files needed by that command.
|
|
84
|
-
It does not install bridge contracts, app contracts, or local deployment outputs.
|
|
150
|
+
It does not install bridge contracts, app contracts, or local deployment outputs. The `private-state-cli --install`
|
|
151
|
+
command provisions the local Tokamak zk-EVM and Groth16 runtime workspaces used by proof-backed commands.
|
|
85
152
|
|
|
86
153
|
### When should I run `private-state-cli --install`?
|
|
87
154
|
|
package/cli-assistant.html
CHANGED
|
@@ -528,7 +528,9 @@
|
|
|
528
528
|
{ id: "get-my-bridge-fund", description: "Read the current bridge-vault balance.", fields: ["network", "privateKey", "alchemyApiKey"] },
|
|
529
529
|
{ id: "join-channel", description: "Bind the caller to a channel-specific L2 identity.", fields: ["channelName", "password", "network", "privateKey", "alchemyApiKey"] },
|
|
530
530
|
{ id: "recover-wallet", description: "Rebuild the recoverable portion of a wallet.", fields: ["channelName", "password", "network", "privateKey", "alchemyApiKey"] },
|
|
531
|
-
{ id: "get-my-
|
|
531
|
+
{ id: "get-my-wallet-meta", description: "Check whether a saved wallet matches on-chain registration.", fields: ["wallet", "password", "network"] },
|
|
532
|
+
{ id: "get-my-l1-address", description: "Derive the L1 address for a private key.", fields: ["privateKey"] },
|
|
533
|
+
{ id: "list-local-wallets", description: "List saved local wallet names that can be reused with --wallet.", fields: ["network", "channelName"] },
|
|
532
534
|
{ id: "deposit-channel", description: "Move bridged funds into the channel L2 accounting balance.", fields: ["wallet", "password", "network", "amount"] },
|
|
533
535
|
{ id: "withdraw-channel", description: "Move channel L2 balance back into the shared bridge vault.", fields: ["wallet", "password", "network", "amount"] },
|
|
534
536
|
{ id: "get-my-channel-fund", description: "Read the current channel L2 accounting balance.", fields: ["wallet", "password", "network"] },
|
package/package.json
CHANGED
|
@@ -90,6 +90,8 @@ const tokamakCliInvocation = buildTokamakCliInvocation();
|
|
|
90
90
|
const tokamakCliCommand = tokamakCliInvocation.command;
|
|
91
91
|
const tokamakCliBaseArgs = tokamakCliInvocation.args;
|
|
92
92
|
const flatDeploymentArtifactPathsByChainId = new Map();
|
|
93
|
+
const DOCKER_CUDA_PROBE_IMAGE = "nvidia/cuda:12.2.0-base-ubuntu22.04";
|
|
94
|
+
const DOCTOR_GPU_PROBE_TIMEOUT_MS = 120000;
|
|
93
95
|
|
|
94
96
|
const abiCoder = AbiCoder.defaultAbiCoder();
|
|
95
97
|
const erc20MetadataAbi = [
|
|
@@ -231,6 +233,18 @@ async function main() {
|
|
|
231
233
|
return;
|
|
232
234
|
}
|
|
233
235
|
|
|
236
|
+
if (args.command === "get-my-l1-address") {
|
|
237
|
+
assertGetMyL1AddressArgs(args);
|
|
238
|
+
handleGetMyL1Address({ args });
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (args.command === "list-local-wallets") {
|
|
243
|
+
assertListLocalWalletsArgs(args);
|
|
244
|
+
handleListLocalWallets({ args });
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
234
248
|
const walletCommandHandlers = {
|
|
235
249
|
"mint-notes": {
|
|
236
250
|
assert: assertMintNotesArgs,
|
|
@@ -256,9 +270,9 @@ async function main() {
|
|
|
256
270
|
assert: (parsedArgs) => assertWalletChannelMoveArgs(parsedArgs, "withdraw-channel"),
|
|
257
271
|
run: ({ provider }) => handleGrothVaultMove({ args, provider, direction: "withdraw" }),
|
|
258
272
|
},
|
|
259
|
-
"get-my-
|
|
260
|
-
assert:
|
|
261
|
-
run: ({ provider }) =>
|
|
273
|
+
"get-my-wallet-meta": {
|
|
274
|
+
assert: assertGetMyWalletMetaArgs,
|
|
275
|
+
run: ({ provider }) => handleGetMyWalletMeta({ args, provider }),
|
|
262
276
|
},
|
|
263
277
|
"get-my-channel-fund": {
|
|
264
278
|
assert: assertGetMyChannelFundArgs,
|
|
@@ -942,6 +956,9 @@ async function handleInstallZkEvm({ args }) {
|
|
|
942
956
|
}
|
|
943
957
|
run(tokamakCliCommand, installArgs);
|
|
944
958
|
const tokamakRuntimeRoot = resolveTokamakCliRuntimeRoot();
|
|
959
|
+
const groth16Runtime = installGroth16RuntimeForPrivateState({
|
|
960
|
+
docker: Boolean(args.docker),
|
|
961
|
+
});
|
|
945
962
|
const localDeploymentBaseRoot = args.includeLocalArtifacts ? process.cwd() : null;
|
|
946
963
|
const deploymentArtifacts = await installPrivateStateCliArtifacts({
|
|
947
964
|
dappName: PRIVATE_STATE_DAPP_LABEL,
|
|
@@ -952,11 +969,13 @@ async function handleInstallZkEvm({ args }) {
|
|
|
952
969
|
includeLocalArtifacts: Boolean(args.includeLocalArtifacts),
|
|
953
970
|
localDeploymentBaseRoot,
|
|
954
971
|
deploymentArtifacts,
|
|
972
|
+
groth16Runtime,
|
|
955
973
|
});
|
|
956
974
|
printJson({
|
|
957
975
|
action: "install",
|
|
958
976
|
tokamakCli: tokamakCliBaseArgs[0],
|
|
959
977
|
runtimeRoot: tokamakRuntimeRoot,
|
|
978
|
+
groth16Runtime,
|
|
960
979
|
docker: Boolean(args.docker),
|
|
961
980
|
includeLocalArtifacts: Boolean(args.includeLocalArtifacts),
|
|
962
981
|
localDeploymentBaseRoot,
|
|
@@ -997,7 +1016,38 @@ async function handleDoctor() {
|
|
|
997
1016
|
}
|
|
998
1017
|
}
|
|
999
1018
|
|
|
1000
|
-
|
|
1019
|
+
function handleGetMyL1Address({ args }) {
|
|
1020
|
+
const privateKey = normalizePrivateKey(requireArg(args.privateKey, "--private-key"));
|
|
1021
|
+
const signer = new Wallet(privateKey);
|
|
1022
|
+
printJson({
|
|
1023
|
+
action: "get-my-l1-address",
|
|
1024
|
+
l1Address: signer.address,
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
function handleListLocalWallets({ args }) {
|
|
1029
|
+
const networkFilter = args.network ? requireNetworkName(args) : null;
|
|
1030
|
+
if (networkFilter) {
|
|
1031
|
+
resolveCliNetwork(networkFilter);
|
|
1032
|
+
}
|
|
1033
|
+
const channelFilter = args.channelName ? slugifyPathComponent(requireArg(args.channelName, "--channel-name")) : null;
|
|
1034
|
+
const wallets = listLocalWallets({
|
|
1035
|
+
networkFilter,
|
|
1036
|
+
channelFilter,
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
printJson({
|
|
1040
|
+
action: "list-local-wallets",
|
|
1041
|
+
workspaceRoot,
|
|
1042
|
+
filters: {
|
|
1043
|
+
network: networkFilter,
|
|
1044
|
+
channelName: args.channelName ?? null,
|
|
1045
|
+
},
|
|
1046
|
+
wallets,
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
async function handleGetMyWalletMeta({ args, provider }) {
|
|
1001
1051
|
const { wallet, walletMetadata } = loadUnlockedWalletWithMetadata(args);
|
|
1002
1052
|
const { signer, l2Identity } = restoreWalletParticipant(wallet, provider);
|
|
1003
1053
|
const context = await loadChannelContext({
|
|
@@ -1015,7 +1065,7 @@ async function handleGetMyAddress({ args, provider }) {
|
|
|
1015
1065
|
=== ethers.toBigInt(normalizeBytes32Hex(expectedStorageKey));
|
|
1016
1066
|
|
|
1017
1067
|
printJson({
|
|
1018
|
-
action: "get-my-
|
|
1068
|
+
action: "get-my-wallet-meta",
|
|
1019
1069
|
wallet: wallet.walletName,
|
|
1020
1070
|
network: walletMetadata.network,
|
|
1021
1071
|
channelName: walletMetadata.channelName,
|
|
@@ -4377,6 +4427,48 @@ function resolveWalletPathCandidates(walletName) {
|
|
|
4377
4427
|
return candidates;
|
|
4378
4428
|
}
|
|
4379
4429
|
|
|
4430
|
+
function listLocalWallets({ networkFilter = null, channelFilter = null } = {}) {
|
|
4431
|
+
if (!fs.existsSync(workspaceRoot)) {
|
|
4432
|
+
return [];
|
|
4433
|
+
}
|
|
4434
|
+
|
|
4435
|
+
const wallets = [];
|
|
4436
|
+
for (const networkEntry of fs.readdirSync(workspaceRoot, { withFileTypes: true })) {
|
|
4437
|
+
if (!networkEntry.isDirectory() || (networkFilter && networkEntry.name !== slugifyPathComponent(networkFilter))) {
|
|
4438
|
+
continue;
|
|
4439
|
+
}
|
|
4440
|
+
const networkDir = path.join(workspaceRoot, networkEntry.name);
|
|
4441
|
+
for (const channelEntry of fs.readdirSync(networkDir, { withFileTypes: true })) {
|
|
4442
|
+
if (!channelEntry.isDirectory() || (channelFilter && channelEntry.name !== channelFilter)) {
|
|
4443
|
+
continue;
|
|
4444
|
+
}
|
|
4445
|
+
const walletsDir = path.join(networkDir, channelEntry.name, "wallets");
|
|
4446
|
+
if (!fs.existsSync(walletsDir)) {
|
|
4447
|
+
continue;
|
|
4448
|
+
}
|
|
4449
|
+
for (const walletEntry of fs.readdirSync(walletsDir, { withFileTypes: true })) {
|
|
4450
|
+
if (!walletEntry.isDirectory()) {
|
|
4451
|
+
continue;
|
|
4452
|
+
}
|
|
4453
|
+
const walletDir = path.join(walletsDir, walletEntry.name);
|
|
4454
|
+
wallets.push({
|
|
4455
|
+
wallet: walletEntry.name,
|
|
4456
|
+
network: networkEntry.name,
|
|
4457
|
+
channelName: channelEntry.name,
|
|
4458
|
+
walletDir,
|
|
4459
|
+
metadataPath: walletMetadataPath(walletDir),
|
|
4460
|
+
hasMetadata: fs.existsSync(walletMetadataPath(walletDir)),
|
|
4461
|
+
hasEncryptedWallet: walletConfigExists(walletDir),
|
|
4462
|
+
});
|
|
4463
|
+
}
|
|
4464
|
+
}
|
|
4465
|
+
}
|
|
4466
|
+
return wallets.sort((left, right) =>
|
|
4467
|
+
[left.network, left.channelName, left.wallet].join("\0")
|
|
4468
|
+
.localeCompare([right.network, right.channelName, right.wallet].join("\0")),
|
|
4469
|
+
);
|
|
4470
|
+
}
|
|
4471
|
+
|
|
4380
4472
|
function channelDataPath(workspaceDir) {
|
|
4381
4473
|
return workspaceChannelDir(workspaceDir);
|
|
4382
4474
|
}
|
|
@@ -4566,8 +4658,33 @@ function assertJoinChannelArgs(args) {
|
|
|
4566
4658
|
assertExplicitSignerPasswordCommandArgs(args, "join-channel");
|
|
4567
4659
|
}
|
|
4568
4660
|
|
|
4569
|
-
function
|
|
4570
|
-
assertWalletPasswordArgs(args, "get-my-
|
|
4661
|
+
function assertGetMyWalletMetaArgs(args) {
|
|
4662
|
+
assertWalletPasswordArgs(args, "get-my-wallet-meta", [], "--wallet, --password, and --network");
|
|
4663
|
+
}
|
|
4664
|
+
|
|
4665
|
+
function assertGetMyL1AddressArgs(args) {
|
|
4666
|
+
requireArg(args.privateKey, "--private-key");
|
|
4667
|
+
assertAllowedCommandKeys(
|
|
4668
|
+
args,
|
|
4669
|
+
"get-my-l1-address",
|
|
4670
|
+
new Set(["command", "positional", "privateKey"]),
|
|
4671
|
+
"--private-key",
|
|
4672
|
+
);
|
|
4673
|
+
}
|
|
4674
|
+
|
|
4675
|
+
function assertListLocalWalletsArgs(args) {
|
|
4676
|
+
if (args.network !== undefined) {
|
|
4677
|
+
requireNetworkName(args);
|
|
4678
|
+
}
|
|
4679
|
+
if (args.channelName !== undefined) {
|
|
4680
|
+
requireArg(args.channelName, "--channel-name");
|
|
4681
|
+
}
|
|
4682
|
+
assertAllowedCommandKeys(
|
|
4683
|
+
args,
|
|
4684
|
+
"list-local-wallets",
|
|
4685
|
+
new Set(["command", "positional", "network", "channelName"]),
|
|
4686
|
+
"optional --network and --channel-name",
|
|
4687
|
+
);
|
|
4571
4688
|
}
|
|
4572
4689
|
|
|
4573
4690
|
function assertWithdrawBridgeArgs(args) {
|
|
@@ -4629,8 +4746,8 @@ function printHelp() {
|
|
|
4629
4746
|
console.log(`
|
|
4630
4747
|
Commands:
|
|
4631
4748
|
--install [--docker] [--include-local-artifacts]
|
|
4632
|
-
Install the Tokamak zk-EVM CLI runtime
|
|
4633
|
-
Use --docker on Linux to forward
|
|
4749
|
+
Install the Tokamak zk-EVM CLI runtime, Groth16 runtime, and private-state deployment artifacts
|
|
4750
|
+
Use --docker on Linux to forward Docker mode to the Tokamak zk-EVM and Groth16 runtimes
|
|
4634
4751
|
Use --include-local-artifacts to also install local deployment/ artifacts from the current working directory
|
|
4635
4752
|
|
|
4636
4753
|
uninstall-zk-evm
|
|
@@ -4660,9 +4777,15 @@ Commands:
|
|
|
4660
4777
|
join-channel --channel-name <NAME> --password <PASSWORD> --network <NAME> --private-key <HEX> --alchemy-api-key <KEY>
|
|
4661
4778
|
Pay the channel join fee and bind a wallet to a channel-specific L2 identity
|
|
4662
4779
|
|
|
4663
|
-
get-my-
|
|
4780
|
+
get-my-wallet-meta --wallet <NAME> --password <PASSWORD> --network <NAME>
|
|
4664
4781
|
Check whether a wallet matches the on-chain channel registration
|
|
4665
4782
|
|
|
4783
|
+
get-my-l1-address --private-key <HEX>
|
|
4784
|
+
Derive the L1 address for a private key
|
|
4785
|
+
|
|
4786
|
+
list-local-wallets [--network <NAME>] [--channel-name <NAME>]
|
|
4787
|
+
List saved local wallet names that can be reused with --wallet
|
|
4788
|
+
|
|
4666
4789
|
deposit-channel --wallet <NAME> --password <PASSWORD> --network <NAME> --amount <TOKENS>
|
|
4667
4790
|
Move bridged funds into the channel L2 accounting balance
|
|
4668
4791
|
|
|
@@ -4927,6 +5050,7 @@ function writePrivateStateCliInstallManifest({
|
|
|
4927
5050
|
includeLocalArtifacts,
|
|
4928
5051
|
localDeploymentBaseRoot,
|
|
4929
5052
|
deploymentArtifacts,
|
|
5053
|
+
groth16Runtime,
|
|
4930
5054
|
}) {
|
|
4931
5055
|
const manifestPath = privateStateCliInstallManifestPath(deploymentArtifacts.cacheBaseRoot);
|
|
4932
5056
|
const manifest = {
|
|
@@ -4941,6 +5065,7 @@ function writePrivateStateCliInstallManifest({
|
|
|
4941
5065
|
includeLocalArtifacts,
|
|
4942
5066
|
localDeploymentBaseRoot,
|
|
4943
5067
|
artifactCacheRoot: deploymentArtifacts.cacheBaseRoot,
|
|
5068
|
+
groth16Runtime,
|
|
4944
5069
|
installedDeploymentArtifacts: deploymentArtifacts.installed.map((entry) => ({
|
|
4945
5070
|
chainId: entry.chainId,
|
|
4946
5071
|
source: entry.source,
|
|
@@ -4966,6 +5091,8 @@ function buildDoctorReport() {
|
|
|
4966
5091
|
const installManifest = readJsonIfExists(installManifestPath);
|
|
4967
5092
|
const dependencyReports = collectDependencyPackageReports(installManifest);
|
|
4968
5093
|
const tokamakCli = inspectTokamakCliRuntime();
|
|
5094
|
+
const groth16Runtime = inspectGroth16Runtime();
|
|
5095
|
+
const gpuDockerReadiness = inspectGpuDockerReadiness(tokamakCli);
|
|
4969
5096
|
const checks = [
|
|
4970
5097
|
{
|
|
4971
5098
|
name: "dependency package versions",
|
|
@@ -4993,6 +5120,28 @@ function buildDoctorReport() {
|
|
|
4993
5120
|
})),
|
|
4994
5121
|
},
|
|
4995
5122
|
},
|
|
5123
|
+
{
|
|
5124
|
+
name: "tokamak docker gpu readiness",
|
|
5125
|
+
ok: gpuDockerReadiness.ok,
|
|
5126
|
+
details: {
|
|
5127
|
+
expectedUseGpus: gpuDockerReadiness.expectedUseGpus,
|
|
5128
|
+
liveUseGpus: gpuDockerReadiness.liveUseGpus,
|
|
5129
|
+
mismatch: gpuDockerReadiness.mismatch,
|
|
5130
|
+
mismatchError: gpuDockerReadiness.mismatchError,
|
|
5131
|
+
hostNvidiaSmi: summarizeProbeResult(gpuDockerReadiness.hostNvidiaSmi),
|
|
5132
|
+
dockerNvidiaSmi: summarizeProbeResult(gpuDockerReadiness.dockerNvidiaSmi),
|
|
5133
|
+
},
|
|
5134
|
+
},
|
|
5135
|
+
{
|
|
5136
|
+
name: "groth16 runtime",
|
|
5137
|
+
ok: groth16Runtime.installed,
|
|
5138
|
+
details: {
|
|
5139
|
+
packageRoot: groth16Runtime.packageRoot,
|
|
5140
|
+
workspaceRoot: groth16Runtime.workspaceRoot,
|
|
5141
|
+
doctorStatus: groth16Runtime.doctor.status,
|
|
5142
|
+
checks: groth16Runtime.checks,
|
|
5143
|
+
},
|
|
5144
|
+
},
|
|
4996
5145
|
];
|
|
4997
5146
|
|
|
4998
5147
|
return {
|
|
@@ -5012,10 +5161,25 @@ function buildDoctorReport() {
|
|
|
5012
5161
|
},
|
|
5013
5162
|
dependencies: dependencyReports,
|
|
5014
5163
|
tokamakCli,
|
|
5164
|
+
groth16Runtime,
|
|
5165
|
+
gpuDockerReadiness,
|
|
5015
5166
|
checks,
|
|
5016
5167
|
};
|
|
5017
5168
|
}
|
|
5018
5169
|
|
|
5170
|
+
function installGroth16RuntimeForPrivateState({ docker }) {
|
|
5171
|
+
const packageRoot = resolveGroth16PackageRoot();
|
|
5172
|
+
const entryPath = resolveGroth16CliEntryPath(packageRoot);
|
|
5173
|
+
const args = [entryPath, "--install"];
|
|
5174
|
+
if (docker) {
|
|
5175
|
+
args.push("--docker");
|
|
5176
|
+
}
|
|
5177
|
+
run(process.execPath, args, { cwd: packageRoot });
|
|
5178
|
+
const runtime = inspectGroth16Runtime();
|
|
5179
|
+
expect(runtime.installed, "Groth16 runtime install completed, but tokamak-groth16 --doctor still reports an unhealthy runtime.");
|
|
5180
|
+
return runtime;
|
|
5181
|
+
}
|
|
5182
|
+
|
|
5019
5183
|
function collectDependencyPackageReports(installManifest = null) {
|
|
5020
5184
|
const installVersions = new Map(
|
|
5021
5185
|
Array.isArray(installManifest?.dependencies)
|
|
@@ -5087,6 +5251,35 @@ function findPackageJsonForName(startDir, expectedName) {
|
|
|
5087
5251
|
throw new Error(`Cannot locate package.json for ${expectedName} above ${startDir}.`);
|
|
5088
5252
|
}
|
|
5089
5253
|
|
|
5254
|
+
function resolveGroth16PackageRoot() {
|
|
5255
|
+
const publicDriveCrsPath = require.resolve("@tokamak-private-dapps/groth16/public-drive-crs");
|
|
5256
|
+
return path.dirname(findPackageJsonForName(path.dirname(publicDriveCrsPath), "@tokamak-private-dapps/groth16"));
|
|
5257
|
+
}
|
|
5258
|
+
|
|
5259
|
+
function resolveGroth16CliEntryPath(packageRoot = resolveGroth16PackageRoot()) {
|
|
5260
|
+
return path.join(packageRoot, "cli", "tokamak-groth16-cli.mjs");
|
|
5261
|
+
}
|
|
5262
|
+
|
|
5263
|
+
function inspectGroth16Runtime() {
|
|
5264
|
+
const packageRoot = resolveGroth16PackageRoot();
|
|
5265
|
+
const entryPath = resolveGroth16CliEntryPath(packageRoot);
|
|
5266
|
+
const doctor = runCaptured(process.execPath, [entryPath, "--doctor", "--verbose"], { cwd: packageRoot });
|
|
5267
|
+
const stdout = stripAnsi(doctor.stdout).trim();
|
|
5268
|
+
const stderr = stripAnsi(doctor.stderr).trim();
|
|
5269
|
+
const report = parseJsonReport(stdout);
|
|
5270
|
+
return {
|
|
5271
|
+
installed: doctor.status === 0 && report?.ok === true,
|
|
5272
|
+
packageRoot,
|
|
5273
|
+
workspaceRoot: report?.workspaceRoot ?? null,
|
|
5274
|
+
checks: report?.checks ?? [],
|
|
5275
|
+
doctor: {
|
|
5276
|
+
status: doctor.status,
|
|
5277
|
+
stdout,
|
|
5278
|
+
stderr,
|
|
5279
|
+
},
|
|
5280
|
+
};
|
|
5281
|
+
}
|
|
5282
|
+
|
|
5090
5283
|
function inspectTokamakCliRuntime() {
|
|
5091
5284
|
const doctor = runCaptured(tokamakCliCommand, [...tokamakCliBaseArgs, "--doctor"], {
|
|
5092
5285
|
cwd: resolveTokamakCliPackageRoot(),
|
|
@@ -5118,6 +5311,84 @@ function inspectTokamakCliRuntime() {
|
|
|
5118
5311
|
};
|
|
5119
5312
|
}
|
|
5120
5313
|
|
|
5314
|
+
function inspectGpuDockerReadiness(tokamakCli) {
|
|
5315
|
+
const hostNvidiaSmi = runProbe("nvidia-smi", ["--query-gpu=name,driver_version", "--format=csv,noheader"]);
|
|
5316
|
+
const dockerNvidiaSmi = runProbe("docker", [
|
|
5317
|
+
"run",
|
|
5318
|
+
"--rm",
|
|
5319
|
+
"--gpus",
|
|
5320
|
+
"all",
|
|
5321
|
+
DOCKER_CUDA_PROBE_IMAGE,
|
|
5322
|
+
"nvidia-smi",
|
|
5323
|
+
]);
|
|
5324
|
+
const expectedUseGpus = Boolean(tokamakCli.cudaCompatible);
|
|
5325
|
+
const liveUseGpus = hostNvidiaSmi.ok && dockerNvidiaSmi.ok;
|
|
5326
|
+
const mismatch = expectedUseGpus !== liveUseGpus;
|
|
5327
|
+
return {
|
|
5328
|
+
ok: !mismatch,
|
|
5329
|
+
expectedUseGpus,
|
|
5330
|
+
liveUseGpus,
|
|
5331
|
+
mismatch,
|
|
5332
|
+
mismatchError: mismatch
|
|
5333
|
+
? [
|
|
5334
|
+
"Tokamak CLI Docker GPU metadata does not match live NVIDIA/Docker GPU probes.",
|
|
5335
|
+
`metadata useGpus=${expectedUseGpus}; live useGpus=${liveUseGpus}.`,
|
|
5336
|
+
].join(" ")
|
|
5337
|
+
: null,
|
|
5338
|
+
probeImage: DOCKER_CUDA_PROBE_IMAGE,
|
|
5339
|
+
hostNvidiaSmi,
|
|
5340
|
+
dockerNvidiaSmi,
|
|
5341
|
+
};
|
|
5342
|
+
}
|
|
5343
|
+
|
|
5344
|
+
function runProbe(command, args) {
|
|
5345
|
+
const result = spawnSync(command, args, {
|
|
5346
|
+
encoding: "utf8",
|
|
5347
|
+
timeout: DOCTOR_GPU_PROBE_TIMEOUT_MS,
|
|
5348
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5349
|
+
});
|
|
5350
|
+
return {
|
|
5351
|
+
command,
|
|
5352
|
+
args,
|
|
5353
|
+
ok: !result.error && result.status === 0,
|
|
5354
|
+
status: result.status,
|
|
5355
|
+
signal: result.signal,
|
|
5356
|
+
error: result.error ? result.error.message : null,
|
|
5357
|
+
stdout: stripAnsi(result.stdout ?? "").trim(),
|
|
5358
|
+
stderr: stripAnsi(result.stderr ?? "").trim(),
|
|
5359
|
+
timedOut: result.error?.code === "ETIMEDOUT",
|
|
5360
|
+
};
|
|
5361
|
+
}
|
|
5362
|
+
|
|
5363
|
+
function summarizeProbeResult(result) {
|
|
5364
|
+
return {
|
|
5365
|
+
command: [result.command, ...result.args].join(" "),
|
|
5366
|
+
ok: result.ok,
|
|
5367
|
+
status: result.status,
|
|
5368
|
+
signal: result.signal,
|
|
5369
|
+
error: result.error,
|
|
5370
|
+
timedOut: result.timedOut,
|
|
5371
|
+
stdout: truncateText(result.stdout, 2000),
|
|
5372
|
+
stderr: truncateText(result.stderr, 2000),
|
|
5373
|
+
};
|
|
5374
|
+
}
|
|
5375
|
+
|
|
5376
|
+
function truncateText(value, maxLength) {
|
|
5377
|
+
const text = String(value ?? "");
|
|
5378
|
+
if (text.length <= maxLength) {
|
|
5379
|
+
return text;
|
|
5380
|
+
}
|
|
5381
|
+
return `${text.slice(0, maxLength)}...`;
|
|
5382
|
+
}
|
|
5383
|
+
|
|
5384
|
+
function parseJsonReport(value) {
|
|
5385
|
+
try {
|
|
5386
|
+
return JSON.parse(value);
|
|
5387
|
+
} catch {
|
|
5388
|
+
return null;
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5121
5392
|
function resolveTokamakCliCacheRoot() {
|
|
5122
5393
|
return path.resolve(process.env.TOKAMAK_ZKEVM_CLI_CACHE_DIR ?? path.join(os.homedir(), ".tokamak-zk-evm"));
|
|
5123
5394
|
}
|