@cogcoin/client 1.1.5 → 1.1.7
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/README.md +2 -2
- package/dist/bitcoind/indexer-daemon.d.ts +3 -7
- package/dist/bitcoind/indexer-daemon.js +39 -204
- package/dist/bitcoind/managed-runtime/bitcoind-policy.d.ts +16 -0
- package/dist/bitcoind/managed-runtime/bitcoind-policy.js +177 -0
- package/dist/bitcoind/managed-runtime/bitcoind-runtime.d.ts +20 -0
- package/dist/bitcoind/managed-runtime/bitcoind-runtime.js +74 -0
- package/dist/bitcoind/managed-runtime/bitcoind-status.d.ts +11 -0
- package/dist/bitcoind/managed-runtime/bitcoind-status.js +44 -0
- package/dist/bitcoind/managed-runtime/indexer-policy.d.ts +34 -0
- package/dist/bitcoind/managed-runtime/indexer-policy.js +200 -0
- package/dist/bitcoind/managed-runtime/indexer-runtime.d.ts +15 -0
- package/dist/bitcoind/managed-runtime/indexer-runtime.js +82 -0
- package/dist/bitcoind/managed-runtime/status.d.ts +11 -0
- package/dist/bitcoind/managed-runtime/status.js +59 -0
- package/dist/bitcoind/managed-runtime/types.d.ts +77 -0
- package/dist/bitcoind/node.d.ts +2 -2
- package/dist/bitcoind/node.js +2 -2
- package/dist/bitcoind/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +53 -3
- package/dist/bitcoind/service.d.ts +2 -7
- package/dist/bitcoind/service.js +79 -207
- package/dist/cli/command-registry.d.ts +1 -1
- package/dist/cli/command-registry.js +2 -64
- package/dist/cli/commands/client-admin.js +3 -18
- package/dist/cli/commands/mining-runtime.js +4 -60
- package/dist/cli/commands/wallet-admin.js +6 -6
- package/dist/cli/context.js +1 -3
- package/dist/cli/mining-json.d.ts +1 -22
- package/dist/cli/mining-json.js +0 -23
- package/dist/cli/output.js +16 -2
- package/dist/cli/parse.js +0 -2
- package/dist/cli/preview-json.d.ts +1 -22
- package/dist/cli/preview-json.js +0 -19
- package/dist/cli/types.d.ts +1 -3
- package/dist/cli/wallet-format.js +1 -1
- package/dist/cli/workflow-hints.d.ts +1 -2
- package/dist/cli/workflow-hints.js +5 -8
- package/dist/wallet/lifecycle/access.d.ts +5 -0
- package/dist/wallet/lifecycle/access.js +79 -0
- package/dist/wallet/lifecycle/context.d.ts +26 -0
- package/dist/wallet/lifecycle/context.js +57 -0
- package/dist/wallet/lifecycle/managed-core.d.ts +1 -9
- package/dist/wallet/lifecycle/managed-core.js +3 -63
- package/dist/wallet/lifecycle/repair-bitcoind.d.ts +10 -0
- package/dist/wallet/lifecycle/repair-bitcoind.js +142 -0
- package/dist/wallet/lifecycle/repair-indexer.d.ts +8 -0
- package/dist/wallet/lifecycle/repair-indexer.js +117 -0
- package/dist/wallet/lifecycle/repair-mining.d.ts +1 -5
- package/dist/wallet/lifecycle/repair-mining.js +5 -39
- package/dist/wallet/lifecycle/repair.d.ts +2 -4
- package/dist/wallet/lifecycle/repair.js +74 -318
- package/dist/wallet/lifecycle/setup-prompts.d.ts +7 -0
- package/dist/wallet/lifecycle/setup-prompts.js +88 -0
- package/dist/wallet/lifecycle/setup-state.d.ts +26 -0
- package/dist/wallet/lifecycle/setup-state.js +159 -0
- package/dist/wallet/lifecycle/setup.d.ts +3 -4
- package/dist/wallet/lifecycle/setup.js +47 -351
- package/dist/wallet/lifecycle/types.d.ts +33 -5
- package/dist/wallet/managed-core-wallet.d.ts +2 -0
- package/dist/wallet/managed-core-wallet.js +27 -1
- package/dist/wallet/mining/candidate.d.ts +1 -0
- package/dist/wallet/mining/candidate.js +38 -6
- package/dist/wallet/mining/competitiveness.d.ts +1 -0
- package/dist/wallet/mining/competitiveness.js +6 -0
- package/dist/wallet/mining/cycle.d.ts +2 -0
- package/dist/wallet/mining/cycle.js +14 -4
- package/dist/wallet/mining/engine-types.d.ts +1 -0
- package/dist/wallet/mining/index.d.ts +1 -1
- package/dist/wallet/mining/index.js +1 -1
- package/dist/wallet/mining/publish.d.ts +3 -0
- package/dist/wallet/mining/publish.js +78 -6
- package/dist/wallet/mining/runner.d.ts +0 -32
- package/dist/wallet/mining/runner.js +59 -104
- package/dist/wallet/mining/stop.d.ts +7 -0
- package/dist/wallet/mining/stop.js +23 -0
- package/dist/wallet/mining/supervisor.d.ts +2 -36
- package/dist/wallet/mining/supervisor.js +139 -246
- package/dist/wallet/read/context.d.ts +1 -5
- package/dist/wallet/read/context.js +20 -379
- package/dist/wallet/read/managed-services.d.ts +33 -0
- package/dist/wallet/read/managed-services.js +222 -0
- package/dist/wallet/state/client-password/bootstrap.d.ts +2 -0
- package/dist/wallet/state/client-password/bootstrap.js +3 -0
- package/dist/wallet/state/client-password/context.d.ts +10 -0
- package/dist/wallet/state/client-password/context.js +46 -0
- package/dist/wallet/state/client-password/crypto.d.ts +34 -0
- package/dist/wallet/state/client-password/crypto.js +117 -0
- package/dist/wallet/state/client-password/files.d.ts +10 -0
- package/dist/wallet/state/client-password/files.js +109 -0
- package/dist/wallet/state/client-password/legacy-cleanup.d.ts +11 -0
- package/dist/wallet/state/client-password/legacy-cleanup.js +338 -0
- package/dist/wallet/state/client-password/messages.d.ts +3 -0
- package/dist/wallet/state/client-password/messages.js +9 -0
- package/dist/wallet/state/client-password/migration.d.ts +4 -0
- package/dist/wallet/state/client-password/migration.js +32 -0
- package/dist/wallet/state/client-password/prompts.d.ts +12 -0
- package/dist/wallet/state/client-password/prompts.js +79 -0
- package/dist/wallet/state/client-password/protected-secrets.d.ts +13 -0
- package/dist/wallet/state/client-password/protected-secrets.js +90 -0
- package/dist/wallet/state/client-password/readiness.d.ts +4 -0
- package/dist/wallet/state/client-password/readiness.js +48 -0
- package/dist/wallet/state/client-password/references.d.ts +1 -0
- package/dist/wallet/state/client-password/references.js +56 -0
- package/dist/wallet/state/client-password/rotation.d.ts +6 -0
- package/dist/wallet/state/client-password/rotation.js +98 -0
- package/dist/wallet/state/client-password/session-policy.d.ts +6 -0
- package/dist/wallet/state/client-password/session-policy.js +28 -0
- package/dist/wallet/state/client-password/session.d.ts +19 -0
- package/dist/wallet/state/client-password/session.js +170 -0
- package/dist/wallet/state/client-password/setup.d.ts +8 -0
- package/dist/wallet/state/client-password/setup.js +49 -0
- package/dist/wallet/state/client-password/types.d.ts +82 -0
- package/dist/wallet/state/client-password/types.js +5 -0
- package/dist/wallet/state/client-password.d.ts +7 -38
- package/dist/wallet/state/client-password.js +52 -937
- package/dist/wallet/tx/anchor.js +123 -216
- package/dist/wallet/tx/cog.js +294 -489
- package/dist/wallet/tx/common.d.ts +2 -0
- package/dist/wallet/tx/common.js +2 -0
- package/dist/wallet/tx/domain-admin.js +111 -220
- package/dist/wallet/tx/domain-market.js +401 -681
- package/dist/wallet/tx/executor.d.ts +176 -0
- package/dist/wallet/tx/executor.js +302 -0
- package/dist/wallet/tx/field.js +109 -215
- package/dist/wallet/tx/register.js +158 -269
- package/dist/wallet/tx/reputation.js +120 -227
- package/package.json +1 -1
- package/dist/wallet/mining/worker-main.js +0 -17
- package/dist/wallet/state/client-password-agent.d.ts +0 -1
- package/dist/wallet/state/client-password-agent.js +0 -211
- /package/dist/{wallet/mining/worker-main.d.ts → bitcoind/managed-runtime/types.js} +0 -0
|
@@ -1,366 +1,122 @@
|
|
|
1
|
-
import { access, constants } from "node:fs/promises";
|
|
2
|
-
import { attachOrStartIndexerDaemon, probeIndexerDaemon, } from "../../bitcoind/indexer-daemon.js";
|
|
3
|
-
import { createRpcClient } from "../../bitcoind/node.js";
|
|
4
|
-
import { attachOrStartManagedBitcoindService, probeManagedBitcoindService } from "../../bitcoind/service.js";
|
|
5
1
|
import { resolveManagedServicePaths } from "../../bitcoind/service-paths.js";
|
|
6
|
-
import { persistWalletCoinControlStateIfNeeded } from "../coin-control.js";
|
|
7
|
-
import { normalizeWalletDescriptorState } from "../descriptor-normalization.js";
|
|
8
|
-
import { acquireFileLock } from "../fs/lock.js";
|
|
9
2
|
import { clearLegacyWalletLockArtifacts } from "../managed-core-wallet.js";
|
|
10
3
|
import { loadMiningRuntimeStatus } from "../mining/runtime-artifacts.js";
|
|
11
|
-
import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
12
|
-
import { createDefaultWalletSecretProvider, createWalletSecretReference, } from "../state/provider.js";
|
|
13
4
|
import { loadWalletState } from "../state/storage.js";
|
|
14
|
-
import {
|
|
5
|
+
import { acquireWalletControlLock, resolveWalletRepairContext, } from "./context.js";
|
|
6
|
+
import { repairManagedBitcoindStage } from "./repair-bitcoind.js";
|
|
7
|
+
import { repairManagedIndexerStage } from "./repair-indexer.js";
|
|
15
8
|
import { applyRepairStoppedMiningState, cleanupMiningForRepair, persistRepairState, resumeBackgroundMiningAfterRepair, } from "./repair-mining.js";
|
|
16
|
-
import {
|
|
17
|
-
async function pathExists(path) {
|
|
18
|
-
try {
|
|
19
|
-
await access(path, constants.F_OK);
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
9
|
+
import { clearOrphanedRepairLocks, ensureIndexerDatabaseHealthy, } from "./repair-runtime.js";
|
|
26
10
|
export async function repairWallet(options) {
|
|
27
|
-
const
|
|
28
|
-
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
29
|
-
const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
|
|
30
|
-
const probeManagedBitcoind = options.probeBitcoindService ?? probeManagedBitcoindService;
|
|
31
|
-
const attachManagedBitcoind = options.attachService ?? attachOrStartManagedBitcoindService;
|
|
32
|
-
const probeManagedIndexerDaemon = options.probeIndexerDaemon ?? probeIndexerDaemon;
|
|
33
|
-
const attachManagedIndexerDaemon = options.attachIndexerDaemon ?? attachOrStartIndexerDaemon;
|
|
11
|
+
const context = resolveWalletRepairContext(options);
|
|
34
12
|
await clearOrphanedRepairLocks([
|
|
35
|
-
paths.walletControlLockPath,
|
|
36
|
-
paths.miningControlLockPath,
|
|
13
|
+
context.paths.walletControlLockPath,
|
|
14
|
+
context.paths.miningControlLockPath,
|
|
37
15
|
]);
|
|
38
|
-
const controlLock = await
|
|
39
|
-
purpose: "wallet-repair",
|
|
40
|
-
walletRootId: null,
|
|
41
|
-
});
|
|
16
|
+
const controlLock = await acquireWalletControlLock(context.paths, "wallet-repair");
|
|
42
17
|
try {
|
|
43
18
|
let loaded;
|
|
44
19
|
try {
|
|
45
20
|
loaded = await loadWalletState({
|
|
46
|
-
primaryPath: paths.walletStatePath,
|
|
47
|
-
backupPath: paths.walletStateBackupPath,
|
|
21
|
+
primaryPath: context.paths.walletStatePath,
|
|
22
|
+
backupPath: context.paths.walletStateBackupPath,
|
|
48
23
|
}, {
|
|
49
|
-
provider,
|
|
24
|
+
provider: context.provider,
|
|
50
25
|
});
|
|
51
26
|
}
|
|
52
27
|
catch {
|
|
53
28
|
throw new Error("local-state-corrupt");
|
|
54
29
|
}
|
|
55
30
|
const recoveredFromBackup = loaded.source === "backup";
|
|
56
|
-
const secretReference = createWalletSecretReference(loaded.state.walletRootId);
|
|
57
31
|
let repairedState = loaded.state;
|
|
58
32
|
let repairStateNeedsPersist = false;
|
|
59
|
-
const servicePaths = resolveManagedServicePaths(
|
|
33
|
+
const servicePaths = resolveManagedServicePaths(context.dataDir, repairedState.walletRootId);
|
|
60
34
|
await clearOrphanedRepairLocks([
|
|
61
35
|
servicePaths.bitcoindLockPath,
|
|
62
36
|
servicePaths.indexerDaemonLockPath,
|
|
63
37
|
]);
|
|
64
|
-
const preRepairMiningRuntime = await loadMiningRuntimeStatus(paths.miningStatusPath).catch(() => null);
|
|
38
|
+
const preRepairMiningRuntime = await loadMiningRuntimeStatus(context.paths.miningStatusPath).catch(() => null);
|
|
65
39
|
const miningCleanup = await cleanupMiningForRepair({
|
|
66
|
-
paths,
|
|
40
|
+
paths: context.paths,
|
|
67
41
|
state: repairedState,
|
|
68
42
|
snapshot: preRepairMiningRuntime,
|
|
69
|
-
nowUnixMs,
|
|
43
|
+
nowUnixMs: context.nowUnixMs,
|
|
70
44
|
});
|
|
71
45
|
const miningPreRepairRunMode = miningCleanup.preRepairRunMode;
|
|
72
46
|
if (miningPreRepairRunMode !== "stopped" || preRepairMiningRuntime?.runMode !== "stopped") {
|
|
73
47
|
repairedState = applyRepairStoppedMiningState(repairedState);
|
|
74
48
|
repairStateNeedsPersist = true;
|
|
75
49
|
}
|
|
76
|
-
if (!
|
|
50
|
+
if (!context.assumeYes) {
|
|
77
51
|
await ensureIndexerDatabaseHealthy({
|
|
78
|
-
databasePath:
|
|
79
|
-
dataDir:
|
|
52
|
+
databasePath: context.databasePath,
|
|
53
|
+
dataDir: context.dataDir,
|
|
80
54
|
walletRootId: repairedState.walletRootId,
|
|
81
55
|
resetIfNeeded: false,
|
|
82
56
|
});
|
|
83
57
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
compatibility: "unreachable",
|
|
91
|
-
status: null,
|
|
92
|
-
error: null,
|
|
93
|
-
};
|
|
94
|
-
let resetIndexerDatabase = false;
|
|
95
|
-
let bitcoindHandle = null;
|
|
96
|
-
let bitcoindPostRepairHealth = "unavailable";
|
|
97
|
-
const bitcoindLock = await acquireFileLock(servicePaths.bitcoindLockPath, {
|
|
98
|
-
purpose: "managed-bitcoind-repair",
|
|
99
|
-
walletRootId: repairedState.walletRootId,
|
|
100
|
-
dataDir: options.dataDir,
|
|
58
|
+
const bitcoindStage = await repairManagedBitcoindStage({
|
|
59
|
+
context,
|
|
60
|
+
servicePaths,
|
|
61
|
+
state: repairedState,
|
|
62
|
+
recoveredFromBackup,
|
|
63
|
+
repairStateNeedsPersist,
|
|
101
64
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
65
|
+
repairedState = bitcoindStage.state;
|
|
66
|
+
repairStateNeedsPersist = bitcoindStage.repairStateNeedsPersist;
|
|
67
|
+
if (recoveredFromBackup) {
|
|
68
|
+
repairedState = await persistRepairState({
|
|
69
|
+
state: repairedState,
|
|
70
|
+
provider: context.provider,
|
|
71
|
+
paths: context.paths,
|
|
72
|
+
nowUnixMs: context.nowUnixMs,
|
|
73
|
+
replacePrimary: true,
|
|
108
74
|
});
|
|
109
|
-
|
|
110
|
-
if (initialBitcoindProbe.compatibility === "service-version-mismatch"
|
|
111
|
-
|| initialBitcoindProbe.compatibility === "wallet-root-mismatch"
|
|
112
|
-
|| initialBitcoindProbe.compatibility === "runtime-mismatch") {
|
|
113
|
-
const processId = initialBitcoindProbe.status?.processId ?? null;
|
|
114
|
-
if (processId === null) {
|
|
115
|
-
throw new Error("managed_bitcoind_process_id_unavailable");
|
|
116
|
-
}
|
|
117
|
-
try {
|
|
118
|
-
process.kill(processId, "SIGTERM");
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
if (!(error instanceof Error) || !("code" in error) || error.code !== "ESRCH") {
|
|
122
|
-
throw error;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
await waitForProcessExit(processId, 15_000, "managed_bitcoind_stop_timeout");
|
|
126
|
-
await clearManagedBitcoindArtifacts(servicePaths);
|
|
127
|
-
bitcoindServiceAction = "stopped-incompatible-service";
|
|
128
|
-
}
|
|
129
|
-
else if (initialBitcoindProbe.compatibility === "unreachable") {
|
|
130
|
-
const hasStaleArtifacts = await Promise.all([
|
|
131
|
-
servicePaths.bitcoindStatusPath,
|
|
132
|
-
servicePaths.bitcoindPidPath,
|
|
133
|
-
servicePaths.bitcoindReadyPath,
|
|
134
|
-
servicePaths.bitcoindWalletStatusPath,
|
|
135
|
-
].map(pathExists));
|
|
136
|
-
if (hasStaleArtifacts.some(Boolean)) {
|
|
137
|
-
await clearManagedBitcoindArtifacts(servicePaths);
|
|
138
|
-
bitcoindServiceAction = "cleared-stale-artifacts";
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
else if (initialBitcoindProbe.compatibility === "protocol-error") {
|
|
142
|
-
throw new Error(initialBitcoindProbe.error ?? "managed_bitcoind_protocol_error");
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
finally {
|
|
146
|
-
await bitcoindLock.release();
|
|
75
|
+
repairStateNeedsPersist = false;
|
|
147
76
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
dataDir: options.dataDir,
|
|
151
|
-
chain: "main",
|
|
152
|
-
startHeight: 0,
|
|
153
|
-
walletRootId: repairedState.walletRootId,
|
|
154
|
-
});
|
|
155
|
-
const bitcoindRpc = (options.rpcFactory ?? createRpcClient)(bitcoindHandle.rpc);
|
|
156
|
-
const normalizedDescriptorState = await normalizeWalletDescriptorState(repairedState, bitcoindRpc);
|
|
157
|
-
if (normalizedDescriptorState.changed) {
|
|
158
|
-
repairedState = normalizedDescriptorState.state;
|
|
159
|
-
repairStateNeedsPersist = true;
|
|
160
|
-
}
|
|
161
|
-
const reconciledCoinControl = await persistWalletCoinControlStateIfNeeded({
|
|
77
|
+
else if (repairStateNeedsPersist) {
|
|
78
|
+
repairedState = await persistRepairState({
|
|
162
79
|
state: repairedState,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
},
|
|
167
|
-
paths,
|
|
168
|
-
nowUnixMs,
|
|
169
|
-
replacePrimary: recoveredFromBackup && !repairStateNeedsPersist,
|
|
170
|
-
rpc: (options.rpcFactory ?? createRpcClient)(bitcoindHandle.rpc),
|
|
80
|
+
provider: context.provider,
|
|
81
|
+
paths: context.paths,
|
|
82
|
+
nowUnixMs: context.nowUnixMs,
|
|
171
83
|
});
|
|
172
|
-
|
|
173
|
-
if (reconciledCoinControl.changed) {
|
|
174
|
-
repairStateNeedsPersist = false;
|
|
175
|
-
}
|
|
176
|
-
let replica = await verifyManagedCoreWalletReplica(repairedState, options.dataDir, {
|
|
177
|
-
nodeHandle: bitcoindHandle,
|
|
178
|
-
attachService: options.attachService,
|
|
179
|
-
rpcFactory: options.rpcFactory,
|
|
180
|
-
});
|
|
181
|
-
let recreatedManagedCoreWallet = false;
|
|
182
|
-
if (replica.proofStatus !== "ready") {
|
|
183
|
-
repairedState = await recreateManagedCoreWalletReplica(repairedState, provider, paths, options.dataDir, nowUnixMs, {
|
|
184
|
-
attachService: options.attachService,
|
|
185
|
-
rpcFactory: options.rpcFactory,
|
|
186
|
-
});
|
|
187
|
-
recreatedManagedCoreWallet = true;
|
|
188
|
-
managedCoreReplicaAction = "recreated";
|
|
189
|
-
repairStateNeedsPersist = false;
|
|
190
|
-
replica = await verifyManagedCoreWalletReplica(repairedState, options.dataDir, {
|
|
191
|
-
nodeHandle: bitcoindHandle,
|
|
192
|
-
attachService: options.attachService,
|
|
193
|
-
rpcFactory: options.rpcFactory,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
const finalBitcoindStatus = await bitcoindHandle.refreshServiceStatus?.() ?? null;
|
|
197
|
-
const chainInfo = await bitcoindRpc.getBlockchainInfo();
|
|
198
|
-
bitcoindPostRepairHealth = mapBitcoindRepairHealth({
|
|
199
|
-
serviceState: finalBitcoindStatus?.state ?? null,
|
|
200
|
-
catchingUp: chainInfo.blocks < chainInfo.headers,
|
|
201
|
-
replica,
|
|
202
|
-
});
|
|
203
|
-
if (bitcoindServiceAction === "none" && initialBitcoindProbe.compatibility === "unreachable") {
|
|
204
|
-
bitcoindServiceAction = "restarted-compatible-service";
|
|
205
|
-
}
|
|
206
|
-
let initialIndexerDaemonInstanceId = null;
|
|
207
|
-
let preAttachIndexerDaemonInstanceId = null;
|
|
208
|
-
const indexerLock = await acquireFileLock(servicePaths.indexerDaemonLockPath, {
|
|
209
|
-
purpose: "indexer-daemon-repair",
|
|
210
|
-
walletRootId: repairedState.walletRootId,
|
|
211
|
-
dataDir: options.dataDir,
|
|
212
|
-
databasePath: options.databasePath,
|
|
213
|
-
});
|
|
214
|
-
try {
|
|
215
|
-
const initialProbe = await probeManagedIndexerDaemon({
|
|
216
|
-
dataDir: options.dataDir,
|
|
217
|
-
walletRootId: repairedState.walletRootId,
|
|
218
|
-
});
|
|
219
|
-
indexerCompatibilityIssue = mapIndexerCompatibilityToRepairIssue(initialProbe.compatibility);
|
|
220
|
-
initialIndexerDaemonInstanceId = initialProbe.status?.daemonInstanceId ?? null;
|
|
221
|
-
if (initialProbe.compatibility === "compatible") {
|
|
222
|
-
await initialProbe.client?.close().catch(() => undefined);
|
|
223
|
-
}
|
|
224
|
-
else if (initialProbe.compatibility === "service-version-mismatch"
|
|
225
|
-
|| initialProbe.compatibility === "wallet-root-mismatch"
|
|
226
|
-
|| initialProbe.compatibility === "schema-mismatch") {
|
|
227
|
-
const processId = initialProbe.status?.processId ?? null;
|
|
228
|
-
if (processId === null) {
|
|
229
|
-
throw new Error("indexer_daemon_process_id_unavailable");
|
|
230
|
-
}
|
|
231
|
-
try {
|
|
232
|
-
process.kill(processId, "SIGTERM");
|
|
233
|
-
}
|
|
234
|
-
catch (error) {
|
|
235
|
-
if (!(error instanceof Error) || !("code" in error) || error.code !== "ESRCH") {
|
|
236
|
-
throw error;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
await waitForProcessExit(processId);
|
|
240
|
-
await clearIndexerDaemonArtifacts(servicePaths);
|
|
241
|
-
indexerDaemonAction = "stopped-incompatible-daemon";
|
|
242
|
-
}
|
|
243
|
-
else if (initialProbe.compatibility === "unreachable") {
|
|
244
|
-
const hasStaleArtifacts = await Promise.all([
|
|
245
|
-
servicePaths.indexerDaemonSocketPath,
|
|
246
|
-
servicePaths.indexerDaemonStatusPath,
|
|
247
|
-
].map(pathExists));
|
|
248
|
-
if (hasStaleArtifacts.some(Boolean)) {
|
|
249
|
-
await clearIndexerDaemonArtifacts(servicePaths);
|
|
250
|
-
indexerDaemonAction = "cleared-stale-artifacts";
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
throw new Error(initialProbe.error ?? "indexer_daemon_protocol_error");
|
|
255
|
-
}
|
|
256
|
-
resetIndexerDatabase = await ensureIndexerDatabaseHealthy({
|
|
257
|
-
databasePath: options.databasePath,
|
|
258
|
-
dataDir: options.dataDir,
|
|
259
|
-
walletRootId: repairedState.walletRootId,
|
|
260
|
-
resetIfNeeded: options.assumeYes ?? false,
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
finally {
|
|
264
|
-
await indexerLock.release();
|
|
265
|
-
}
|
|
266
|
-
if (recoveredFromBackup) {
|
|
267
|
-
repairedState = await persistRepairState({
|
|
268
|
-
state: repairedState,
|
|
269
|
-
provider,
|
|
270
|
-
paths,
|
|
271
|
-
nowUnixMs,
|
|
272
|
-
replacePrimary: true,
|
|
273
|
-
});
|
|
274
|
-
repairStateNeedsPersist = false;
|
|
275
|
-
}
|
|
276
|
-
else if (repairStateNeedsPersist) {
|
|
277
|
-
repairedState = await persistRepairState({
|
|
278
|
-
state: repairedState,
|
|
279
|
-
provider,
|
|
280
|
-
paths,
|
|
281
|
-
nowUnixMs,
|
|
282
|
-
});
|
|
283
|
-
repairStateNeedsPersist = false;
|
|
284
|
-
}
|
|
285
|
-
const preAttachProbe = await probeManagedIndexerDaemon({
|
|
286
|
-
dataDir: options.dataDir,
|
|
287
|
-
walletRootId: repairedState.walletRootId,
|
|
288
|
-
});
|
|
289
|
-
if (preAttachProbe.compatibility === "compatible") {
|
|
290
|
-
preAttachIndexerDaemonInstanceId = preAttachProbe.status?.daemonInstanceId ?? null;
|
|
291
|
-
await preAttachProbe.client?.close().catch(() => undefined);
|
|
292
|
-
}
|
|
293
|
-
else if (preAttachProbe.compatibility !== "unreachable") {
|
|
294
|
-
throw new Error(preAttachProbe.error ?? "indexer_daemon_protocol_error");
|
|
295
|
-
}
|
|
296
|
-
const daemon = await attachManagedIndexerDaemon({
|
|
297
|
-
dataDir: options.dataDir,
|
|
298
|
-
databasePath: options.databasePath,
|
|
299
|
-
walletRootId: repairedState.walletRootId,
|
|
300
|
-
});
|
|
301
|
-
try {
|
|
302
|
-
const { health: indexerPostRepairHealth, daemonInstanceId: postRepairDaemonInstanceId, } = await verifyIndexerPostRepairHealth({
|
|
303
|
-
daemon,
|
|
304
|
-
probeIndexerDaemon: probeManagedIndexerDaemon,
|
|
305
|
-
dataDir: options.dataDir,
|
|
306
|
-
walletRootId: repairedState.walletRootId,
|
|
307
|
-
nowUnixMs,
|
|
308
|
-
});
|
|
309
|
-
const restartedIndexerDaemon = indexerDaemonAction !== "none" || preAttachProbe.compatibility === "unreachable";
|
|
310
|
-
if (restartedIndexerDaemon
|
|
311
|
-
&& initialIndexerDaemonInstanceId !== null
|
|
312
|
-
&& postRepairDaemonInstanceId === initialIndexerDaemonInstanceId) {
|
|
313
|
-
throw new Error("indexer_daemon_repair_identity_not_rotated");
|
|
314
|
-
}
|
|
315
|
-
if (!restartedIndexerDaemon
|
|
316
|
-
&& preAttachProbe.compatibility === "compatible"
|
|
317
|
-
&& preAttachIndexerDaemonInstanceId !== null
|
|
318
|
-
&& postRepairDaemonInstanceId !== preAttachIndexerDaemonInstanceId) {
|
|
319
|
-
throw new Error("indexer_daemon_repair_identity_changed");
|
|
320
|
-
}
|
|
321
|
-
if (indexerDaemonAction === "none" && preAttachProbe.compatibility === "unreachable") {
|
|
322
|
-
indexerDaemonAction = "restarted-compatible-daemon";
|
|
323
|
-
}
|
|
324
|
-
const miningResume = await resumeBackgroundMiningAfterRepair({
|
|
325
|
-
miningPreRepairRunMode,
|
|
326
|
-
provider,
|
|
327
|
-
paths,
|
|
328
|
-
repairedState,
|
|
329
|
-
bitcoindPostRepairHealth,
|
|
330
|
-
indexerPostRepairHealth,
|
|
331
|
-
dataDir: options.dataDir,
|
|
332
|
-
databasePath: options.databasePath,
|
|
333
|
-
startBackgroundMining: options.startBackgroundMining,
|
|
334
|
-
});
|
|
335
|
-
await clearLegacyWalletLockArtifacts(paths.walletRuntimeRoot);
|
|
336
|
-
return {
|
|
337
|
-
walletRootId: repairedState.walletRootId,
|
|
338
|
-
recoveredFromBackup,
|
|
339
|
-
recreatedManagedCoreWallet,
|
|
340
|
-
resetIndexerDatabase,
|
|
341
|
-
bitcoindServiceAction,
|
|
342
|
-
bitcoindCompatibilityIssue,
|
|
343
|
-
managedCoreReplicaAction,
|
|
344
|
-
bitcoindPostRepairHealth,
|
|
345
|
-
indexerDaemonAction,
|
|
346
|
-
indexerCompatibilityIssue,
|
|
347
|
-
indexerPostRepairHealth,
|
|
348
|
-
miningPreRepairRunMode,
|
|
349
|
-
miningResumeAction: miningResume.miningResumeAction,
|
|
350
|
-
miningPostRepairRunMode: miningResume.miningPostRepairRunMode,
|
|
351
|
-
miningResumeError: miningResume.miningResumeError,
|
|
352
|
-
note: resetIndexerDatabase
|
|
353
|
-
? "Indexer artifacts were reset and may still be catching up."
|
|
354
|
-
: null,
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
finally {
|
|
358
|
-
await daemon.close().catch(() => undefined);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
finally {
|
|
362
|
-
await bitcoindHandle?.stop?.().catch(() => undefined);
|
|
84
|
+
repairStateNeedsPersist = false;
|
|
363
85
|
}
|
|
86
|
+
const indexerStage = await repairManagedIndexerStage({
|
|
87
|
+
context,
|
|
88
|
+
servicePaths,
|
|
89
|
+
state: repairedState,
|
|
90
|
+
});
|
|
91
|
+
const miningResume = await resumeBackgroundMiningAfterRepair({
|
|
92
|
+
miningPreRepairRunMode,
|
|
93
|
+
provider: context.provider,
|
|
94
|
+
paths: context.paths,
|
|
95
|
+
repairedState,
|
|
96
|
+
bitcoindPostRepairHealth: bitcoindStage.bitcoindPostRepairHealth,
|
|
97
|
+
indexerPostRepairHealth: indexerStage.indexerPostRepairHealth,
|
|
98
|
+
});
|
|
99
|
+
await clearLegacyWalletLockArtifacts(context.paths.walletRuntimeRoot);
|
|
100
|
+
return {
|
|
101
|
+
walletRootId: repairedState.walletRootId,
|
|
102
|
+
recoveredFromBackup,
|
|
103
|
+
recreatedManagedCoreWallet: bitcoindStage.recreatedManagedCoreWallet,
|
|
104
|
+
resetIndexerDatabase: indexerStage.resetIndexerDatabase,
|
|
105
|
+
bitcoindServiceAction: bitcoindStage.bitcoindServiceAction,
|
|
106
|
+
bitcoindCompatibilityIssue: bitcoindStage.bitcoindCompatibilityIssue,
|
|
107
|
+
managedCoreReplicaAction: bitcoindStage.managedCoreReplicaAction,
|
|
108
|
+
bitcoindPostRepairHealth: bitcoindStage.bitcoindPostRepairHealth,
|
|
109
|
+
indexerDaemonAction: indexerStage.indexerDaemonAction,
|
|
110
|
+
indexerCompatibilityIssue: indexerStage.indexerCompatibilityIssue,
|
|
111
|
+
indexerPostRepairHealth: indexerStage.indexerPostRepairHealth,
|
|
112
|
+
miningPreRepairRunMode,
|
|
113
|
+
miningResumeAction: miningResume.miningResumeAction,
|
|
114
|
+
miningPostRepairRunMode: miningResume.miningPostRepairRunMode,
|
|
115
|
+
miningResumeError: miningResume.miningResumeError,
|
|
116
|
+
note: indexerStage.resetIndexerDatabase
|
|
117
|
+
? "Indexer artifacts were reset and may still be catching up."
|
|
118
|
+
: null,
|
|
119
|
+
};
|
|
364
120
|
}
|
|
365
121
|
finally {
|
|
366
122
|
await controlLock.release();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { WalletInitializationResult, WalletPrompter } from "./types.js";
|
|
2
|
+
export declare function promptForRestoreMnemonic(prompter: WalletPrompter): Promise<string>;
|
|
3
|
+
export declare function promptForInitializationMode(prompter: WalletPrompter): Promise<Exclude<WalletInitializationResult["setupMode"], "existing">>;
|
|
4
|
+
export declare function confirmTypedAcknowledgement(prompter: WalletPrompter, expected: string, message: string, errorCode?: string): Promise<void>;
|
|
5
|
+
export declare function writeMnemonicReveal(prompter: WalletPrompter, phrase: string, introLines: readonly string[]): void;
|
|
6
|
+
export declare function confirmMnemonic(prompter: WalletPrompter, words: readonly string[]): Promise<void>;
|
|
7
|
+
export declare function clearSensitiveDisplay(prompter: WalletPrompter, scope: "mnemonic-reveal" | "restore-mnemonic-entry"): Promise<void>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { createMnemonicConfirmationChallenge, isEnglishMnemonicWord, validateEnglishMnemonic, } from "../material.js";
|
|
2
|
+
import { renderWalletMnemonicRevealArt } from "../mnemonic-art.js";
|
|
3
|
+
async function promptRequiredValue(prompter, message) {
|
|
4
|
+
const value = (await prompter.prompt(message)).trim();
|
|
5
|
+
if (value === "") {
|
|
6
|
+
throw new Error("wallet_prompt_value_required");
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
export async function promptForRestoreMnemonic(prompter) {
|
|
11
|
+
const words = [];
|
|
12
|
+
for (let index = 0; index < 24; index += 1) {
|
|
13
|
+
const word = (await promptRequiredValue(prompter, `Word ${index + 1} of 24: `)).toLowerCase();
|
|
14
|
+
if (!isEnglishMnemonicWord(word)) {
|
|
15
|
+
throw new Error("wallet_restore_mnemonic_invalid");
|
|
16
|
+
}
|
|
17
|
+
words.push(word);
|
|
18
|
+
}
|
|
19
|
+
const phrase = words.join(" ");
|
|
20
|
+
if (!validateEnglishMnemonic(phrase)) {
|
|
21
|
+
throw new Error("wallet_restore_mnemonic_invalid");
|
|
22
|
+
}
|
|
23
|
+
return phrase;
|
|
24
|
+
}
|
|
25
|
+
export async function promptForInitializationMode(prompter) {
|
|
26
|
+
if (prompter.selectOption != null) {
|
|
27
|
+
return await prompter.selectOption({
|
|
28
|
+
message: "How should Cogcoin set up this wallet?",
|
|
29
|
+
options: [
|
|
30
|
+
{
|
|
31
|
+
label: "Create new wallet",
|
|
32
|
+
description: "Generate a fresh 24-word recovery phrase.",
|
|
33
|
+
value: "generated",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: "Restore existing wallet",
|
|
37
|
+
description: "Enter an existing 24-word recovery phrase.",
|
|
38
|
+
value: "restored",
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
initialValue: "generated",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
prompter.writeLine("How should Cogcoin set up this wallet?");
|
|
45
|
+
prompter.writeLine("1. Create new wallet");
|
|
46
|
+
prompter.writeLine("2. Restore existing wallet");
|
|
47
|
+
while (true) {
|
|
48
|
+
const answer = (await prompter.prompt("Choice [1-2]: ")).trim();
|
|
49
|
+
if (answer === "1") {
|
|
50
|
+
return "generated";
|
|
51
|
+
}
|
|
52
|
+
if (answer === "2") {
|
|
53
|
+
return "restored";
|
|
54
|
+
}
|
|
55
|
+
prompter.writeLine("Enter 1 or 2.");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function confirmTypedAcknowledgement(prompter, expected, message, errorCode = "wallet_typed_confirmation_rejected") {
|
|
59
|
+
const answer = (await prompter.prompt(message)).trim();
|
|
60
|
+
if (answer !== expected) {
|
|
61
|
+
throw new Error(errorCode);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function writeMnemonicReveal(prompter, phrase, introLines) {
|
|
65
|
+
const words = phrase.trim().split(/\s+/);
|
|
66
|
+
for (const line of introLines) {
|
|
67
|
+
prompter.writeLine(line);
|
|
68
|
+
}
|
|
69
|
+
for (const line of renderWalletMnemonicRevealArt(words)) {
|
|
70
|
+
prompter.writeLine(line);
|
|
71
|
+
}
|
|
72
|
+
prompter.writeLine("Single-line copy:");
|
|
73
|
+
prompter.writeLine(phrase);
|
|
74
|
+
}
|
|
75
|
+
export async function confirmMnemonic(prompter, words) {
|
|
76
|
+
const challenge = createMnemonicConfirmationChallenge([...words]);
|
|
77
|
+
for (const entry of challenge) {
|
|
78
|
+
const answer = (await prompter.prompt(`Confirm word #${entry.index + 1}: `)).trim().toLowerCase();
|
|
79
|
+
if (answer !== entry.word) {
|
|
80
|
+
throw new Error(`wallet_init_confirmation_failed_word_${entry.index + 1}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export async function clearSensitiveDisplay(prompter, scope) {
|
|
85
|
+
await Promise.resolve()
|
|
86
|
+
.then(() => prompter.clearSensitiveDisplay?.(scope))
|
|
87
|
+
.catch(() => undefined);
|
|
88
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { deriveWalletMaterialFromMnemonic } from "../material.js";
|
|
2
|
+
import type { WalletRuntimePaths } from "../runtime.js";
|
|
3
|
+
import { type WalletSecretProvider } from "../state/provider.js";
|
|
4
|
+
import type { WalletStateV1 } from "../types.js";
|
|
5
|
+
import type { WalletSetupContext } from "./types.js";
|
|
6
|
+
export type WalletMaterial = ReturnType<typeof deriveWalletMaterialFromMnemonic>;
|
|
7
|
+
export declare function clearPendingInitialization(paths: WalletRuntimePaths, provider: WalletSecretProvider): Promise<void>;
|
|
8
|
+
export declare function loadOrCreatePendingInitializationMaterial(options: {
|
|
9
|
+
provider: WalletSecretProvider;
|
|
10
|
+
paths: WalletRuntimePaths;
|
|
11
|
+
nowUnixMs: number;
|
|
12
|
+
}): Promise<WalletMaterial>;
|
|
13
|
+
export declare function createInitialWalletState(options: {
|
|
14
|
+
walletRootId: string;
|
|
15
|
+
nowUnixMs: number;
|
|
16
|
+
material: WalletMaterial;
|
|
17
|
+
internalCoreWalletPassphrase: string;
|
|
18
|
+
}): WalletStateV1;
|
|
19
|
+
export declare function persistInitializedWallet(options: {
|
|
20
|
+
context: WalletSetupContext;
|
|
21
|
+
provider: WalletSecretProvider;
|
|
22
|
+
material: WalletMaterial;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
walletRootId: string;
|
|
25
|
+
state: WalletStateV1;
|
|
26
|
+
}>;
|