@cogcoin/client 1.1.6 → 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.js +29 -79
- 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-runtime.d.ts +15 -0
- package/dist/bitcoind/managed-runtime/indexer-runtime.js +82 -0
- package/dist/bitcoind/managed-runtime/types.d.ts +40 -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.js +46 -126
- 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/context.js +0 -1
- package/dist/wallet/lifecycle/repair-mining.d.ts +1 -5
- package/dist/wallet/lifecycle/repair-mining.js +5 -39
- package/dist/wallet/lifecycle/repair.js +0 -3
- package/dist/wallet/lifecycle/setup.js +10 -8
- package/dist/wallet/lifecycle/types.d.ts +1 -4
- 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 -204
- 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.d.ts +0 -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/bitcoind/service.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { execFile, spawn } from "node:child_process";
|
|
3
|
-
import { access, constants, mkdir, readFile,
|
|
3
|
+
import { access, constants, mkdir, readFile, rm } from "node:fs/promises";
|
|
4
4
|
import { totalmem } from "node:os";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
import { promisify } from "node:util";
|
|
@@ -10,7 +10,9 @@ import { acquireFileLock, FileLockBusyError } from "../wallet/fs/lock.js";
|
|
|
10
10
|
import { writeFileAtomic } from "../wallet/fs/atomic.js";
|
|
11
11
|
import { writeRuntimeStatusFile } from "../wallet/fs/status-file.js";
|
|
12
12
|
import { stopIndexerDaemonServiceWithLockHeld } from "./indexer-daemon.js";
|
|
13
|
-
import { mapManagedBitcoindRuntimeProbeFailure, mapManagedBitcoindValidationError,
|
|
13
|
+
import { mapManagedBitcoindRuntimeProbeFailure, mapManagedBitcoindValidationError, validateManagedBitcoindObservedStatus, } from "./managed-runtime/bitcoind-policy.js";
|
|
14
|
+
import { listManagedBitcoindStatusCandidates, readManagedBitcoindObservedStatus, } from "./managed-runtime/bitcoind-status.js";
|
|
15
|
+
import { attachOrStartManagedBitcoindRuntime, probeManagedBitcoindRuntime, } from "./managed-runtime/bitcoind-runtime.js";
|
|
14
16
|
import { readJsonFileIfPresent } from "./managed-runtime/status.js";
|
|
15
17
|
import { createRpcClient, validateNodeConfigForTesting } from "./node.js";
|
|
16
18
|
import { resolveManagedServicePaths, UNINITIALIZED_WALLET_ROOT_ID } from "./service-paths.js";
|
|
@@ -78,42 +80,6 @@ async function acquireFileLockWithRetry(lockPath, metadata, timeoutMs) {
|
|
|
78
80
|
function getWalletReplicaName(walletRootId) {
|
|
79
81
|
return `cogcoin-${walletRootId}`.replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 63);
|
|
80
82
|
}
|
|
81
|
-
async function listManagedBitcoindStatusCandidates(options) {
|
|
82
|
-
const candidates = new Map();
|
|
83
|
-
const addCandidate = async (statusPath, allowDataDirMismatch = false) => {
|
|
84
|
-
const status = await readJsonFileIfPresent(statusPath);
|
|
85
|
-
if (status === null) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
if (!allowDataDirMismatch && status.dataDir !== options.dataDir) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
candidates.set(statusPath, status);
|
|
92
|
-
};
|
|
93
|
-
await addCandidate(options.expectedStatusPath, true);
|
|
94
|
-
try {
|
|
95
|
-
const entries = await readdir(options.runtimeRoot, {
|
|
96
|
-
withFileTypes: true,
|
|
97
|
-
});
|
|
98
|
-
for (const entry of entries) {
|
|
99
|
-
if (!entry.isDirectory()) {
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
const statusPath = join(options.runtimeRoot, entry.name, "bitcoind-status.json");
|
|
103
|
-
if (statusPath === options.expectedStatusPath) {
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
await addCandidate(statusPath);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
// Missing runtime roots are handled by returning no candidates.
|
|
111
|
-
}
|
|
112
|
-
return [...candidates.entries()].map(([statusPath, status]) => ({
|
|
113
|
-
statusPath,
|
|
114
|
-
status,
|
|
115
|
-
}));
|
|
116
|
-
}
|
|
117
83
|
async function allocatePort() {
|
|
118
84
|
return new Promise((resolve, reject) => {
|
|
119
85
|
const server = net.createServer();
|
|
@@ -664,44 +630,19 @@ async function tryAttachExistingManagedBitcoindService(options) {
|
|
|
664
630
|
const refreshed = await refreshManagedBitcoindStatus(probe.status, paths, options);
|
|
665
631
|
return createNodeHandle(refreshed, paths, options, "attached");
|
|
666
632
|
}
|
|
667
|
-
async function waitForManagedBitcoindService(options, timeoutMs) {
|
|
668
|
-
const deadline = Date.now() + timeoutMs;
|
|
669
|
-
while (Date.now() < deadline) {
|
|
670
|
-
const attached = await tryAttachExistingManagedBitcoindService(options).catch(() => null);
|
|
671
|
-
if (attached !== null) {
|
|
672
|
-
return attached;
|
|
673
|
-
}
|
|
674
|
-
await sleep(250);
|
|
675
|
-
}
|
|
676
|
-
throw new Error("managed_bitcoind_service_start_timeout");
|
|
677
|
-
}
|
|
678
633
|
export async function probeManagedBitcoindService(options) {
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
const candidates = await listManagedBitcoindStatusCandidates({
|
|
634
|
+
const resolvedOptions = {
|
|
635
|
+
...options,
|
|
682
636
|
dataDir: options.dataDir ?? "",
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
});
|
|
686
|
-
const expectedCandidate = candidates.find((candidate) => candidate.statusPath === paths.bitcoindStatusPath) ?? null;
|
|
687
|
-
for (const candidate of candidates) {
|
|
688
|
-
if (!await isProcessAlive(candidate.status.processId)) {
|
|
689
|
-
continue;
|
|
690
|
-
}
|
|
691
|
-
return probeManagedBitcoindStatusCandidate(candidate.status, options, paths.walletRuntimeRoot);
|
|
692
|
-
}
|
|
693
|
-
if (expectedCandidate !== null) {
|
|
694
|
-
return {
|
|
695
|
-
compatibility: "unreachable",
|
|
696
|
-
status: expectedCandidate.status,
|
|
697
|
-
error: null,
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
return {
|
|
701
|
-
compatibility: "unreachable",
|
|
702
|
-
status: candidates[0]?.status ?? null,
|
|
703
|
-
error: null,
|
|
637
|
+
walletRootId: options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID,
|
|
638
|
+
startupTimeoutMs: options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS,
|
|
704
639
|
};
|
|
640
|
+
return probeManagedBitcoindRuntime(resolvedOptions, {
|
|
641
|
+
getPaths: (runtimeOptions) => resolveManagedServicePaths(runtimeOptions.dataDir, runtimeOptions.walletRootId),
|
|
642
|
+
listStatusCandidates: listManagedBitcoindStatusCandidates,
|
|
643
|
+
isProcessAlive,
|
|
644
|
+
probeStatusCandidate: probeManagedBitcoindStatusCandidate,
|
|
645
|
+
});
|
|
705
646
|
}
|
|
706
647
|
export async function attachOrStartManagedBitcoindService(options) {
|
|
707
648
|
const resolvedOptions = {
|
|
@@ -716,42 +657,27 @@ export async function attachOrStartManagedBitcoindService(options) {
|
|
|
716
657
|
walletRootId: resolvedOptions.walletRootId,
|
|
717
658
|
shutdownTimeoutMs: resolvedOptions.shutdownTimeoutMs,
|
|
718
659
|
}, async () => {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
const paths = resolveManagedServicePaths(resolvedOptions.dataDir ?? "", resolvedOptions.walletRootId);
|
|
732
|
-
try {
|
|
733
|
-
const lock = await acquireFileLock(paths.bitcoindLockPath, {
|
|
660
|
+
return attachOrStartManagedBitcoindRuntime({
|
|
661
|
+
...resolvedOptions,
|
|
662
|
+
dataDir: resolvedOptions.dataDir ?? "",
|
|
663
|
+
walletRootId: resolvedOptions.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID,
|
|
664
|
+
startupTimeoutMs,
|
|
665
|
+
}, {
|
|
666
|
+
getPaths: (runtimeOptions) => resolveManagedServicePaths(runtimeOptions.dataDir, runtimeOptions.walletRootId),
|
|
667
|
+
listStatusCandidates: listManagedBitcoindStatusCandidates,
|
|
668
|
+
isProcessAlive,
|
|
669
|
+
probeStatusCandidate: probeManagedBitcoindStatusCandidate,
|
|
670
|
+
attachExisting: tryAttachExistingManagedBitcoindService,
|
|
671
|
+
acquireStartLock: async (runtimeOptions, paths) => acquireFileLock(paths.bitcoindLockPath, {
|
|
734
672
|
purpose: "managed-bitcoind-start",
|
|
735
|
-
walletRootId:
|
|
736
|
-
dataDir:
|
|
737
|
-
})
|
|
738
|
-
|
|
739
|
-
const liveProbe = await probeManagedBitcoindService(resolvedOptions);
|
|
740
|
-
const liveDecision = resolveManagedBitcoindProbeDecision(liveProbe);
|
|
741
|
-
if (liveDecision.action === "attach") {
|
|
742
|
-
const reattached = await tryAttachExistingManagedBitcoindService(resolvedOptions);
|
|
743
|
-
if (reattached !== null) {
|
|
744
|
-
return reattached;
|
|
745
|
-
}
|
|
746
|
-
throw new Error("managed_bitcoind_protocol_error");
|
|
747
|
-
}
|
|
748
|
-
if (liveDecision.action === "reject") {
|
|
749
|
-
throw new Error(liveDecision.error ?? "managed_bitcoind_protocol_error");
|
|
750
|
-
}
|
|
673
|
+
walletRootId: runtimeOptions.walletRootId,
|
|
674
|
+
dataDir: runtimeOptions.dataDir,
|
|
675
|
+
}),
|
|
676
|
+
startService: async (runtimeOptions, paths) => {
|
|
751
677
|
const bitcoindPath = await getBitcoindPath();
|
|
752
678
|
await verifyBitcoindVersion(bitcoindPath);
|
|
753
679
|
const binaryVersion = SUPPORTED_BITCOIND_VERSION;
|
|
754
|
-
await mkdir(
|
|
680
|
+
await mkdir(runtimeOptions.dataDir, { recursive: true });
|
|
755
681
|
const startManagedProcess = async (startOptions) => {
|
|
756
682
|
const runtimeConfig = await resolveRuntimeConfig(paths.bitcoindStatusPath, paths.bitcoindRuntimeConfigPath, startOptions);
|
|
757
683
|
await writeBitcoinConf(paths.bitcoinConfPath, startOptions, runtimeConfig);
|
|
@@ -793,16 +719,15 @@ export async function attachOrStartManagedBitcoindService(options) {
|
|
|
793
719
|
throw error;
|
|
794
720
|
}
|
|
795
721
|
const nowUnixMs = Date.now();
|
|
796
|
-
const
|
|
797
|
-
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc, walletRootId, startOptions.dataDir ?? "");
|
|
722
|
+
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc, startOptions.walletRootId, startOptions.dataDir);
|
|
798
723
|
return createBitcoindServiceStatus({
|
|
799
724
|
binaryVersion,
|
|
800
725
|
serviceInstanceId: randomBytes(16).toString("hex"),
|
|
801
726
|
state: "ready",
|
|
802
727
|
processId: child.pid ?? null,
|
|
803
|
-
walletRootId,
|
|
728
|
+
walletRootId: startOptions.walletRootId,
|
|
804
729
|
chain: startOptions.chain,
|
|
805
|
-
dataDir: startOptions.dataDir
|
|
730
|
+
dataDir: startOptions.dataDir,
|
|
806
731
|
runtimeRoot: paths.walletRuntimeRoot,
|
|
807
732
|
startHeight: startOptions.startHeight,
|
|
808
733
|
rpc: rpcConfig,
|
|
@@ -818,32 +743,25 @@ export async function attachOrStartManagedBitcoindService(options) {
|
|
|
818
743
|
};
|
|
819
744
|
let status;
|
|
820
745
|
try {
|
|
821
|
-
status = await startManagedProcess(
|
|
746
|
+
status = await startManagedProcess(runtimeOptions);
|
|
822
747
|
}
|
|
823
748
|
catch (error) {
|
|
824
|
-
if (
|
|
749
|
+
if (runtimeOptions.getblockArchivePath === undefined || runtimeOptions.getblockArchivePath === null) {
|
|
825
750
|
throw error;
|
|
826
751
|
}
|
|
827
752
|
status = await startManagedProcess({
|
|
828
|
-
...
|
|
753
|
+
...runtimeOptions,
|
|
829
754
|
getblockArchivePath: null,
|
|
830
755
|
getblockArchiveEndHeight: null,
|
|
831
756
|
getblockArchiveSha256: null,
|
|
832
757
|
});
|
|
833
758
|
}
|
|
834
759
|
await writeBitcoindStatus(paths, status);
|
|
835
|
-
return createNodeHandle(status,
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
}
|
|
841
|
-
catch (error) {
|
|
842
|
-
if (error instanceof FileLockBusyError) {
|
|
843
|
-
return waitForManagedBitcoindService(resolvedOptions, startupTimeoutMs);
|
|
844
|
-
}
|
|
845
|
-
throw error;
|
|
846
|
-
}
|
|
760
|
+
return createNodeHandle(status, resolveManagedServicePaths(runtimeOptions.dataDir, runtimeOptions.walletRootId), runtimeOptions, "started");
|
|
761
|
+
},
|
|
762
|
+
isLockBusyError: (error) => error instanceof FileLockBusyError,
|
|
763
|
+
sleep,
|
|
764
|
+
});
|
|
847
765
|
});
|
|
848
766
|
}
|
|
849
767
|
export async function stopManagedBitcoindService(options) {
|
|
@@ -866,8 +784,10 @@ export async function stopManagedBitcoindService(options) {
|
|
|
866
784
|
}
|
|
867
785
|
}
|
|
868
786
|
export async function readManagedBitcoindServiceStatusForTesting(dataDir, walletRootId = UNINITIALIZED_WALLET_ROOT_ID) {
|
|
869
|
-
|
|
870
|
-
|
|
787
|
+
return readManagedBitcoindObservedStatus({
|
|
788
|
+
dataDir,
|
|
789
|
+
walletRootId,
|
|
790
|
+
});
|
|
871
791
|
}
|
|
872
792
|
export async function shutdownManagedBitcoindServiceForTesting(options) {
|
|
873
793
|
await stopManagedBitcoindService({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type CommandHandlerFamily = "status" | "update" | "sync" | "follow" | "client-admin" | "service-runtime" | "wallet-admin" | "wallet-read" | "wallet-mutation" | "mining-admin" | "mining-runtime" | "mining-read";
|
|
2
|
-
export type CommandName = "init" | "reset" | "repair" | "update" | "sync" | "status" | "client-
|
|
2
|
+
export type CommandName = "init" | "reset" | "repair" | "update" | "sync" | "status" | "client-change-password" | "follow" | "bitcoin-start" | "bitcoin-stop" | "bitcoin-status" | "bitcoin-transfer" | "indexer-start" | "indexer-stop" | "indexer-status" | "anchor" | "register" | "transfer" | "sell" | "unsell" | "buy" | "domain-endpoint-set" | "domain-endpoint-clear" | "domain-delegate-set" | "domain-delegate-clear" | "domain-miner-set" | "domain-miner-clear" | "domain-canonical" | "fields" | "field" | "field-create" | "field-set" | "field-clear" | "send" | "claim" | "reclaim" | "cog-lock" | "rep-give" | "rep-revoke" | "mine" | "mine-setup" | "mine-prompt" | "mine-prompt-list" | "mine-status" | "mine-log" | "wallet-show-mnemonic" | "wallet-status" | "address" | "ids" | "balance" | "locks" | "domains" | "show";
|
|
3
3
|
type AliasMatchMode = "always" | "requires-arg" | "end-or-flag";
|
|
4
4
|
interface HelpEntry {
|
|
5
5
|
usage: string;
|
|
@@ -31,38 +31,6 @@ const commandSpecs = [
|
|
|
31
31
|
return "cogcoin update";
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
|
-
{
|
|
35
|
-
id: "client-unlock",
|
|
36
|
-
handlerFamily: "client-admin",
|
|
37
|
-
supportsYes: false,
|
|
38
|
-
supportsSatvb: false,
|
|
39
|
-
aliases: [{ tokens: ["client", "unlock"] }],
|
|
40
|
-
helpEntries: [
|
|
41
|
-
{
|
|
42
|
-
usage: "client unlock",
|
|
43
|
-
description: "Unlock password-protected local wallet secrets for a limited time",
|
|
44
|
-
},
|
|
45
|
-
],
|
|
46
|
-
describeCommand() {
|
|
47
|
-
return "cogcoin client unlock";
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
id: "client-lock",
|
|
52
|
-
handlerFamily: "client-admin",
|
|
53
|
-
supportsYes: false,
|
|
54
|
-
supportsSatvb: false,
|
|
55
|
-
aliases: [{ tokens: ["client", "lock"] }],
|
|
56
|
-
helpEntries: [
|
|
57
|
-
{
|
|
58
|
-
usage: "client lock",
|
|
59
|
-
description: "Flush the cached client password unlock session",
|
|
60
|
-
},
|
|
61
|
-
],
|
|
62
|
-
describeCommand() {
|
|
63
|
-
return "cogcoin client lock";
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
34
|
{
|
|
67
35
|
id: "client-change-password",
|
|
68
36
|
handlerFamily: "client-admin",
|
|
@@ -308,38 +276,6 @@ const commandSpecs = [
|
|
|
308
276
|
return "cogcoin mine";
|
|
309
277
|
},
|
|
310
278
|
},
|
|
311
|
-
{
|
|
312
|
-
id: "mine-start",
|
|
313
|
-
handlerFamily: "mining-runtime",
|
|
314
|
-
supportsYes: false,
|
|
315
|
-
supportsSatvb: false,
|
|
316
|
-
aliases: [{ tokens: ["mine", "start"] }],
|
|
317
|
-
helpEntries: [
|
|
318
|
-
{
|
|
319
|
-
usage: "mine start",
|
|
320
|
-
description: "Start the miner as a background worker",
|
|
321
|
-
},
|
|
322
|
-
],
|
|
323
|
-
describeCommand() {
|
|
324
|
-
return "cogcoin mine start";
|
|
325
|
-
},
|
|
326
|
-
},
|
|
327
|
-
{
|
|
328
|
-
id: "mine-stop",
|
|
329
|
-
handlerFamily: "mining-runtime",
|
|
330
|
-
supportsYes: false,
|
|
331
|
-
supportsSatvb: false,
|
|
332
|
-
aliases: [{ tokens: ["mine", "stop"] }],
|
|
333
|
-
helpEntries: [
|
|
334
|
-
{
|
|
335
|
-
usage: "mine stop",
|
|
336
|
-
description: "Stop the active background miner",
|
|
337
|
-
},
|
|
338
|
-
],
|
|
339
|
-
describeCommand() {
|
|
340
|
-
return "cogcoin mine stop";
|
|
341
|
-
},
|
|
342
|
-
},
|
|
343
279
|
{
|
|
344
280
|
id: "mine-setup",
|
|
345
281
|
handlerFamily: "mining-admin",
|
|
@@ -949,6 +885,8 @@ const commandSpecs = [
|
|
|
949
885
|
},
|
|
950
886
|
];
|
|
951
887
|
const removedPathSpecs = [
|
|
888
|
+
{ tokens: ["client", "unlock"], errorCode: "cli_client_unlock_removed" },
|
|
889
|
+
{ tokens: ["client", "lock"], errorCode: "cli_client_lock_removed" },
|
|
952
890
|
{ tokens: ["restore"], errorCode: "cli_restore_removed" },
|
|
953
891
|
{ tokens: ["wallet", "delete"], errorCode: "cli_wallet_delete_removed" },
|
|
954
892
|
{ tokens: ["wallet", "restore"], errorCode: "cli_wallet_restore_removed" },
|
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
import { writeLine } from "../io.js";
|
|
2
2
|
import { writeHandledCliError } from "../output.js";
|
|
3
|
-
import { changeClientPassword,
|
|
3
|
+
import { changeClientPassword, } from "../../wallet/state/provider.js";
|
|
4
4
|
function createCommandPrompter(context) {
|
|
5
5
|
return context.createPrompter();
|
|
6
6
|
}
|
|
7
7
|
export async function runClientAdminCommand(parsed, context) {
|
|
8
8
|
try {
|
|
9
|
-
if (parsed.command === "client-lock") {
|
|
10
|
-
await lockClientPassword(context.walletSecretProvider);
|
|
11
|
-
writeLine(context.stdout, "Client locked.");
|
|
12
|
-
return 0;
|
|
13
|
-
}
|
|
14
|
-
if (parsed.command === "client-unlock") {
|
|
15
|
-
const prompter = createCommandPrompter(context);
|
|
16
|
-
const status = await unlockClientPassword(context.walletSecretProvider, prompter);
|
|
17
|
-
writeLine(context.stdout, status.unlockUntilUnixMs === null
|
|
18
|
-
? "Client unlocked."
|
|
19
|
-
: `Client unlocked until ${new Date(status.unlockUntilUnixMs).toISOString()}.`);
|
|
20
|
-
return 0;
|
|
21
|
-
}
|
|
22
9
|
if (parsed.command === "client-change-password") {
|
|
23
10
|
const prompter = createCommandPrompter(context);
|
|
24
|
-
|
|
25
|
-
writeLine(context.stdout,
|
|
26
|
-
? "Client password changed."
|
|
27
|
-
: `Client password changed. Client unlocked until ${new Date(status.unlockUntilUnixMs).toISOString()}.`);
|
|
11
|
+
await changeClientPassword(context.walletSecretProvider, prompter);
|
|
12
|
+
writeLine(context.stdout, "Client password changed.");
|
|
28
13
|
return 0;
|
|
29
14
|
}
|
|
30
15
|
writeLine(context.stderr, `client admin command not implemented: ${parsed.command}`);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { dirname } from "node:path";
|
|
2
2
|
import { DEFAULT_SNAPSHOT_METADATA, resolveBootstrapPathsForTesting } from "../../bitcoind/bootstrap.js";
|
|
3
3
|
import { createEmptyMiningFollowVisualizerState, MiningFollowVisualizer, } from "../../wallet/mining/visualizer.js";
|
|
4
|
+
import { createMiningStopRequestedError } from "../../wallet/mining/stop.js";
|
|
4
5
|
import { resolveWalletRootIdFromLocalArtifacts } from "../../wallet/root-resolution.js";
|
|
5
6
|
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
7
|
+
import { bindClientPasswordPromptSessionPolicy } from "../../wallet/state/client-password/session-policy.js";
|
|
6
8
|
import { ManagedIndexerProgressObserver, assertManagedIndexerStatusRecoverable, isManagedIndexerCaughtUp, pollManagedIndexerUntilCaughtUp, } from "../managed-indexer-observer.js";
|
|
7
9
|
import { usesTtyProgress, writeLine } from "../io.js";
|
|
8
10
|
import { writeHandledCliError } from "../output.js";
|
|
9
|
-
import { formatNextStepLines, getMineStopNextSteps, } from "../workflow-hints.js";
|
|
10
11
|
import { createCloseSignalWatcher, waitForCompletionOrStop } from "../signals.js";
|
|
11
12
|
import { createSyncProgressReporter } from "../sync-progress.js";
|
|
12
13
|
import { PASSIVE_UPDATE_CHECK_TIMEOUT_MS, applyUpdateCheckResult, compareSemver, createEmptyUpdateCheckCache, fetchLatestPublishedVersion, isUpdateCheckDisabled, loadUpdateCheckCache, persistUpdateCheckCache, shouldRefreshUpdateCheck, } from "../update-service.js";
|
|
@@ -317,7 +318,7 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
317
318
|
const packageVersion = await context.readPackageVersion();
|
|
318
319
|
const runtimePaths = context.resolveWalletRuntimePaths();
|
|
319
320
|
if (parsed.command === "mine") {
|
|
320
|
-
const prompter = context.createPrompter();
|
|
321
|
+
const prompter = bindClientPasswordPromptSessionPolicy(context.createPrompter(), "mining-indefinite");
|
|
321
322
|
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, prompter);
|
|
322
323
|
const ttyProgressActive = usesTtyProgress(parsed.progressOutput, context.stderr);
|
|
323
324
|
await ensureMiningProviderSetup({
|
|
@@ -368,7 +369,7 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
368
369
|
: false;
|
|
369
370
|
abortController = new AbortController();
|
|
370
371
|
onStop = () => {
|
|
371
|
-
abortController?.abort();
|
|
372
|
+
abortController?.abort(createMiningStopRequestedError());
|
|
372
373
|
};
|
|
373
374
|
context.signalSource.on("SIGINT", onStop);
|
|
374
375
|
context.signalSource.on("SIGTERM", onStop);
|
|
@@ -397,63 +398,6 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
397
398
|
}
|
|
398
399
|
return 0;
|
|
399
400
|
}
|
|
400
|
-
if (parsed.command === "mine-start") {
|
|
401
|
-
const prompter = createCommandPrompter(context);
|
|
402
|
-
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, prompter);
|
|
403
|
-
await ensureMiningProviderSetup({
|
|
404
|
-
context,
|
|
405
|
-
provider,
|
|
406
|
-
prompter,
|
|
407
|
-
runtimePaths,
|
|
408
|
-
});
|
|
409
|
-
const preflightCode = await syncManagedMiningReadiness({
|
|
410
|
-
parsed,
|
|
411
|
-
context,
|
|
412
|
-
dataDir,
|
|
413
|
-
databasePath: dbPath,
|
|
414
|
-
expectedBinaryVersion: packageVersion,
|
|
415
|
-
provider,
|
|
416
|
-
runtimePaths,
|
|
417
|
-
});
|
|
418
|
-
if (preflightCode !== null) {
|
|
419
|
-
return preflightCode;
|
|
420
|
-
}
|
|
421
|
-
const result = await context.startBackgroundMining({
|
|
422
|
-
dataDir,
|
|
423
|
-
databasePath: dbPath,
|
|
424
|
-
provider,
|
|
425
|
-
prompter,
|
|
426
|
-
builtInSetupEnsured: true,
|
|
427
|
-
paths: runtimePaths,
|
|
428
|
-
});
|
|
429
|
-
if (!result.started) {
|
|
430
|
-
writeLine(context.stdout, "Background mining is already active.");
|
|
431
|
-
if (result.snapshot?.backgroundWorkerPid !== null && result.snapshot?.backgroundWorkerPid !== undefined) {
|
|
432
|
-
writeLine(context.stdout, `Worker pid: ${result.snapshot.backgroundWorkerPid}`);
|
|
433
|
-
}
|
|
434
|
-
return 0;
|
|
435
|
-
}
|
|
436
|
-
writeLine(context.stdout, "Started background mining.");
|
|
437
|
-
if (result.snapshot?.backgroundWorkerPid !== null && result.snapshot?.backgroundWorkerPid !== undefined) {
|
|
438
|
-
writeLine(context.stdout, `Worker pid: ${result.snapshot.backgroundWorkerPid}`);
|
|
439
|
-
}
|
|
440
|
-
return 0;
|
|
441
|
-
}
|
|
442
|
-
if (parsed.command === "mine-stop") {
|
|
443
|
-
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, context.createPrompter());
|
|
444
|
-
const snapshot = await context.stopBackgroundMining({
|
|
445
|
-
dataDir,
|
|
446
|
-
databasePath: dbPath,
|
|
447
|
-
provider,
|
|
448
|
-
paths: runtimePaths,
|
|
449
|
-
});
|
|
450
|
-
const nextSteps = getMineStopNextSteps();
|
|
451
|
-
writeLine(context.stdout, snapshot?.note ?? "Background mining was not active.");
|
|
452
|
-
for (const line of formatNextStepLines(nextSteps)) {
|
|
453
|
-
writeLine(context.stdout, line);
|
|
454
|
-
}
|
|
455
|
-
return 0;
|
|
456
|
-
}
|
|
457
401
|
writeLine(context.stderr, `mining runtime command not implemented: ${parsed.command}`);
|
|
458
402
|
return 1;
|
|
459
403
|
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { writeLine } from "../io.js";
|
|
2
2
|
import { writeHandledCliError } from "../output.js";
|
|
3
3
|
import { loadWelcomeArtText } from "../art.js";
|
|
4
|
-
import { formatNextStepLines, getFundingQuickstartGuidance,
|
|
4
|
+
import { formatNextStepLines, getFundingQuickstartGuidance, getInitUnlockGuidanceLines, getInitNextSteps, } from "../workflow-hints.js";
|
|
5
5
|
import { createOwnedLockCleanupSignalWatcher, waitForCompletionOrStop, } from "../signals.js";
|
|
6
6
|
import { runSyncCommand } from "./sync.js";
|
|
7
|
-
import { CLIENT_PASSWORD_SETUP_AUTO_UNLOCK_SECONDS } from "../../wallet/state/client-password.js";
|
|
8
7
|
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
9
8
|
function createCommandPrompter(context) {
|
|
10
9
|
return context.createPrompter();
|
|
11
10
|
}
|
|
12
11
|
function getRepairWarnings(result) {
|
|
13
|
-
return result.miningResumeAction === "
|
|
14
|
-
? [
|
|
12
|
+
return result.miningResumeAction === "skipped-background-mode-removed"
|
|
13
|
+
? ["Background mining no longer resumes automatically after repair. Run `cogcoin mine` if you want mining resumed."]
|
|
15
14
|
: [];
|
|
16
15
|
}
|
|
17
16
|
function getResetWarnings(result) {
|
|
@@ -20,7 +19,7 @@ function getResetWarnings(result) {
|
|
|
20
19
|
: [];
|
|
21
20
|
}
|
|
22
21
|
function writeSetupUnlockGuidance(stdout) {
|
|
23
|
-
for (const line of
|
|
22
|
+
for (const line of getInitUnlockGuidanceLines()) {
|
|
24
23
|
writeLine(stdout, line);
|
|
25
24
|
}
|
|
26
25
|
}
|
|
@@ -100,7 +99,8 @@ function formatResetResultText(result) {
|
|
|
100
99
|
function isRepairMiningResumeActionOk(action) {
|
|
101
100
|
return action === "none"
|
|
102
101
|
|| action === "skipped-not-resumable"
|
|
103
|
-
|| action === "
|
|
102
|
+
|| action === "skipped-post-repair-blocked"
|
|
103
|
+
|| action === "skipped-background-mode-removed";
|
|
104
104
|
}
|
|
105
105
|
function buildRepairWarningEntries(result) {
|
|
106
106
|
const entries = [];
|
package/dist/cli/context.js
CHANGED
|
@@ -13,7 +13,7 @@ import { initializeWallet, previewResetWallet, repairWallet, resetWallet, showWa
|
|
|
13
13
|
import { resolveWalletRuntimePathsForTesting } from "../wallet/runtime.js";
|
|
14
14
|
import { openWalletReadContext } from "../wallet/read/index.js";
|
|
15
15
|
import { loadRawWalletStateEnvelope, loadWalletState } from "../wallet/state/storage.js";
|
|
16
|
-
import { ensureBuiltInMiningSetupIfNeeded, followMiningLog, inspectMiningControlPlane, inspectMiningDomainPromptState, readMiningLog, runForegroundMining, setupBuiltInMining,
|
|
16
|
+
import { ensureBuiltInMiningSetupIfNeeded, followMiningLog, inspectMiningControlPlane, inspectMiningDomainPromptState, readMiningLog, runForegroundMining, setupBuiltInMining, updateMiningDomainPrompt, } from "../wallet/mining/index.js";
|
|
17
17
|
import { createLazyDefaultWalletSecretProvider } from "../wallet/state/provider.js";
|
|
18
18
|
import { anchorDomain, transferBitcoin, buyDomain, claimCogLock, clearDomainDelegate, clearDomainEndpoint, clearDomainMiner, clearField, createField, giveReputation, lockCogToDomain, registerDomain, reclaimCogLock, revokeReputation, sendCog, setField, setDomainCanonical, setDomainDelegate, setDomainEndpoint, setDomainMiner, sellDomain, transferDomain, } from "../wallet/tx/index.js";
|
|
19
19
|
import { createTerminalPrompter } from "./prompt.js";
|
|
@@ -93,8 +93,6 @@ export function createDefaultContext(overrides = {}) {
|
|
|
93
93
|
inspectMiningDomainPromptState: overrides.inspectMiningDomainPromptState ?? inspectMiningDomainPromptState,
|
|
94
94
|
ensureBuiltInMiningSetupIfNeeded: overrides.ensureBuiltInMiningSetupIfNeeded ?? ensureBuiltInMiningSetupIfNeeded,
|
|
95
95
|
runForegroundMining: overrides.runForegroundMining ?? runForegroundMining,
|
|
96
|
-
startBackgroundMining: overrides.startBackgroundMining ?? startBackgroundMining,
|
|
97
|
-
stopBackgroundMining: overrides.stopBackgroundMining ?? stopBackgroundMining,
|
|
98
96
|
setupBuiltInMining: overrides.setupBuiltInMining ?? setupBuiltInMining,
|
|
99
97
|
updateMiningDomainPrompt: overrides.updateMiningDomainPrompt ?? updateMiningDomainPrompt,
|
|
100
98
|
readMiningLog: overrides.readMiningLog ?? readMiningLog,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MiningControlPlaneView, MiningDomainPromptMutationResult
|
|
1
|
+
import type { MiningControlPlaneView, MiningDomainPromptMutationResult } from "../wallet/mining/index.js";
|
|
2
2
|
export declare function buildMineSetupData(view: MiningControlPlaneView): {
|
|
3
3
|
resultType: "state-change";
|
|
4
4
|
stateChange: {
|
|
@@ -8,27 +8,6 @@ export declare function buildMineSetupData(view: MiningControlPlaneView): {
|
|
|
8
8
|
};
|
|
9
9
|
state: Record<string, unknown>;
|
|
10
10
|
};
|
|
11
|
-
export declare function buildMineStartData(result: {
|
|
12
|
-
started: boolean;
|
|
13
|
-
snapshot: MiningRuntimeStatusV1 | null;
|
|
14
|
-
}): {
|
|
15
|
-
resultType: "state-change";
|
|
16
|
-
stateChange: {
|
|
17
|
-
kind: string;
|
|
18
|
-
before: Record<string, unknown> | null;
|
|
19
|
-
after: Record<string, unknown> | null;
|
|
20
|
-
};
|
|
21
|
-
state: Record<string, unknown>;
|
|
22
|
-
};
|
|
23
|
-
export declare function buildMineStopData(snapshot: MiningRuntimeStatusV1 | null): {
|
|
24
|
-
resultType: "state-change";
|
|
25
|
-
stateChange: {
|
|
26
|
-
kind: string;
|
|
27
|
-
before: Record<string, unknown> | null;
|
|
28
|
-
after: Record<string, unknown> | null;
|
|
29
|
-
};
|
|
30
|
-
state: Record<string, unknown>;
|
|
31
|
-
};
|
|
32
11
|
export declare function buildMinePromptData(result: MiningDomainPromptMutationResult): {
|
|
33
12
|
domain: {
|
|
34
13
|
name: string;
|
package/dist/cli/mining-json.js
CHANGED
|
@@ -35,29 +35,6 @@ export function buildMineSetupData(view) {
|
|
|
35
35
|
after,
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
export function buildMineStartData(result) {
|
|
39
|
-
const after = {
|
|
40
|
-
started: result.started,
|
|
41
|
-
runtime: summarizeRuntime(result.snapshot),
|
|
42
|
-
};
|
|
43
|
-
return buildStateChangeData({
|
|
44
|
-
kind: "mine-start",
|
|
45
|
-
state: after,
|
|
46
|
-
after,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
export function buildMineStopData(snapshot) {
|
|
50
|
-
const after = {
|
|
51
|
-
stopped: snapshot !== null,
|
|
52
|
-
runtime: summarizeRuntime(snapshot),
|
|
53
|
-
note: snapshot?.note ?? "Background mining was not active.",
|
|
54
|
-
};
|
|
55
|
-
return buildStateChangeData({
|
|
56
|
-
kind: "mine-stop",
|
|
57
|
-
state: after,
|
|
58
|
-
after,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
38
|
export function buildMinePromptData(result) {
|
|
62
39
|
return {
|
|
63
40
|
domain: result.domain,
|
package/dist/cli/output.js
CHANGED
|
@@ -330,8 +330,8 @@ export function createCliErrorPresentation(errorCode, fallbackMessage, error) {
|
|
|
330
330
|
if (errorCode === "wallet_client_password_locked") {
|
|
331
331
|
return {
|
|
332
332
|
what: "Client password is locked.",
|
|
333
|
-
why: "This command needs the password-protected local wallet secret, but
|
|
334
|
-
next: "
|
|
333
|
+
why: "This command needs the password-protected local wallet secret, but this process does not currently hold an unlocked client-password session.",
|
|
334
|
+
next: "Rerun the command in an interactive terminal so Cogcoin can prompt for the client password. Separate CLI invocations no longer share unlocked state.",
|
|
335
335
|
};
|
|
336
336
|
}
|
|
337
337
|
if (errorCode === "wallet_client_password_change_requires_tty") {
|
|
@@ -341,6 +341,20 @@ export function createCliErrorPresentation(errorCode, fallbackMessage, error) {
|
|
|
341
341
|
next: "Run `cogcoin client change-password` in an interactive terminal.",
|
|
342
342
|
};
|
|
343
343
|
}
|
|
344
|
+
if (errorCode === "cli_client_unlock_removed") {
|
|
345
|
+
return {
|
|
346
|
+
what: "`client unlock` was removed.",
|
|
347
|
+
why: "Cogcoin no longer shares unlocked client-password sessions across separate CLI commands.",
|
|
348
|
+
next: "Rerun password-aware commands in an interactive terminal so Cogcoin can prompt for the client password when needed.",
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
if (errorCode === "cli_client_lock_removed") {
|
|
352
|
+
return {
|
|
353
|
+
what: "`client lock` was removed.",
|
|
354
|
+
why: "Cogcoin no longer keeps reusable unlocked client-password sessions after a command exits.",
|
|
355
|
+
next: "Fresh CLI invocations start locked automatically and prompt when wallet-local secrets are needed.",
|
|
356
|
+
};
|
|
357
|
+
}
|
|
344
358
|
if (errorCode === "cli_restore_removed" || errorCode === "cli_wallet_restore_removed") {
|
|
345
359
|
return {
|
|
346
360
|
what: "Standalone restore commands were removed.",
|
package/dist/cli/parse.js
CHANGED
|
@@ -282,8 +282,6 @@ export function parseCliArgs(argv) {
|
|
|
282
282
|
|| command === "sync"
|
|
283
283
|
|| command === "follow"
|
|
284
284
|
|| command === "mine"
|
|
285
|
-
|| command === "mine-start"
|
|
286
|
-
|| command === "mine-stop"
|
|
287
285
|
|| command === "mine-setup"
|
|
288
286
|
|| command === "mine-prompt-list"
|
|
289
287
|
|| command === "mine-status"
|