@tokamak-private-dapps/private-state-cli 1.1.0 → 1.1.1
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 +18 -0
- package/README.md +5 -0
- package/lib/private-state-cli-command-registry.mjs +2 -0
- package/package.json +1 -1
- package/private-state-bridge-cli.mjs +31 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.1 - 2026-05-08
|
|
4
|
+
|
|
5
|
+
- Added bridge deployment verification support for Etherscan-compatible explorers, including
|
|
6
|
+
proxy and implementation verification for the main bridge contracts after deploy or upgrade
|
|
7
|
+
flows.
|
|
8
|
+
- Added an incremental ChannelManager verification script that scans channel creation events from
|
|
9
|
+
the last indexed block, skips already verified channel contracts, and persists scan progress for
|
|
10
|
+
later runs.
|
|
11
|
+
- Required `channel join` to refresh through the recovery index before joining an existing channel,
|
|
12
|
+
while preserving the explicit `--from-genesis` path for recovery commands that intentionally
|
|
13
|
+
rebuild workspace state from channel genesis.
|
|
14
|
+
- Verified the private-state CLI end-to-end flow with isolated local workspace state after the
|
|
15
|
+
indexed join recovery change.
|
|
16
|
+
|
|
3
17
|
## 1.1.0 - 2026-05-06
|
|
4
18
|
|
|
19
|
+
- Required `channel join` to use an existing recovered channel workspace and refresh through the
|
|
20
|
+
recovery index before submitting the join transaction, so old channels are not silently replayed
|
|
21
|
+
from genesis during join. `wallet recover-workspace --from-genesis` now also replays encrypted
|
|
22
|
+
note delivery logs from channel genesis for existing wallets.
|
|
5
23
|
- Refreshed channel workspaces through the existing recovery-indexed replay path after successful
|
|
6
24
|
wallet transactions instead of manually patching local snapshots, and bounded post-transaction
|
|
7
25
|
replay by the transaction receipt block so provider latest-block lag cannot skip the confirmed
|
package/README.md
CHANGED
|
@@ -110,6 +110,11 @@ private-state-cli wallet recover-workspace --channel-name <CHANNEL> --network ma
|
|
|
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` requires the channel workspace to have a usable recovery index and refreshes that workspace through the
|
|
114
|
+
indexed path before submitting the registration transaction. For a channel that was created elsewhere, run
|
|
115
|
+
`channel recover-workspace --from-genesis` once before joining; later joins and wallet commands resume from the saved
|
|
116
|
+
index instead of silently replaying from genesis.
|
|
117
|
+
|
|
113
118
|
Wallet getter commands that need channel state, including `wallet get-meta`, `wallet get-channel-fund`, and
|
|
114
119
|
`wallet get-notes`, follow the same indexed recovery rule before reading local or on-chain state. `wallet get-notes` also uses
|
|
115
120
|
the wallet's saved note-receive scan index for encrypted note delivery logs. If either index is unusable, the command
|
|
@@ -332,6 +332,8 @@ export const PRIVATE_STATE_CLI_COMMANDS = Object.freeze([
|
|
|
332
332
|
fields: ["channelName", "network", "account", "walletSecretPath", "rpcUrl"],
|
|
333
333
|
usage: "--channel-name, --network, --account, --wallet-secret-path, and optional --rpc-url",
|
|
334
334
|
help: [
|
|
335
|
+
"Requires a recovered channel workspace and refreshes it through the workspace recovery index before joining",
|
|
336
|
+
"Run channel recover-workspace --from-genesis once if no usable local recovery index exists",
|
|
335
337
|
"--wallet-secret-path imports an existing source secret file into the protected wallet-local secret file",
|
|
336
338
|
"Prints the immutable policy snapshot before first registration",
|
|
337
339
|
],
|
package/package.json
CHANGED
|
@@ -846,11 +846,6 @@ async function syncChannelWorkspace({
|
|
|
846
846
|
ethers.toBigInt(derivedAPubBlockHash) === ethers.toBigInt(normalizeBytes32Hex(channelInfo.aPubBlockHash)),
|
|
847
847
|
`Derived channel block-info hash ${derivedAPubBlockHash} does not match onchain ${channelInfo.aPubBlockHash}.`,
|
|
848
848
|
);
|
|
849
|
-
const localSnapshotReusable = !fromGenesis && canReuseLocalWorkspaceSnapshot({
|
|
850
|
-
existingArtifacts,
|
|
851
|
-
currentRootVectorHash,
|
|
852
|
-
managedStorageAddresses,
|
|
853
|
-
});
|
|
854
849
|
const recoveryIndex = useWorkspaceRecoveryIndex && !fromGenesis
|
|
855
850
|
? getUsableWorkspaceRecoveryIndex({
|
|
856
851
|
existingArtifacts,
|
|
@@ -859,6 +854,12 @@ async function syncChannelWorkspace({
|
|
|
859
854
|
managedStorageAddresses,
|
|
860
855
|
})
|
|
861
856
|
: null;
|
|
857
|
+
const localSnapshotReusable = !fromGenesis && (!useWorkspaceRecoveryIndex || recoveryIndex)
|
|
858
|
+
&& canReuseLocalWorkspaceSnapshot({
|
|
859
|
+
existingArtifacts,
|
|
860
|
+
currentRootVectorHash,
|
|
861
|
+
managedStorageAddresses,
|
|
862
|
+
});
|
|
862
863
|
if (useWorkspaceRecoveryIndex && !fromGenesis && !localSnapshotReusable && !recoveryIndex) {
|
|
863
864
|
throw new Error([
|
|
864
865
|
`Workspace recovery index is missing or unusable for channel ${channelName} on ${networkNameFromChainId(network.chainId)}.`,
|
|
@@ -1155,6 +1156,7 @@ async function handleRecoverWallet({ args, network, provider, rpcUrl }) {
|
|
|
1155
1156
|
signer,
|
|
1156
1157
|
noteReceiveKeyMaterial,
|
|
1157
1158
|
progressAction: "wallet recover-workspace",
|
|
1159
|
+
fromGenesis: args.fromGenesis === true,
|
|
1158
1160
|
});
|
|
1159
1161
|
printJson({
|
|
1160
1162
|
action: "wallet recover-workspace",
|
|
@@ -1202,6 +1204,7 @@ async function handleRecoverWallet({ args, network, provider, rpcUrl }) {
|
|
|
1202
1204
|
signer,
|
|
1203
1205
|
noteReceiveKeyMaterial,
|
|
1204
1206
|
progressAction: "wallet recover-workspace",
|
|
1207
|
+
fromGenesis: args.fromGenesis === true,
|
|
1205
1208
|
});
|
|
1206
1209
|
|
|
1207
1210
|
printJson({
|
|
@@ -2861,6 +2864,13 @@ async function handleJoinChannel({ args, network, provider, rpcUrl }) {
|
|
|
2861
2864
|
);
|
|
2862
2865
|
status = "joined";
|
|
2863
2866
|
|
|
2867
|
+
await refreshPersistedWorkspaceAfterLocalTransaction({
|
|
2868
|
+
context,
|
|
2869
|
+
provider,
|
|
2870
|
+
receipt,
|
|
2871
|
+
progressAction: "channel join",
|
|
2872
|
+
});
|
|
2873
|
+
|
|
2864
2874
|
const walletContext = ensureWallet({
|
|
2865
2875
|
channelContext: context,
|
|
2866
2876
|
signerAddress: signer.address,
|
|
@@ -3718,6 +3728,7 @@ async function recoverWalletReceivedNotes({
|
|
|
3718
3728
|
signer,
|
|
3719
3729
|
noteReceiveKeyMaterial = null,
|
|
3720
3730
|
progressAction = null,
|
|
3731
|
+
fromGenesis = false,
|
|
3721
3732
|
}) {
|
|
3722
3733
|
const resolvedNoteReceiveKeyMaterial = noteReceiveKeyMaterial ?? await deriveNoteReceiveKeyMaterial({
|
|
3723
3734
|
signer,
|
|
@@ -3732,6 +3743,7 @@ async function recoverWalletReceivedNotes({
|
|
|
3732
3743
|
provider,
|
|
3733
3744
|
noteReceivePrivateKey: resolvedNoteReceiveKeyMaterial.privateKey,
|
|
3734
3745
|
progressAction,
|
|
3746
|
+
fromGenesis,
|
|
3735
3747
|
});
|
|
3736
3748
|
return {
|
|
3737
3749
|
noteReceiveKeyMaterial: resolvedNoteReceiveKeyMaterial,
|
|
@@ -3745,13 +3757,16 @@ async function recoverDeliveredNotesFromEventLogs({
|
|
|
3745
3757
|
provider,
|
|
3746
3758
|
noteReceivePrivateKey,
|
|
3747
3759
|
progressAction = null,
|
|
3760
|
+
fromGenesis = false,
|
|
3748
3761
|
}) {
|
|
3749
3762
|
const latestBlock = await provider.getBlockNumber();
|
|
3750
|
-
const scanStartBlock =
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3763
|
+
const scanStartBlock = fromGenesis
|
|
3764
|
+
? Number(context.workspace.genesisBlockNumber)
|
|
3765
|
+
: requireUsableWalletNoteReceiveRecoveryIndex({
|
|
3766
|
+
walletContext,
|
|
3767
|
+
context,
|
|
3768
|
+
latestBlock,
|
|
3769
|
+
});
|
|
3755
3770
|
const scanRange = {
|
|
3756
3771
|
fromBlock: scanStartBlock,
|
|
3757
3772
|
toBlock: latestBlock,
|
|
@@ -4695,13 +4710,16 @@ async function loadJoinChannelContext({ args, network, provider }) {
|
|
|
4695
4710
|
network: { chainId, name: resolvedNetworkName },
|
|
4696
4711
|
provider,
|
|
4697
4712
|
bridgeResources,
|
|
4698
|
-
persist:
|
|
4713
|
+
persist: true,
|
|
4714
|
+
allowExistingWorkspaceSync: true,
|
|
4715
|
+
useWorkspaceRecoveryIndex: true,
|
|
4716
|
+
progressAction: "channel join",
|
|
4699
4717
|
});
|
|
4700
4718
|
|
|
4701
4719
|
return {
|
|
4702
4720
|
workspaceName: channelName,
|
|
4703
|
-
workspaceDir:
|
|
4704
|
-
persistChannelWorkspace:
|
|
4721
|
+
workspaceDir: initialized.workspaceDir,
|
|
4722
|
+
persistChannelWorkspace: true,
|
|
4705
4723
|
workspace: initialized.workspace,
|
|
4706
4724
|
bridgeAbiManifest: bridgeResources.bridgeAbiManifest,
|
|
4707
4725
|
currentSnapshot: initialized.currentSnapshot,
|