@cogcoin/client 0.5.15 → 1.0.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/README.md +80 -25
- package/dist/app-paths.d.ts +5 -6
- package/dist/app-paths.js +8 -16
- package/dist/art/balance.txt +10 -0
- package/dist/art/welcome.txt +16 -0
- package/dist/bitcoind/bootstrap/controller.d.ts +1 -0
- package/dist/bitcoind/bootstrap/controller.js +53 -1
- package/dist/bitcoind/client/follow-block-times.d.ts +1 -0
- package/dist/bitcoind/client/follow-block-times.js +1 -1
- package/dist/bitcoind/client/internal-types.d.ts +7 -3
- package/dist/bitcoind/client/managed-client.d.ts +4 -2
- package/dist/bitcoind/client/managed-client.js +14 -0
- package/dist/bitcoind/client/sync-engine.js +72 -11
- package/dist/bitcoind/hash-order.d.ts +4 -0
- package/dist/bitcoind/hash-order.js +13 -0
- package/dist/bitcoind/indexer-daemon-main.js +11 -3
- package/dist/bitcoind/normalize.js +3 -2
- package/dist/bitcoind/processing-start-height.d.ts +5 -0
- package/dist/bitcoind/processing-start-height.js +7 -0
- package/dist/bitcoind/progress/constants.d.ts +4 -0
- package/dist/bitcoind/progress/constants.js +4 -0
- package/dist/bitcoind/progress/controller.d.ts +2 -1
- package/dist/bitcoind/progress/controller.js +3 -3
- package/dist/bitcoind/progress/follow-scene.d.ts +6 -2
- package/dist/bitcoind/progress/follow-scene.js +29 -6
- package/dist/bitcoind/progress/formatting.d.ts +1 -0
- package/dist/bitcoind/progress/formatting.js +6 -0
- package/dist/bitcoind/progress/train-scene.js +37 -18
- package/dist/bitcoind/progress/tty-renderer.d.ts +6 -1
- package/dist/bitcoind/progress/tty-renderer.js +8 -4
- package/dist/bitcoind/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +3 -0
- package/dist/bitcoind/types.d.ts +6 -0
- package/dist/bytes.d.ts +1 -0
- package/dist/bytes.js +3 -0
- package/dist/cli/art.d.ts +2 -0
- package/dist/cli/art.js +37 -0
- package/dist/cli/commands/client-admin.d.ts +2 -0
- package/dist/cli/commands/client-admin.js +91 -0
- package/dist/cli/commands/follow.js +0 -2
- package/dist/cli/commands/mining-admin.js +6 -47
- package/dist/cli/commands/mining-read.js +11 -50
- package/dist/cli/commands/mining-runtime.js +142 -5
- package/dist/cli/commands/service-runtime.js +0 -2
- package/dist/cli/commands/status.js +8 -2
- package/dist/cli/commands/sync.js +49 -92
- package/dist/cli/commands/wallet-admin.js +142 -136
- package/dist/cli/commands/wallet-mutation.js +91 -79
- package/dist/cli/commands/wallet-read.js +15 -18
- package/dist/cli/context.js +5 -14
- package/dist/cli/mining-format.d.ts +0 -1
- package/dist/cli/mining-format.js +5 -37
- package/dist/cli/mining-json.d.ts +0 -18
- package/dist/cli/mining-json.js +0 -35
- package/dist/cli/mutation-command-groups.d.ts +1 -2
- package/dist/cli/mutation-command-groups.js +0 -5
- package/dist/cli/mutation-json.d.ts +24 -145
- package/dist/cli/mutation-json.js +30 -136
- package/dist/cli/mutation-resolved-json.d.ts +0 -7
- package/dist/cli/mutation-resolved-json.js +4 -10
- package/dist/cli/mutation-success.d.ts +2 -0
- package/dist/cli/mutation-success.js +11 -1
- package/dist/cli/mutation-text-format.js +1 -3
- package/dist/cli/output.d.ts +1 -1
- package/dist/cli/output.js +254 -231
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +93 -122
- package/dist/cli/preview-json.d.ts +17 -120
- package/dist/cli/preview-json.js +14 -97
- package/dist/cli/prompt.js +8 -13
- package/dist/cli/read-json.d.ts +15 -37
- package/dist/cli/read-json.js +44 -140
- package/dist/cli/runner.js +10 -13
- package/dist/cli/sync-progress.d.ts +6 -0
- package/dist/cli/sync-progress.js +91 -0
- package/dist/cli/types.d.ts +9 -17
- package/dist/cli/types.js +0 -2
- package/dist/cli/wallet-format.d.ts +1 -0
- package/dist/cli/wallet-format.js +208 -144
- package/dist/cli/workflow-hints.d.ts +3 -3
- package/dist/cli/workflow-hints.js +11 -8
- package/dist/client/default-client.d.ts +3 -1
- package/dist/client/default-client.js +45 -2
- package/dist/client/factory.js +1 -1
- package/dist/client/initialization.js +23 -0
- package/dist/client/persistence.js +5 -5
- package/dist/client/store-adapter.js +1 -0
- package/dist/sqlite/checkpoints.d.ts +1 -0
- package/dist/sqlite/checkpoints.js +7 -0
- package/dist/sqlite/store.js +14 -1
- package/dist/types.d.ts +1 -0
- package/dist/wallet/coin-control.d.ts +41 -12
- package/dist/wallet/coin-control.js +100 -428
- package/dist/wallet/descriptor-normalization.d.ts +1 -3
- package/dist/wallet/descriptor-normalization.js +0 -16
- package/dist/wallet/lifecycle.d.ts +7 -99
- package/dist/wallet/lifecycle.js +513 -968
- package/dist/wallet/managed-core-wallet.d.ts +13 -0
- package/dist/wallet/managed-core-wallet.js +20 -0
- package/dist/wallet/mining/constants.d.ts +5 -12
- package/dist/wallet/mining/constants.js +5 -12
- package/dist/wallet/mining/control.d.ts +1 -13
- package/dist/wallet/mining/control.js +45 -349
- package/dist/wallet/mining/index.d.ts +4 -5
- package/dist/wallet/mining/index.js +2 -3
- package/dist/wallet/mining/runner.d.ts +123 -13
- package/dist/wallet/mining/runner.js +899 -511
- package/dist/wallet/mining/runtime-artifacts.js +23 -3
- package/dist/wallet/mining/sentence-protocol.d.ts +44 -0
- package/dist/wallet/mining/sentence-protocol.js +123 -0
- package/dist/wallet/mining/sentences.d.ts +4 -8
- package/dist/wallet/mining/sentences.js +3 -52
- package/dist/wallet/mining/state.d.ts +11 -6
- package/dist/wallet/mining/state.js +7 -6
- package/dist/wallet/mining/types.d.ts +2 -30
- package/dist/wallet/mining/visualizer.d.ts +31 -3
- package/dist/wallet/mining/visualizer.js +135 -13
- package/dist/wallet/read/context.d.ts +0 -2
- package/dist/wallet/read/context.js +119 -140
- package/dist/wallet/read/filter.js +2 -11
- package/dist/wallet/read/index.d.ts +1 -1
- package/dist/wallet/read/project.js +24 -77
- package/dist/wallet/read/types.d.ts +10 -25
- package/dist/wallet/reset.d.ts +0 -1
- package/dist/wallet/reset.js +60 -138
- package/dist/wallet/root-resolution.d.ts +1 -5
- package/dist/wallet/root-resolution.js +0 -18
- package/dist/wallet/runtime.d.ts +0 -6
- package/dist/wallet/runtime.js +0 -8
- package/dist/wallet/state/client-password-agent.js +208 -0
- package/dist/wallet/state/client-password.d.ts +65 -0
- package/dist/wallet/state/client-password.js +952 -0
- package/dist/wallet/state/crypto.d.ts +1 -20
- package/dist/wallet/state/crypto.js +0 -63
- package/dist/wallet/state/provider.d.ts +23 -11
- package/dist/wallet/state/provider.js +248 -290
- package/dist/wallet/state/storage.d.ts +2 -2
- package/dist/wallet/state/storage.js +48 -16
- package/dist/wallet/tx/anchor.d.ts +3 -28
- package/dist/wallet/tx/anchor.js +349 -1250
- package/dist/wallet/tx/bitcoin-transfer.d.ts +35 -0
- package/dist/wallet/tx/bitcoin-transfer.js +200 -0
- package/dist/wallet/tx/cog.d.ts +5 -1
- package/dist/wallet/tx/cog.js +149 -185
- package/dist/wallet/tx/common.d.ts +61 -8
- package/dist/wallet/tx/common.js +266 -146
- package/dist/wallet/tx/domain-admin.d.ts +3 -1
- package/dist/wallet/tx/domain-admin.js +61 -99
- package/dist/wallet/tx/domain-market.d.ts +5 -1
- package/dist/wallet/tx/domain-market.js +221 -228
- package/dist/wallet/tx/field.d.ts +4 -10
- package/dist/wallet/tx/field.js +83 -924
- package/dist/wallet/tx/identity-selector.d.ts +9 -3
- package/dist/wallet/tx/identity-selector.js +17 -35
- package/dist/wallet/tx/index.d.ts +3 -1
- package/dist/wallet/tx/index.js +2 -1
- package/dist/wallet/tx/register.d.ts +3 -1
- package/dist/wallet/tx/register.js +62 -220
- package/dist/wallet/tx/reputation.d.ts +3 -1
- package/dist/wallet/tx/reputation.js +58 -95
- package/dist/wallet/types.d.ts +8 -122
- package/package.json +5 -5
- package/dist/wallet/archive.d.ts +0 -4
- package/dist/wallet/archive.js +0 -41
- package/dist/wallet/mining/hook-protocol.d.ts +0 -47
- package/dist/wallet/mining/hook-protocol.js +0 -161
- package/dist/wallet/mining/hook-runner.js +0 -52
- package/dist/wallet/mining/hooks.d.ts +0 -38
- package/dist/wallet/mining/hooks.js +0 -520
- package/dist/wallet/state/explicit-lock.d.ts +0 -4
- package/dist/wallet/state/explicit-lock.js +0 -19
- package/dist/wallet/state/session.d.ts +0 -12
- package/dist/wallet/state/session.js +0 -23
- /package/dist/wallet/{mining/hook-runner.d.ts → state/client-password-agent.d.ts} +0 -0
package/dist/bytes.js
CHANGED
|
@@ -9,6 +9,9 @@ export function hexToBytes(hex) {
|
|
|
9
9
|
export function cloneBytes(bytes) {
|
|
10
10
|
return new Uint8Array(bytes);
|
|
11
11
|
}
|
|
12
|
+
export function reverseBytes(bytes) {
|
|
13
|
+
return Uint8Array.from([...bytes].reverse());
|
|
14
|
+
}
|
|
12
15
|
export function encodeText(value) {
|
|
13
16
|
return textEncoder.encode(value);
|
|
14
17
|
}
|
package/dist/cli/art.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
let welcomeArtCache = null;
|
|
3
|
+
let balanceArtCache = null;
|
|
4
|
+
const FIXED_ART_WIDTH = 80;
|
|
5
|
+
const BALANCE_ART_HEIGHT = 10;
|
|
6
|
+
function normalizeFixedArtText(raw, options) {
|
|
7
|
+
const lines = raw.replaceAll("\r\n", "\n").split("\n");
|
|
8
|
+
if (lines[lines.length - 1] === "") {
|
|
9
|
+
lines.pop();
|
|
10
|
+
}
|
|
11
|
+
if (lines.length !== options.height) {
|
|
12
|
+
throw new Error(`${options.name}_art_height_invalid_${lines.length}`);
|
|
13
|
+
}
|
|
14
|
+
for (const line of lines) {
|
|
15
|
+
if (line.length !== FIXED_ART_WIDTH) {
|
|
16
|
+
throw new Error(`${options.name}_art_width_invalid_${line.length}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return lines.join("\n");
|
|
20
|
+
}
|
|
21
|
+
export function loadWelcomeArtText() {
|
|
22
|
+
if (welcomeArtCache !== null) {
|
|
23
|
+
return welcomeArtCache;
|
|
24
|
+
}
|
|
25
|
+
welcomeArtCache = readFileSync(new URL("../art/welcome.txt", import.meta.url), "utf8");
|
|
26
|
+
return welcomeArtCache;
|
|
27
|
+
}
|
|
28
|
+
export function loadBalanceArtText() {
|
|
29
|
+
if (balanceArtCache !== null) {
|
|
30
|
+
return balanceArtCache;
|
|
31
|
+
}
|
|
32
|
+
balanceArtCache = normalizeFixedArtText(readFileSync(new URL("../art/balance.txt", import.meta.url), "utf8"), {
|
|
33
|
+
name: "balance",
|
|
34
|
+
height: BALANCE_ART_HEIGHT,
|
|
35
|
+
});
|
|
36
|
+
return balanceArtCache;
|
|
37
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { writeLine } from "../io.js";
|
|
2
|
+
import { createTerminalPrompter } from "../prompt.js";
|
|
3
|
+
import { createMutationSuccessEnvelope, describeCanonicalCommand, resolveStableMutationJsonSchema, writeHandledCliError, writeJsonValue, } from "../output.js";
|
|
4
|
+
import { changeClientPassword, lockClientPassword, unlockClientPassword, } from "../../wallet/state/provider.js";
|
|
5
|
+
function createCommandPrompter(parsed, context) {
|
|
6
|
+
return parsed.outputMode !== "text"
|
|
7
|
+
? createTerminalPrompter(context.stdin, context.stderr)
|
|
8
|
+
: context.createPrompter();
|
|
9
|
+
}
|
|
10
|
+
export async function runClientAdminCommand(parsed, context) {
|
|
11
|
+
try {
|
|
12
|
+
if (parsed.command === "client-lock") {
|
|
13
|
+
const status = await lockClientPassword(context.walletSecretProvider);
|
|
14
|
+
if (parsed.outputMode === "json") {
|
|
15
|
+
writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "locked", {
|
|
16
|
+
resultType: "operation",
|
|
17
|
+
operation: {
|
|
18
|
+
kind: "client-lock",
|
|
19
|
+
locked: true,
|
|
20
|
+
unlockUntilUnixMs: status.unlockUntilUnixMs,
|
|
21
|
+
},
|
|
22
|
+
state: {
|
|
23
|
+
locked: true,
|
|
24
|
+
unlockUntilUnixMs: status.unlockUntilUnixMs,
|
|
25
|
+
},
|
|
26
|
+
}));
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
writeLine(context.stdout, "Client locked.");
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
if (parsed.command === "client-unlock") {
|
|
33
|
+
const prompter = createCommandPrompter(parsed, context);
|
|
34
|
+
const status = await unlockClientPassword(context.walletSecretProvider, prompter);
|
|
35
|
+
if (parsed.outputMode === "json") {
|
|
36
|
+
writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "unlocked", {
|
|
37
|
+
resultType: "operation",
|
|
38
|
+
operation: {
|
|
39
|
+
kind: "client-unlock",
|
|
40
|
+
unlocked: status.unlocked,
|
|
41
|
+
unlockUntilUnixMs: status.unlockUntilUnixMs,
|
|
42
|
+
},
|
|
43
|
+
state: {
|
|
44
|
+
unlocked: status.unlocked,
|
|
45
|
+
unlockUntilUnixMs: status.unlockUntilUnixMs,
|
|
46
|
+
},
|
|
47
|
+
}));
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
writeLine(context.stdout, status.unlockUntilUnixMs === null
|
|
51
|
+
? "Client unlocked."
|
|
52
|
+
: `Client unlocked until ${new Date(status.unlockUntilUnixMs).toISOString()}.`);
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
if (parsed.command === "client-change-password") {
|
|
56
|
+
const prompter = createCommandPrompter(parsed, context);
|
|
57
|
+
const status = await changeClientPassword(context.walletSecretProvider, prompter);
|
|
58
|
+
if (parsed.outputMode === "json") {
|
|
59
|
+
writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMutationJsonSchema(parsed), describeCanonicalCommand(parsed), "changed", {
|
|
60
|
+
resultType: "operation",
|
|
61
|
+
operation: {
|
|
62
|
+
kind: "client-change-password",
|
|
63
|
+
changed: true,
|
|
64
|
+
unlocked: status.unlocked,
|
|
65
|
+
unlockUntilUnixMs: status.unlockUntilUnixMs,
|
|
66
|
+
},
|
|
67
|
+
state: {
|
|
68
|
+
changed: true,
|
|
69
|
+
unlocked: status.unlocked,
|
|
70
|
+
unlockUntilUnixMs: status.unlockUntilUnixMs,
|
|
71
|
+
},
|
|
72
|
+
}));
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
writeLine(context.stdout, status.unlockUntilUnixMs === null
|
|
76
|
+
? "Client password changed."
|
|
77
|
+
: `Client password changed. Client unlocked until ${new Date(status.unlockUntilUnixMs).toISOString()}.`);
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
80
|
+
writeLine(context.stderr, `client admin command not implemented: ${parsed.command}`);
|
|
81
|
+
return 1;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return writeHandledCliError({
|
|
85
|
+
parsed,
|
|
86
|
+
stdout: context.stdout,
|
|
87
|
+
stderr: context.stderr,
|
|
88
|
+
error,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -16,8 +16,6 @@ export async function runFollowCommand(parsed, context) {
|
|
|
16
16
|
paths: runtimePaths,
|
|
17
17
|
provider: context.walletSecretProvider,
|
|
18
18
|
loadRawWalletStateEnvelope: context.loadRawWalletStateEnvelope,
|
|
19
|
-
loadUnlockSession: context.loadUnlockSession,
|
|
20
|
-
loadWalletExplicitLock: context.loadWalletExplicitLock,
|
|
21
19
|
});
|
|
22
20
|
try {
|
|
23
21
|
controlLock = await acquireFileLock(runtimePaths.walletControlLockPath, {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { buildMineSetupData, } from "../mining-json.js";
|
|
2
|
+
import { buildMineSetupPreviewData } from "../preview-json.js";
|
|
3
3
|
import { writeLine } from "../io.js";
|
|
4
4
|
import { createTerminalPrompter } from "../prompt.js";
|
|
5
5
|
import { createPreviewSuccessEnvelope, createMutationSuccessEnvelope, describeCanonicalCommand, resolvePreviewJsonSchema, resolveStableMiningControlJsonSchema, writeHandledCliError, writeJsonValue, } from "../output.js";
|
|
6
|
-
import { formatNextStepLines,
|
|
6
|
+
import { formatNextStepLines, getMineSetupNextSteps, } from "../workflow-hints.js";
|
|
7
|
+
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
7
8
|
function createCommandPrompter(parsed, context) {
|
|
8
9
|
return parsed.outputMode !== "text"
|
|
9
10
|
? createTerminalPrompter(context.stdin, context.stderr)
|
|
@@ -11,52 +12,10 @@ function createCommandPrompter(parsed, context) {
|
|
|
11
12
|
}
|
|
12
13
|
export async function runMiningAdminCommand(parsed, context) {
|
|
13
14
|
try {
|
|
14
|
-
const provider = context.walletSecretProvider;
|
|
15
15
|
const runtimePaths = context.resolveWalletRuntimePaths(parsed.seedName);
|
|
16
|
-
if (parsed.command === "hooks-mining-enable") {
|
|
17
|
-
const prompter = createCommandPrompter(parsed, context);
|
|
18
|
-
const view = await context.enableMiningHooks({
|
|
19
|
-
provider,
|
|
20
|
-
prompter,
|
|
21
|
-
paths: runtimePaths,
|
|
22
|
-
});
|
|
23
|
-
const nextSteps = getHooksEnableMiningNextSteps();
|
|
24
|
-
if (parsed.outputMode === "preview-json") {
|
|
25
|
-
writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "enabled", buildHooksPreviewData("hooks-enable-mining", view), {
|
|
26
|
-
nextSteps,
|
|
27
|
-
}));
|
|
28
|
-
return 0;
|
|
29
|
-
}
|
|
30
|
-
if (parsed.outputMode === "json") {
|
|
31
|
-
writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMiningControlJsonSchema(parsed), "cogcoin hooks enable mining", "enabled", buildHooksEnableMiningData(view), {
|
|
32
|
-
nextSteps,
|
|
33
|
-
}));
|
|
34
|
-
return 0;
|
|
35
|
-
}
|
|
36
|
-
writeLine(context.stdout, "Custom mining hook enabled.");
|
|
37
|
-
for (const line of formatNextStepLines(nextSteps)) {
|
|
38
|
-
writeLine(context.stdout, line);
|
|
39
|
-
}
|
|
40
|
-
return 0;
|
|
41
|
-
}
|
|
42
|
-
if (parsed.command === "hooks-mining-disable") {
|
|
43
|
-
const view = await context.disableMiningHooks({
|
|
44
|
-
provider,
|
|
45
|
-
paths: runtimePaths,
|
|
46
|
-
});
|
|
47
|
-
if (parsed.outputMode === "preview-json") {
|
|
48
|
-
writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "disabled", buildHooksPreviewData("hooks-disable-mining", view)));
|
|
49
|
-
return 0;
|
|
50
|
-
}
|
|
51
|
-
if (parsed.outputMode === "json") {
|
|
52
|
-
writeJsonValue(context.stdout, createMutationSuccessEnvelope(resolveStableMiningControlJsonSchema(parsed), "cogcoin hooks disable mining", "disabled", buildHooksDisableMiningData(view)));
|
|
53
|
-
return 0;
|
|
54
|
-
}
|
|
55
|
-
writeLine(context.stdout, "Mining hooks switched back to builtin mode.");
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
58
16
|
if (parsed.command === "mine-setup") {
|
|
59
17
|
const prompter = createCommandPrompter(parsed, context);
|
|
18
|
+
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, prompter);
|
|
60
19
|
const view = await context.setupBuiltInMining({
|
|
61
20
|
provider,
|
|
62
21
|
prompter,
|
|
@@ -64,7 +23,7 @@ export async function runMiningAdminCommand(parsed, context) {
|
|
|
64
23
|
});
|
|
65
24
|
const nextSteps = getMineSetupNextSteps();
|
|
66
25
|
if (parsed.outputMode === "preview-json") {
|
|
67
|
-
writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "configured",
|
|
26
|
+
writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "configured", buildMineSetupPreviewData(view), {
|
|
68
27
|
nextSteps,
|
|
69
28
|
}));
|
|
70
29
|
return 0;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { dirname } from "node:path";
|
|
2
2
|
import { stat } from "node:fs/promises";
|
|
3
|
-
import {
|
|
3
|
+
import { formatMineStatusReport, formatMiningEventRecord } from "../mining-format.js";
|
|
4
4
|
import { writeLine } from "../io.js";
|
|
5
|
-
import { inspectWalletLocalState } from "../../wallet/read/index.js";
|
|
6
5
|
import { createErrorEnvelope, createSuccessEnvelope, describeCanonicalCommand, normalizeListPage, writeJsonValue, } from "../output.js";
|
|
7
|
-
import {
|
|
6
|
+
import { buildMineLogJson, buildMineStatusJson } from "../read-json.js";
|
|
7
|
+
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
8
8
|
async function readRotationIndices(paths) {
|
|
9
9
|
const rotation = [];
|
|
10
10
|
for (let index = 1; index <= 4; index += 1) {
|
|
@@ -26,46 +26,6 @@ export async function runMiningReadCommand(parsed, context) {
|
|
|
26
26
|
const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
|
|
27
27
|
const runtimePaths = context.resolveWalletRuntimePaths(parsed.seedName);
|
|
28
28
|
await context.ensureDirectory(dirname(dbPath));
|
|
29
|
-
if (parsed.command === "hooks-mining-status") {
|
|
30
|
-
const localState = await inspectWalletLocalState({
|
|
31
|
-
secretProvider: context.walletSecretProvider,
|
|
32
|
-
paths: runtimePaths,
|
|
33
|
-
});
|
|
34
|
-
const view = await context.inspectMiningControlPlane({
|
|
35
|
-
provider: context.walletSecretProvider,
|
|
36
|
-
localState,
|
|
37
|
-
bitcoind: {
|
|
38
|
-
health: "unavailable",
|
|
39
|
-
status: null,
|
|
40
|
-
message: "Managed bitcoind status unavailable during hook inspection.",
|
|
41
|
-
},
|
|
42
|
-
nodeStatus: null,
|
|
43
|
-
nodeHealth: "unavailable",
|
|
44
|
-
indexer: {
|
|
45
|
-
health: "unavailable",
|
|
46
|
-
status: null,
|
|
47
|
-
message: null,
|
|
48
|
-
snapshotTip: null,
|
|
49
|
-
source: "none",
|
|
50
|
-
daemonInstanceId: null,
|
|
51
|
-
snapshotSeq: null,
|
|
52
|
-
openedAtUnixMs: null,
|
|
53
|
-
},
|
|
54
|
-
verify: parsed.verify,
|
|
55
|
-
paths: runtimePaths,
|
|
56
|
-
});
|
|
57
|
-
if (parsed.outputMode === "json") {
|
|
58
|
-
const result = buildHooksStatusJson(view);
|
|
59
|
-
writeJsonValue(context.stdout, createSuccessEnvelope("cogcoin/hooks-status/v1", describeCanonicalCommand(parsed), result.data, {
|
|
60
|
-
warnings: result.warnings,
|
|
61
|
-
explanations: result.explanations,
|
|
62
|
-
nextSteps: result.nextSteps,
|
|
63
|
-
}));
|
|
64
|
-
return 0;
|
|
65
|
-
}
|
|
66
|
-
writeLine(context.stdout, formatHooksStatusReport(view));
|
|
67
|
-
return 0;
|
|
68
|
-
}
|
|
69
29
|
if (parsed.command === "mine-log") {
|
|
70
30
|
if (!parsed.follow) {
|
|
71
31
|
const allEvents = await context.readMiningLog({
|
|
@@ -128,15 +88,18 @@ export async function runMiningReadCommand(parsed, context) {
|
|
|
128
88
|
}
|
|
129
89
|
return 0;
|
|
130
90
|
}
|
|
91
|
+
const provider = parsed.outputMode === "text"
|
|
92
|
+
? withInteractiveWalletSecretProvider(context.walletSecretProvider, context.createPrompter())
|
|
93
|
+
: context.walletSecretProvider;
|
|
131
94
|
const readContext = await context.openWalletReadContext({
|
|
132
95
|
dataDir,
|
|
133
96
|
databasePath: dbPath,
|
|
134
|
-
secretProvider:
|
|
97
|
+
secretProvider: provider,
|
|
135
98
|
paths: runtimePaths,
|
|
136
99
|
});
|
|
137
100
|
try {
|
|
138
101
|
const mining = readContext.mining ?? await context.inspectMiningControlPlane({
|
|
139
|
-
provider
|
|
102
|
+
provider,
|
|
140
103
|
localState: readContext.localState,
|
|
141
104
|
bitcoind: readContext.bitcoind,
|
|
142
105
|
nodeStatus: readContext.nodeStatus,
|
|
@@ -163,11 +126,9 @@ export async function runMiningReadCommand(parsed, context) {
|
|
|
163
126
|
catch (error) {
|
|
164
127
|
const message = error instanceof Error ? error.message : String(error);
|
|
165
128
|
if (parsed.outputMode === "json") {
|
|
166
|
-
writeJsonValue(context.stdout, createErrorEnvelope(parsed.command === "
|
|
167
|
-
? "cogcoin/
|
|
168
|
-
:
|
|
169
|
-
? "cogcoin/mine-log/v1"
|
|
170
|
-
: "cogcoin/mine-status/v1", describeCanonicalCommand(parsed), message, message));
|
|
129
|
+
writeJsonValue(context.stdout, createErrorEnvelope(parsed.command === "mine-log"
|
|
130
|
+
? "cogcoin/mine-log/v1"
|
|
131
|
+
: "cogcoin/mine-status/v1", describeCanonicalCommand(parsed), message, message));
|
|
171
132
|
return 5;
|
|
172
133
|
}
|
|
173
134
|
writeLine(context.stderr, message);
|
|
@@ -1,23 +1,136 @@
|
|
|
1
1
|
import { dirname } from "node:path";
|
|
2
|
+
import { FileLockBusyError, acquireFileLock } from "../../wallet/fs/lock.js";
|
|
3
|
+
import { resolveWalletRootIdFromLocalArtifacts } from "../../wallet/root-resolution.js";
|
|
4
|
+
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
2
5
|
import { buildMineStartData, buildMineStopData, } from "../mining-json.js";
|
|
3
6
|
import { buildMineStartPreviewData, buildMineStopPreviewData, } from "../preview-json.js";
|
|
4
|
-
import { writeLine } from "../io.js";
|
|
7
|
+
import { usesTtyProgress, writeLine } from "../io.js";
|
|
5
8
|
import { createTerminalPrompter } from "../prompt.js";
|
|
6
9
|
import { createPreviewSuccessEnvelope, createMutationSuccessEnvelope, describeCanonicalCommand, resolvePreviewJsonSchema, resolveStableMiningControlJsonSchema, writeHandledCliError, writeJsonValue, } from "../output.js";
|
|
7
10
|
import { formatNextStepLines, getMineStopNextSteps, } from "../workflow-hints.js";
|
|
11
|
+
import { createStopSignalWatcher, waitForCompletionOrStop } from "../signals.js";
|
|
12
|
+
import { createSyncProgressReporter } from "../sync-progress.js";
|
|
8
13
|
function createCommandPrompter(parsed, context) {
|
|
9
14
|
return parsed.outputMode !== "text"
|
|
10
15
|
? createTerminalPrompter(context.stdin, context.stderr)
|
|
11
16
|
: context.createPrompter();
|
|
12
17
|
}
|
|
18
|
+
async function ensureMiningProviderSetup(options) {
|
|
19
|
+
const setupReady = await options.context.ensureBuiltInMiningSetupIfNeeded({
|
|
20
|
+
provider: options.provider,
|
|
21
|
+
prompter: options.prompter,
|
|
22
|
+
paths: options.runtimePaths,
|
|
23
|
+
});
|
|
24
|
+
if (!setupReady) {
|
|
25
|
+
throw new Error("Built-in mining provider is not configured. Run `cogcoin mine setup`.");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function syncManagedMiningReadiness(options) {
|
|
29
|
+
const ttyProgressActive = usesTtyProgress(options.parsed.progressOutput, options.context.stderr);
|
|
30
|
+
let controlLock = null;
|
|
31
|
+
let store = null;
|
|
32
|
+
let storeOwned = true;
|
|
33
|
+
let client = null;
|
|
34
|
+
let clientClosed = false;
|
|
35
|
+
try {
|
|
36
|
+
const walletRoot = await resolveWalletRootIdFromLocalArtifacts({
|
|
37
|
+
paths: options.runtimePaths,
|
|
38
|
+
provider: options.provider,
|
|
39
|
+
loadRawWalletStateEnvelope: options.context.loadRawWalletStateEnvelope,
|
|
40
|
+
});
|
|
41
|
+
try {
|
|
42
|
+
controlLock = await acquireFileLock(options.runtimePaths.walletControlLockPath, {
|
|
43
|
+
purpose: "managed-sync",
|
|
44
|
+
walletRootId: walletRoot.walletRootId,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error instanceof FileLockBusyError) {
|
|
49
|
+
throw new Error("wallet_control_lock_busy");
|
|
50
|
+
}
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
await options.context.ensureDirectory(dirname(options.databasePath));
|
|
54
|
+
store = await options.context.openSqliteStore({ filename: options.databasePath });
|
|
55
|
+
client = await options.context.openManagedBitcoindClient({
|
|
56
|
+
store,
|
|
57
|
+
databasePath: options.databasePath,
|
|
58
|
+
dataDir: options.dataDir,
|
|
59
|
+
walletRootId: walletRoot.walletRootId,
|
|
60
|
+
progressOutput: options.parsed.progressOutput,
|
|
61
|
+
onProgress: ttyProgressActive ? undefined : createSyncProgressReporter({
|
|
62
|
+
progressOutput: options.parsed.progressOutput,
|
|
63
|
+
write: (line) => {
|
|
64
|
+
writeLine(options.context.stderr, line);
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
});
|
|
68
|
+
storeOwned = false;
|
|
69
|
+
const stopWatcher = createStopSignalWatcher(options.context.signalSource, options.context.stderr, client, options.context.forceExit, [options.runtimePaths.walletControlLockPath]);
|
|
70
|
+
try {
|
|
71
|
+
const syncOutcome = await waitForCompletionOrStop(client.syncToTip(), stopWatcher);
|
|
72
|
+
if (syncOutcome.kind === "stopped") {
|
|
73
|
+
return syncOutcome.code;
|
|
74
|
+
}
|
|
75
|
+
const result = syncOutcome.value;
|
|
76
|
+
if (result.endingHeight !== null && result.endingHeight === result.bestHeight) {
|
|
77
|
+
stopWatcher.cleanup();
|
|
78
|
+
const detachPromise = typeof client.detachToBackgroundFollow === "function"
|
|
79
|
+
? client.detachToBackgroundFollow()
|
|
80
|
+
: Promise.resolve();
|
|
81
|
+
try {
|
|
82
|
+
await detachPromise;
|
|
83
|
+
await client.close();
|
|
84
|
+
clientClosed = true;
|
|
85
|
+
writeLine(options.context.stderr, "Detached cleanly; background indexer follow resumed.");
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
writeLine(options.context.stderr, "Detach failed before background indexer follow was confirmed.");
|
|
90
|
+
return 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
throw new Error("Managed sync did not reach the current Bitcoin tip.");
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
stopWatcher.cleanup();
|
|
97
|
+
if (!clientClosed) {
|
|
98
|
+
await client.close();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
if (storeOwned && store !== null) {
|
|
104
|
+
await store.close().catch(() => undefined);
|
|
105
|
+
}
|
|
106
|
+
await controlLock?.release().catch(() => undefined);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
13
109
|
export async function runMiningRuntimeCommand(parsed, context) {
|
|
14
110
|
try {
|
|
15
111
|
const dbPath = parsed.dbPath ?? context.resolveDefaultClientDatabasePath();
|
|
16
112
|
const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
|
|
17
|
-
const provider = context.walletSecretProvider;
|
|
18
113
|
const runtimePaths = context.resolveWalletRuntimePaths(parsed.seedName);
|
|
19
|
-
await context.ensureDirectory(dirname(dbPath));
|
|
20
114
|
if (parsed.command === "mine") {
|
|
115
|
+
const prompter = context.createPrompter();
|
|
116
|
+
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, prompter);
|
|
117
|
+
await ensureMiningProviderSetup({
|
|
118
|
+
context,
|
|
119
|
+
provider,
|
|
120
|
+
prompter,
|
|
121
|
+
runtimePaths,
|
|
122
|
+
});
|
|
123
|
+
const preflightCode = await syncManagedMiningReadiness({
|
|
124
|
+
parsed,
|
|
125
|
+
context,
|
|
126
|
+
dataDir,
|
|
127
|
+
databasePath: dbPath,
|
|
128
|
+
provider,
|
|
129
|
+
runtimePaths,
|
|
130
|
+
});
|
|
131
|
+
if (preflightCode !== null) {
|
|
132
|
+
return preflightCode;
|
|
133
|
+
}
|
|
21
134
|
const abortController = new AbortController();
|
|
22
135
|
const onStop = () => {
|
|
23
136
|
abortController.abort();
|
|
@@ -29,11 +142,12 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
29
142
|
dataDir,
|
|
30
143
|
databasePath: dbPath,
|
|
31
144
|
provider,
|
|
32
|
-
prompter
|
|
145
|
+
prompter,
|
|
33
146
|
signal: abortController.signal,
|
|
34
147
|
stdout: context.stdout,
|
|
35
148
|
stderr: context.stderr,
|
|
36
149
|
progressOutput: parsed.progressOutput,
|
|
150
|
+
builtInSetupEnsured: true,
|
|
37
151
|
paths: runtimePaths,
|
|
38
152
|
});
|
|
39
153
|
}
|
|
@@ -44,11 +158,31 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
44
158
|
return 0;
|
|
45
159
|
}
|
|
46
160
|
if (parsed.command === "mine-start") {
|
|
161
|
+
const prompter = createCommandPrompter(parsed, context);
|
|
162
|
+
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, prompter);
|
|
163
|
+
await ensureMiningProviderSetup({
|
|
164
|
+
context,
|
|
165
|
+
provider,
|
|
166
|
+
prompter,
|
|
167
|
+
runtimePaths,
|
|
168
|
+
});
|
|
169
|
+
const preflightCode = await syncManagedMiningReadiness({
|
|
170
|
+
parsed,
|
|
171
|
+
context,
|
|
172
|
+
dataDir,
|
|
173
|
+
databasePath: dbPath,
|
|
174
|
+
provider,
|
|
175
|
+
runtimePaths,
|
|
176
|
+
});
|
|
177
|
+
if (preflightCode !== null) {
|
|
178
|
+
return preflightCode;
|
|
179
|
+
}
|
|
47
180
|
const result = await context.startBackgroundMining({
|
|
48
181
|
dataDir,
|
|
49
182
|
databasePath: dbPath,
|
|
50
183
|
provider,
|
|
51
|
-
prompter
|
|
184
|
+
prompter,
|
|
185
|
+
builtInSetupEnsured: true,
|
|
52
186
|
paths: runtimePaths,
|
|
53
187
|
});
|
|
54
188
|
if (parsed.outputMode === "preview-json") {
|
|
@@ -73,6 +207,9 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
73
207
|
return 0;
|
|
74
208
|
}
|
|
75
209
|
if (parsed.command === "mine-stop") {
|
|
210
|
+
const provider = parsed.outputMode === "text"
|
|
211
|
+
? withInteractiveWalletSecretProvider(context.walletSecretProvider, context.createPrompter())
|
|
212
|
+
: context.walletSecretProvider;
|
|
76
213
|
const snapshot = await context.stopBackgroundMining({
|
|
77
214
|
dataDir,
|
|
78
215
|
databasePath: dbPath,
|
|
@@ -38,8 +38,6 @@ async function resolveEffectiveWalletRootId(context) {
|
|
|
38
38
|
paths: context.resolveWalletRuntimePaths(),
|
|
39
39
|
provider: context.walletSecretProvider,
|
|
40
40
|
loadRawWalletStateEnvelope: context.loadRawWalletStateEnvelope,
|
|
41
|
-
loadUnlockSession: context.loadUnlockSession,
|
|
42
|
-
loadWalletExplicitLock: context.loadWalletExplicitLock,
|
|
43
41
|
}).catch(() => ({
|
|
44
42
|
walletRootId: UNINITIALIZED_WALLET_ROOT_ID,
|
|
45
43
|
source: "default-uninitialized",
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { dirname } from "node:path";
|
|
2
2
|
import { buildStatusJson } from "../read-json.js";
|
|
3
|
-
import { formatWalletOverviewReport } from "../wallet-format.js";
|
|
3
|
+
import { formatBalanceReport, formatWalletOverviewReport } from "../wallet-format.js";
|
|
4
4
|
import { writeLine } from "../io.js";
|
|
5
|
+
import { createTerminalPrompter } from "../prompt.js";
|
|
5
6
|
import { createSuccessEnvelope, describeCanonicalCommand, writeJsonValue } from "../output.js";
|
|
7
|
+
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
6
8
|
export async function runStatusCommand(parsed, context) {
|
|
7
9
|
const dbPath = parsed.dbPath ?? context.resolveDefaultClientDatabasePath();
|
|
8
10
|
const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
|
|
9
11
|
const runtimePaths = context.resolveWalletRuntimePaths(parsed.seedName);
|
|
10
12
|
await context.ensureDirectory(dirname(dbPath));
|
|
13
|
+
const provider = parsed.outputMode === "text"
|
|
14
|
+
? withInteractiveWalletSecretProvider(context.walletSecretProvider, context.createPrompter?.() ?? createTerminalPrompter(context.stdin, context.stdout))
|
|
15
|
+
: context.walletSecretProvider;
|
|
11
16
|
const readContext = await context.openWalletReadContext({
|
|
12
17
|
dataDir,
|
|
13
18
|
databasePath: dbPath,
|
|
14
|
-
secretProvider:
|
|
19
|
+
secretProvider: provider,
|
|
15
20
|
paths: runtimePaths,
|
|
16
21
|
});
|
|
17
22
|
try {
|
|
@@ -25,6 +30,7 @@ export async function runStatusCommand(parsed, context) {
|
|
|
25
30
|
return 0;
|
|
26
31
|
}
|
|
27
32
|
writeLine(context.stdout, formatWalletOverviewReport(readContext, await context.readPackageVersion()));
|
|
33
|
+
writeLine(context.stdout, formatBalanceReport(readContext));
|
|
28
34
|
return 0;
|
|
29
35
|
}
|
|
30
36
|
finally {
|