@tokamak-private-dapps/private-state-cli 1.1.1 → 1.2.0
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 +36 -0
- package/README.md +23 -12
- package/lib/private-state-cli-command-registry.mjs +80 -18
- package/package.json +1 -1
- package/private-state-bridge-cli.mjs +1982 -156
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0 - 2026-05-08
|
|
4
|
+
|
|
5
|
+
- Added optional channel workspace mirror recovery. `channel recover-workspace` now accepts
|
|
6
|
+
`--source rpc|mirror`, with `rpc` remaining the default when `--source` is omitted.
|
|
7
|
+
- Added `channel set-workspace-mirror` so a channel leader can register the official workspace
|
|
8
|
+
mirror base URL stored in `BridgeCore`.
|
|
9
|
+
- Added mirror checkpoint validation that checks signed checkpoint metadata before downloading
|
|
10
|
+
bundles, then validates downloaded checkpoint or delta bundle contents against on-chain channel
|
|
11
|
+
metadata before replaying the remaining RPC log delta to the latest block.
|
|
12
|
+
- Documented the static server protocol for channel workspace mirrors.
|
|
13
|
+
- Removed `--source auto` from `channel recover-workspace`; recovery source is now either
|
|
14
|
+
`rpc` or `mirror`.
|
|
15
|
+
- Required `channel recover-workspace --from-genesis` to be paired with explicit `--source rpc`
|
|
16
|
+
so genesis replay cannot be requested accidentally through an omitted source.
|
|
17
|
+
- Restored pre-command workspace refresh for commands that require current local state, but limited
|
|
18
|
+
automatic refresh to saved recovery indexes. Automatic command preflight never replays from
|
|
19
|
+
genesis and points users to explicit `channel recover-workspace` or `wallet recover-workspace`
|
|
20
|
+
when a genesis rebuild is required.
|
|
21
|
+
- Restored received-note event-log refresh for `wallet get-notes`, `wallet transfer-notes`, and
|
|
22
|
+
`wallet redeem-notes`, limited to the saved wallet note recovery index.
|
|
23
|
+
- Limited pre-command automatic recovery to a 10 second RPC log scan budget based on the CLI's
|
|
24
|
+
paced log query rate.
|
|
25
|
+
- Reworked workspace mirror recovery around leader-signed checkpoint manifests and
|
|
26
|
+
delta bundles. When a local recovery index exists, the CLI prechecks the mirror checkpoint and
|
|
27
|
+
downloads only the matching delta bundle instead of a full workspace bundle.
|
|
28
|
+
- Removed the version segment from workspace mirror URLs and kept the protocol version only in
|
|
29
|
+
manifest and bundle metadata.
|
|
30
|
+
- Added `channel publish-workspace-mirror` to build static mirror files when the local workspace is
|
|
31
|
+
current and ahead of the registered mirror checkpoint.
|
|
32
|
+
- Added `channel publish-workspace-mirror --force` so a channel leader can repair an unreadable or
|
|
33
|
+
invalid remote mirror manifest by publishing a full checkpoint without using that manifest as a
|
|
34
|
+
delta base.
|
|
35
|
+
- Required mirror bundle `sizeBytes` and enforce it as the download limit before verifying bundle
|
|
36
|
+
contents.
|
|
37
|
+
- Kept streaming checkpoint or delta bundle download progress with an estimated remaining time.
|
|
38
|
+
|
|
3
39
|
## 1.1.1 - 2026-05-08
|
|
4
40
|
|
|
5
41
|
- Added bridge deployment verification support for Etherscan-compatible explorers, including
|
package/README.md
CHANGED
|
@@ -99,26 +99,37 @@ continues to print the same command list for shell compatibility.
|
|
|
99
99
|
|
|
100
100
|
Workspace recovery commands use the saved recovery index by default. If the local workspace is missing, corrupted, or
|
|
101
101
|
does not contain a usable index, `channel recover-workspace` and `wallet recover-workspace` stop with an explicit error instead of
|
|
102
|
-
silently replaying logs from channel genesis. Use `--from-genesis` only when you intentionally want to
|
|
103
|
-
channel creation block:
|
|
102
|
+
silently replaying logs from channel genesis. Use `--source rpc --from-genesis` only when you intentionally want to
|
|
103
|
+
rebuild channel workspace state from the channel creation block:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
|
-
private-state-cli channel recover-workspace --channel-name <CHANNEL> --network mainnet --from-genesis
|
|
106
|
+
private-state-cli channel recover-workspace --channel-name <CHANNEL> --network mainnet --source rpc --from-genesis
|
|
107
107
|
private-state-cli wallet recover-workspace --channel-name <CHANNEL> --network mainnet --account <ACCOUNT> --from-genesis
|
|
108
108
|
```
|
|
109
109
|
|
|
110
110
|
`channel create` is the exception: after the channel is created on-chain, the CLI initializes that new local workspace
|
|
111
111
|
by replaying from the channel's genesis block because no prior recovery index can exist for a new channel.
|
|
112
112
|
|
|
113
|
-
`channel join`
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
index instead of silently replaying from genesis.
|
|
113
|
+
`channel join` refreshes stale channel workspace state through the saved recovery index before submitting the
|
|
114
|
+
registration transaction. For a channel that was created elsewhere, run `channel recover-workspace --source rpc --from-genesis`
|
|
115
|
+
once before joining, or recover from a registered workspace mirror; later joins and wallet commands resume from the
|
|
116
|
+
saved index instead of silently replaying from genesis.
|
|
117
117
|
|
|
118
118
|
Wallet getter commands that need channel state, including `wallet get-meta`, `wallet get-channel-fund`, and
|
|
119
|
-
`wallet get-notes`,
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
`wallet get-notes`, refresh stale local workspaces through saved recovery indexes before reading state. `wallet get-notes`
|
|
120
|
+
also refreshes received-note logs through the saved wallet note recovery index. Automatic refresh never replays from
|
|
121
|
+
channel genesis and only runs when the estimated RPC log scan fits within the 10 second pre-command budget. If a saved
|
|
122
|
+
index is missing, unusable, or too far behind, the command stops and asks the user to run the appropriate recovery
|
|
123
|
+
command with `--from-genesis` explicitly when needed.
|
|
124
|
+
|
|
125
|
+
Channel leaders can optionally register a workspace mirror server so users can bootstrap recovery
|
|
126
|
+
from a signed checkpoint and download only the local-to-checkpoint delta when a local recovery index
|
|
127
|
+
already exists. The channel leader can build the static mirror files with
|
|
128
|
+
`channel publish-workspace-mirror` and then deploy the output directory to the registered mirror
|
|
129
|
+
host. If the existing mirror manifest is unreadable or invalid, the leader can use
|
|
130
|
+
`channel publish-workspace-mirror --force` to write a full checkpoint without trusting that remote
|
|
131
|
+
manifest as a delta base. The CLI protocol is documented at
|
|
132
|
+
https://github.com/tokamak-network/Tokamak-zk-EVM-contracts/blob/main/packages/apps/private-state/docs/channel-workspace-mirror-protocol.md.
|
|
122
133
|
|
|
123
134
|
Back up a local wallet with:
|
|
124
135
|
|
|
@@ -134,7 +145,7 @@ run `channel recover-workspace` before using wallet commands that need channel s
|
|
|
134
145
|
|
|
135
146
|
```bash
|
|
136
147
|
private-state-cli wallet import --input ./wallet-backup.zip
|
|
137
|
-
private-state-cli channel recover-workspace --channel-name <CHANNEL> --network mainnet --from-genesis
|
|
148
|
+
private-state-cli channel recover-workspace --channel-name <CHANNEL> --network mainnet --source rpc --from-genesis
|
|
138
149
|
```
|
|
139
150
|
|
|
140
151
|
For a wider backup that can run wallet commands immediately when the imported channel workspace cache is still
|
|
@@ -330,7 +341,7 @@ Suggested interaction flow:
|
|
|
330
341
|
`wallet mint-notes`.
|
|
331
342
|
7. For a private transfer, select available note IDs from `wallet get-notes`, find the recipient L2 address from
|
|
332
343
|
`wallet get-meta`, then build `wallet transfer-notes`.
|
|
333
|
-
8. After transfer, guide the recipient to run `wallet get-notes
|
|
344
|
+
8. After transfer, guide the recipient to run `wallet get-notes`; it refreshes received notes from the saved recovery index when the delta fits the 10 second pre-command budget. If the index is missing or too far behind, explain `wallet recover-workspace --from-genesis`.
|
|
334
345
|
|
|
335
346
|
Example onboarding explanation for `channel join`:
|
|
336
347
|
|
|
@@ -69,10 +69,10 @@ export const PRIVATE_STATE_CLI_FIELD_CATALOG = Object.freeze({
|
|
|
69
69
|
option: "--wallet",
|
|
70
70
|
},
|
|
71
71
|
output: {
|
|
72
|
-
label: "Output
|
|
72
|
+
label: "Output Path",
|
|
73
73
|
type: "text",
|
|
74
|
-
placeholder: "/path/to/
|
|
75
|
-
valueLabel: "<
|
|
74
|
+
placeholder: "/path/to/output",
|
|
75
|
+
valueLabel: "<PATH>",
|
|
76
76
|
option: "--output",
|
|
77
77
|
},
|
|
78
78
|
input: {
|
|
@@ -157,10 +157,34 @@ export const PRIVATE_STATE_CLI_FIELD_CATALOG = Object.freeze({
|
|
|
157
157
|
fromGenesis: {
|
|
158
158
|
label: "Scan From Genesis",
|
|
159
159
|
type: "checkbox",
|
|
160
|
-
hint: "Ignore the local recovery index and replay channel logs from genesis.",
|
|
160
|
+
hint: "Requires --source rpc. Ignore the local recovery index and replay channel logs from genesis.",
|
|
161
161
|
option: "--from-genesis",
|
|
162
162
|
optional: true,
|
|
163
163
|
},
|
|
164
|
+
source: {
|
|
165
|
+
label: "Recovery Source",
|
|
166
|
+
type: "select",
|
|
167
|
+
options: ["rpc", "mirror"],
|
|
168
|
+
valueLabel: "<rpc|mirror>",
|
|
169
|
+
hint: "Optional. Defaults to rpc. mirror validates the channel leader's checkpoint manifest and downloads only the needed checkpoint or delta bundle before RPC delta replay.",
|
|
170
|
+
option: "--source",
|
|
171
|
+
optional: true,
|
|
172
|
+
},
|
|
173
|
+
url: {
|
|
174
|
+
label: "Workspace Mirror URL",
|
|
175
|
+
type: "text",
|
|
176
|
+
placeholder: "https://mirror.example",
|
|
177
|
+
valueLabel: "<URL>",
|
|
178
|
+
hint: "Base URL for the channel workspace mirror protocol.",
|
|
179
|
+
option: "--url",
|
|
180
|
+
},
|
|
181
|
+
force: {
|
|
182
|
+
label: "Force",
|
|
183
|
+
type: "checkbox",
|
|
184
|
+
hint: "Ignore an unreadable or invalid existing mirror manifest and publish a full checkpoint instead of a delta.",
|
|
185
|
+
option: "--force",
|
|
186
|
+
optional: true,
|
|
187
|
+
},
|
|
164
188
|
json: {
|
|
165
189
|
label: "JSON Output",
|
|
166
190
|
type: "checkbox",
|
|
@@ -280,15 +304,40 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
280
304
|
id: "channel-recover-workspace",
|
|
281
305
|
display: "channel recover-workspace",
|
|
282
306
|
description: "Rebuild the local channel workspace from bridge state.",
|
|
283
|
-
fields: ["channelName", "network", "fromGenesis", "rpcUrl"],
|
|
284
|
-
usage: "--channel-name, --network, optional --from-genesis, and optional --rpc-url",
|
|
307
|
+
fields: ["channelName", "network", "source", "fromGenesis", "rpcUrl"],
|
|
308
|
+
usage: "--channel-name, --network, optional --source, optional --from-genesis, and optional --rpc-url",
|
|
285
309
|
help: [
|
|
286
|
-
"By default, resumes RPC log scanning from the workspace recovery index when available",
|
|
310
|
+
"By default, --source rpc resumes RPC log scanning from the workspace recovery index when available",
|
|
311
|
+
"--source mirror validates the channel leader's registered checkpoint manifest, downloads only the needed checkpoint or delta bundle, and then replays RPC logs to latest",
|
|
287
312
|
"Fails instead of falling back to genesis when no usable recovery index exists",
|
|
288
|
-
"Use --from-genesis to ignore the recovery index and replay logs from channel genesis",
|
|
313
|
+
"Use --source rpc --from-genesis to ignore the recovery index and replay logs from channel genesis",
|
|
289
314
|
"Prints RPC log scan progress while rebuilding the workspace",
|
|
290
315
|
],
|
|
291
316
|
},
|
|
317
|
+
{
|
|
318
|
+
id: "channel-set-workspace-mirror",
|
|
319
|
+
display: "channel set-workspace-mirror",
|
|
320
|
+
description: "Register or update the channel leader's workspace mirror base URL.",
|
|
321
|
+
fields: ["channelName", "network", "account", "url", "rpcUrl"],
|
|
322
|
+
usage: "--channel-name, --network, --account, --url, and optional --rpc-url",
|
|
323
|
+
help: [
|
|
324
|
+
"Only the on-chain channel leader can update the registered mirror URL",
|
|
325
|
+
"The URL points to a server implementing the private-state channel workspace mirror protocol",
|
|
326
|
+
],
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
id: "channel-publish-workspace-mirror",
|
|
330
|
+
display: "channel publish-workspace-mirror",
|
|
331
|
+
description: "Build static workspace mirror files for the registered mirror URL.",
|
|
332
|
+
fields: ["channelName", "network", "account", "output", "force", "rpcUrl"],
|
|
333
|
+
usage: "--channel-name, --network, --account, --output, optional --force, and optional --rpc-url",
|
|
334
|
+
help: [
|
|
335
|
+
"Requires the local channel workspace to be current and ahead of the registered mirror checkpoint",
|
|
336
|
+
"--force ignores an unreadable or invalid existing mirror manifest and publishes a full checkpoint without a delta",
|
|
337
|
+
"Writes manifest.json, checkpoint.zip, and any needed delta bundle under the workspace mirror static path",
|
|
338
|
+
"Does not upload files to a remote server; deploy the output directory to the registered HTTPS mirror host",
|
|
339
|
+
],
|
|
340
|
+
},
|
|
292
341
|
{
|
|
293
342
|
id: "channel-get-meta",
|
|
294
343
|
display: "channel get-meta",
|
|
@@ -332,8 +381,8 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
332
381
|
fields: ["channelName", "network", "account", "walletSecretPath", "rpcUrl"],
|
|
333
382
|
usage: "--channel-name, --network, --account, --wallet-secret-path, and optional --rpc-url",
|
|
334
383
|
help: [
|
|
335
|
-
"
|
|
336
|
-
"
|
|
384
|
+
"Refreshes the local channel workspace through the saved recovery index before joining when the scan fits the 10 second pre-command budget",
|
|
385
|
+
"Fails instead of replaying from genesis; run channel recover-workspace --source rpc --from-genesis when a genesis rebuild is required",
|
|
337
386
|
"--wallet-secret-path imports an existing source secret file into the protected wallet-local secret file",
|
|
338
387
|
"Prints the immutable policy snapshot before first registration",
|
|
339
388
|
],
|
|
@@ -344,7 +393,7 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
344
393
|
description: "Check whether a wallet matches the on-chain channel registration.",
|
|
345
394
|
fields: ["wallet", "network"],
|
|
346
395
|
usage: "--wallet and --network",
|
|
347
|
-
help: ["Refreshes channel
|
|
396
|
+
help: ["Refreshes the local channel workspace through the saved recovery index before reading registration metadata when the scan fits the 10 second pre-command budget"],
|
|
348
397
|
},
|
|
349
398
|
{
|
|
350
399
|
id: "wallet-list",
|
|
@@ -384,6 +433,7 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
384
433
|
description: "Move bridged funds into the channel L2 accounting balance.",
|
|
385
434
|
fields: ["wallet", "network", "amount"],
|
|
386
435
|
usage: "--wallet, --network, and --amount",
|
|
436
|
+
help: ["Refreshes the local channel workspace through the saved recovery index before proving the deposit when the scan fits the 10 second pre-command budget"],
|
|
387
437
|
},
|
|
388
438
|
{
|
|
389
439
|
id: "wallet-withdraw-channel",
|
|
@@ -391,6 +441,7 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
391
441
|
description: "Move channel L2 balance back into the shared bridge vault.",
|
|
392
442
|
fields: ["wallet", "network", "amount"],
|
|
393
443
|
usage: "--wallet, --network, and --amount",
|
|
444
|
+
help: ["Refreshes the local channel workspace through the saved recovery index before proving the withdrawal when the scan fits the 10 second pre-command budget"],
|
|
394
445
|
},
|
|
395
446
|
{
|
|
396
447
|
id: "wallet-get-channel-fund",
|
|
@@ -398,7 +449,7 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
398
449
|
description: "Read the current channel L2 accounting balance.",
|
|
399
450
|
fields: ["wallet", "network"],
|
|
400
451
|
usage: "--wallet and --network",
|
|
401
|
-
help: ["Refreshes channel
|
|
452
|
+
help: ["Refreshes the local channel workspace through the saved recovery index before reading the L2 accounting balance when the scan fits the 10 second pre-command budget"],
|
|
402
453
|
},
|
|
403
454
|
{
|
|
404
455
|
id: "channel-exit",
|
|
@@ -406,6 +457,7 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
406
457
|
description: "Exit a channel. Both the CLI and bridge contract require a zero channel balance.",
|
|
407
458
|
fields: ["wallet", "network"],
|
|
408
459
|
usage: "--wallet and --network",
|
|
460
|
+
help: ["Refreshes the local channel workspace through the saved recovery index before checking the channel balance when the scan fits the 10 second pre-command budget"],
|
|
409
461
|
},
|
|
410
462
|
{
|
|
411
463
|
id: "wallet-mint-notes",
|
|
@@ -413,7 +465,10 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
413
465
|
description: "Mint one or two private-state notes from the wallet's channel balance.",
|
|
414
466
|
fields: ["wallet", "network", "amounts", "txSubmitter"],
|
|
415
467
|
usage: "--wallet, --network, --amounts, and optional --tx-submitter",
|
|
416
|
-
help: [
|
|
468
|
+
help: [
|
|
469
|
+
"Refreshes the local channel workspace through the saved recovery index before proving the mint when the scan fits the 10 second pre-command budget",
|
|
470
|
+
"Use --tx-submitter <ACCOUNT> to let a separate local L1 account pay gas for stronger transaction privacy",
|
|
471
|
+
],
|
|
417
472
|
},
|
|
418
473
|
{
|
|
419
474
|
id: "wallet-transfer-notes",
|
|
@@ -421,7 +476,10 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
421
476
|
description: "Spend input notes into the registered 1->1, 1->2, or 2->1 private transfer shapes.",
|
|
422
477
|
fields: ["wallet", "network", "noteIds", "recipients", "amounts", "txSubmitter"],
|
|
423
478
|
usage: "--wallet, --network, --note-ids, --recipients, --amounts, and optional --tx-submitter",
|
|
424
|
-
help: [
|
|
479
|
+
help: [
|
|
480
|
+
"Refreshes the local channel workspace and received-note logs through saved recovery indexes before proving the transfer when scans fit the 10 second pre-command budget",
|
|
481
|
+
"Use --tx-submitter <ACCOUNT> to let a separate local L1 account pay gas for stronger transaction privacy",
|
|
482
|
+
],
|
|
425
483
|
},
|
|
426
484
|
{
|
|
427
485
|
id: "wallet-redeem-notes",
|
|
@@ -429,17 +487,21 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
429
487
|
description: "Redeem one tracked note back into the wallet's channel balance.",
|
|
430
488
|
fields: ["wallet", "network", "noteIds", "txSubmitter"],
|
|
431
489
|
usage: "--wallet, --network, --note-ids, and optional --tx-submitter",
|
|
432
|
-
help: [
|
|
490
|
+
help: [
|
|
491
|
+
"Refreshes the local channel workspace and received-note logs through saved recovery indexes before proving the redeem when scans fit the 10 second pre-command budget",
|
|
492
|
+
"Use --tx-submitter <ACCOUNT> to let a separate local L1 account pay gas for stronger transaction privacy",
|
|
493
|
+
],
|
|
433
494
|
},
|
|
434
495
|
{
|
|
435
496
|
id: "wallet-get-notes",
|
|
436
497
|
display: "wallet get-notes",
|
|
437
|
-
description: "
|
|
498
|
+
description: "Refresh received notes when the saved recovery index is recent, then show tracked note state.",
|
|
438
499
|
fields: ["wallet", "network"],
|
|
439
500
|
usage: "--wallet and --network",
|
|
440
501
|
help: [
|
|
441
|
-
"Refreshes channel
|
|
442
|
-
"Refreshes received-note logs through the wallet note recovery index",
|
|
502
|
+
"Refreshes the local channel workspace through the saved recovery index before reading notes when the scan fits the 10 second pre-command budget",
|
|
503
|
+
"Refreshes received-note logs through the saved wallet note recovery index when the scan fits the 10 second pre-command budget",
|
|
504
|
+
"Fails instead of replaying from genesis; run wallet recover-workspace --from-genesis when a genesis rebuild is required",
|
|
443
505
|
],
|
|
444
506
|
},
|
|
445
507
|
]);
|
package/package.json
CHANGED