@cogcoin/client 0.5.14 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +16 -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 +38 -3
- package/dist/cli/commands/service-runtime.js +0 -2
- package/dist/cli/commands/status.js +8 -2
- package/dist/cli/commands/sync.js +51 -4
- 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 +4 -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/types.d.ts +8 -17
- package/dist/cli/types.js +0 -2
- package/dist/cli/wallet-format.d.ts +1 -0
- package/dist/cli/wallet-format.js +205 -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 -11
- package/dist/wallet/coin-control.js +100 -357
- 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 +3 -4
- package/dist/wallet/mining/index.js +1 -2
- package/dist/wallet/mining/runner.d.ts +179 -6
- package/dist/wallet/mining/runner.js +891 -501
- 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 -1240
- 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 +74 -10
- package/dist/wallet/tx/common.js +315 -138
- 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 +84 -914
- 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/bitcoind/types.d.ts
CHANGED
|
@@ -173,6 +173,7 @@ export interface ManagedBitcoindClient extends Client {
|
|
|
173
173
|
syncToTip(): Promise<SyncResult>;
|
|
174
174
|
startFollowingTip(): Promise<void>;
|
|
175
175
|
getNodeStatus(): Promise<ManagedBitcoindStatus>;
|
|
176
|
+
detachToBackgroundFollow(): Promise<void>;
|
|
176
177
|
close(): Promise<void>;
|
|
177
178
|
}
|
|
178
179
|
export interface InternalManagedBitcoindOptions extends ManagedBitcoindOptions {
|
|
@@ -275,6 +276,7 @@ export interface RpcPrevout {
|
|
|
275
276
|
}
|
|
276
277
|
export interface RpcVin {
|
|
277
278
|
txid?: string;
|
|
279
|
+
vout?: number;
|
|
278
280
|
coinbase?: string;
|
|
279
281
|
prevout?: RpcPrevout;
|
|
280
282
|
}
|
|
@@ -298,6 +300,11 @@ export interface RpcMempoolEntry {
|
|
|
298
300
|
ancestorsize?: number;
|
|
299
301
|
descendantsize?: number;
|
|
300
302
|
}
|
|
303
|
+
export interface RpcEstimateSmartFeeResult {
|
|
304
|
+
feerate?: number;
|
|
305
|
+
errors?: string[];
|
|
306
|
+
blocks?: number;
|
|
307
|
+
}
|
|
301
308
|
export interface RpcRawMempoolVerbose {
|
|
302
309
|
txids: string[];
|
|
303
310
|
mempool_sequence: string | number;
|
|
@@ -310,6 +317,11 @@ export interface RpcWalletTransaction {
|
|
|
310
317
|
blockheight?: number;
|
|
311
318
|
time?: number;
|
|
312
319
|
timereceived?: number;
|
|
320
|
+
details?: Array<{
|
|
321
|
+
address?: string;
|
|
322
|
+
vout?: number;
|
|
323
|
+
}>;
|
|
324
|
+
decoded?: RpcTransaction;
|
|
313
325
|
}
|
|
314
326
|
export interface RpcBlock {
|
|
315
327
|
hash: string;
|
|
@@ -409,6 +421,10 @@ export interface RpcListUnspentEntry {
|
|
|
409
421
|
}
|
|
410
422
|
export interface RpcDecodedPsbt {
|
|
411
423
|
tx: RpcTransaction;
|
|
424
|
+
inputs?: Array<{
|
|
425
|
+
witness_utxo?: RpcVout;
|
|
426
|
+
non_witness_utxo?: RpcTransaction;
|
|
427
|
+
}>;
|
|
412
428
|
}
|
|
413
429
|
export interface RpcFinalizePsbtResult {
|
|
414
430
|
psbt?: string;
|
package/dist/bytes.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
2
2
|
export declare function hexToBytes(hex: string): Uint8Array;
|
|
3
3
|
export declare function cloneBytes(bytes: Uint8Array): Uint8Array;
|
|
4
|
+
export declare function reverseBytes(bytes: Uint8Array): Uint8Array;
|
|
4
5
|
export declare function encodeText(value: string): Uint8Array;
|
|
5
6
|
export declare function decodeText(bytes: Uint8Array): string;
|
|
6
7
|
export declare function encodeNullableText(value: string | null): Uint8Array;
|
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);
|
|
@@ -5,19 +5,42 @@ import { writeLine } from "../io.js";
|
|
|
5
5
|
import { createTerminalPrompter } from "../prompt.js";
|
|
6
6
|
import { createPreviewSuccessEnvelope, createMutationSuccessEnvelope, describeCanonicalCommand, resolvePreviewJsonSchema, resolveStableMiningControlJsonSchema, writeHandledCliError, writeJsonValue, } from "../output.js";
|
|
7
7
|
import { formatNextStepLines, getMineStopNextSteps, } from "../workflow-hints.js";
|
|
8
|
+
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
8
9
|
function createCommandPrompter(parsed, context) {
|
|
9
10
|
return parsed.outputMode !== "text"
|
|
10
11
|
? createTerminalPrompter(context.stdin, context.stderr)
|
|
11
12
|
: context.createPrompter();
|
|
12
13
|
}
|
|
14
|
+
async function prestartManagedMiningServices(options) {
|
|
15
|
+
let readContext = null;
|
|
16
|
+
try {
|
|
17
|
+
readContext = await options.context.openWalletReadContext({
|
|
18
|
+
dataDir: options.dataDir,
|
|
19
|
+
databasePath: options.databasePath,
|
|
20
|
+
secretProvider: options.provider,
|
|
21
|
+
paths: options.runtimePaths,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
await readContext?.close();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
13
28
|
export async function runMiningRuntimeCommand(parsed, context) {
|
|
14
29
|
try {
|
|
15
30
|
const dbPath = parsed.dbPath ?? context.resolveDefaultClientDatabasePath();
|
|
16
31
|
const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
|
|
17
|
-
const provider = context.walletSecretProvider;
|
|
18
32
|
const runtimePaths = context.resolveWalletRuntimePaths(parsed.seedName);
|
|
19
33
|
await context.ensureDirectory(dirname(dbPath));
|
|
20
34
|
if (parsed.command === "mine") {
|
|
35
|
+
const prompter = context.createPrompter();
|
|
36
|
+
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, prompter);
|
|
37
|
+
await prestartManagedMiningServices({
|
|
38
|
+
context,
|
|
39
|
+
dataDir,
|
|
40
|
+
databasePath: dbPath,
|
|
41
|
+
provider,
|
|
42
|
+
runtimePaths,
|
|
43
|
+
});
|
|
21
44
|
const abortController = new AbortController();
|
|
22
45
|
const onStop = () => {
|
|
23
46
|
abortController.abort();
|
|
@@ -29,7 +52,7 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
29
52
|
dataDir,
|
|
30
53
|
databasePath: dbPath,
|
|
31
54
|
provider,
|
|
32
|
-
prompter
|
|
55
|
+
prompter,
|
|
33
56
|
signal: abortController.signal,
|
|
34
57
|
stdout: context.stdout,
|
|
35
58
|
stderr: context.stderr,
|
|
@@ -44,11 +67,20 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
44
67
|
return 0;
|
|
45
68
|
}
|
|
46
69
|
if (parsed.command === "mine-start") {
|
|
70
|
+
const prompter = createCommandPrompter(parsed, context);
|
|
71
|
+
const provider = withInteractiveWalletSecretProvider(context.walletSecretProvider, prompter);
|
|
72
|
+
await prestartManagedMiningServices({
|
|
73
|
+
context,
|
|
74
|
+
dataDir,
|
|
75
|
+
databasePath: dbPath,
|
|
76
|
+
provider,
|
|
77
|
+
runtimePaths,
|
|
78
|
+
});
|
|
47
79
|
const result = await context.startBackgroundMining({
|
|
48
80
|
dataDir,
|
|
49
81
|
databasePath: dbPath,
|
|
50
82
|
provider,
|
|
51
|
-
prompter
|
|
83
|
+
prompter,
|
|
52
84
|
paths: runtimePaths,
|
|
53
85
|
});
|
|
54
86
|
if (parsed.outputMode === "preview-json") {
|
|
@@ -73,6 +105,9 @@ export async function runMiningRuntimeCommand(parsed, context) {
|
|
|
73
105
|
return 0;
|
|
74
106
|
}
|
|
75
107
|
if (parsed.command === "mine-stop") {
|
|
108
|
+
const provider = parsed.outputMode === "text"
|
|
109
|
+
? withInteractiveWalletSecretProvider(context.walletSecretProvider, context.createPrompter())
|
|
110
|
+
: context.walletSecretProvider;
|
|
76
111
|
const snapshot = await context.stopBackgroundMining({
|
|
77
112
|
dataDir,
|
|
78
113
|
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 {
|
|
@@ -3,10 +3,29 @@ import { formatManagedSyncErrorMessage } from "../../bitcoind/errors.js";
|
|
|
3
3
|
import { formatBytes, formatDuration } from "../../bitcoind/progress/formatting.js";
|
|
4
4
|
import { FileLockBusyError, acquireFileLock } from "../../wallet/fs/lock.js";
|
|
5
5
|
import { resolveWalletRootIdFromLocalArtifacts } from "../../wallet/root-resolution.js";
|
|
6
|
+
import { withInteractiveWalletSecretProvider } from "../../wallet/state/provider.js";
|
|
6
7
|
import { usesTtyProgress, writeLine } from "../io.js";
|
|
7
8
|
import { classifyCliError, formatCliTextError } from "../output.js";
|
|
9
|
+
import { createTerminalPrompter } from "../prompt.js";
|
|
8
10
|
import { createStopSignalWatcher, waitForCompletionOrStop } from "../signals.js";
|
|
11
|
+
import { formatBalanceReport } from "../wallet-format.js";
|
|
9
12
|
const SYNC_PROGRESS_LOG_INTERVAL_MS = 5_000;
|
|
13
|
+
async function writePostSyncBalanceReport(options) {
|
|
14
|
+
const provider = withInteractiveWalletSecretProvider(options.context.walletSecretProvider, options.context.createPrompter?.() ?? createTerminalPrompter(options.context.stdin, options.context.stdout));
|
|
15
|
+
const readContext = await options.context.openWalletReadContext({
|
|
16
|
+
dataDir: options.dataDir,
|
|
17
|
+
databasePath: options.databasePath,
|
|
18
|
+
secretProvider: provider,
|
|
19
|
+
walletControlLockHeld: true,
|
|
20
|
+
paths: options.runtimePaths,
|
|
21
|
+
});
|
|
22
|
+
try {
|
|
23
|
+
writeLine(options.context.stdout, formatBalanceReport(readContext));
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
await readContext.close().catch(() => undefined);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
10
29
|
function createSyncProgressReporter(options) {
|
|
11
30
|
let lastPhase = null;
|
|
12
31
|
let lastMessage = "";
|
|
@@ -104,13 +123,13 @@ export async function runSyncCommand(parsed, context) {
|
|
|
104
123
|
let controlLock = null;
|
|
105
124
|
let store = null;
|
|
106
125
|
let storeOwned = true;
|
|
126
|
+
let client = null;
|
|
127
|
+
let clientClosed = false;
|
|
107
128
|
try {
|
|
108
129
|
const walletRoot = await resolveWalletRootIdFromLocalArtifacts({
|
|
109
130
|
paths: runtimePaths,
|
|
110
131
|
provider: context.walletSecretProvider,
|
|
111
132
|
loadRawWalletStateEnvelope: context.loadRawWalletStateEnvelope,
|
|
112
|
-
loadUnlockSession: context.loadUnlockSession,
|
|
113
|
-
loadWalletExplicitLock: context.loadWalletExplicitLock,
|
|
114
133
|
});
|
|
115
134
|
try {
|
|
116
135
|
controlLock = await acquireFileLock(runtimePaths.walletControlLockPath, {
|
|
@@ -126,7 +145,7 @@ export async function runSyncCommand(parsed, context) {
|
|
|
126
145
|
}
|
|
127
146
|
await context.ensureDirectory(dirname(dbPath));
|
|
128
147
|
store = await context.openSqliteStore({ filename: dbPath });
|
|
129
|
-
|
|
148
|
+
client = await context.openManagedBitcoindClient({
|
|
130
149
|
store,
|
|
131
150
|
databasePath: dbPath,
|
|
132
151
|
dataDir,
|
|
@@ -147,6 +166,32 @@ export async function runSyncCommand(parsed, context) {
|
|
|
147
166
|
return syncOutcome.code;
|
|
148
167
|
}
|
|
149
168
|
const result = syncOutcome.value;
|
|
169
|
+
if (result.endingHeight !== null && result.endingHeight === result.bestHeight) {
|
|
170
|
+
stopWatcher.cleanup();
|
|
171
|
+
const detachPromise = typeof client.detachToBackgroundFollow === "function"
|
|
172
|
+
? client.detachToBackgroundFollow()
|
|
173
|
+
: Promise.resolve();
|
|
174
|
+
if (typeof client.playSyncCompletionScene === "function") {
|
|
175
|
+
await client.playSyncCompletionScene().catch(() => undefined);
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
await detachPromise;
|
|
179
|
+
await client.close();
|
|
180
|
+
clientClosed = true;
|
|
181
|
+
writeLine(context.stderr, "Detached cleanly; background indexer follow resumed.");
|
|
182
|
+
await writePostSyncBalanceReport({
|
|
183
|
+
context,
|
|
184
|
+
dataDir,
|
|
185
|
+
databasePath: dbPath,
|
|
186
|
+
runtimePaths,
|
|
187
|
+
}).catch(() => undefined);
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
writeLine(context.stderr, "Detach failed before background indexer follow was confirmed.");
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
150
195
|
if (typeof client.playSyncCompletionScene === "function") {
|
|
151
196
|
const completionOutcome = await waitForCompletionOrStop(client.playSyncCompletionScene().catch(() => undefined), stopWatcher);
|
|
152
197
|
if (completionOutcome.kind === "stopped") {
|
|
@@ -161,7 +206,9 @@ export async function runSyncCommand(parsed, context) {
|
|
|
161
206
|
}
|
|
162
207
|
finally {
|
|
163
208
|
stopWatcher.cleanup();
|
|
164
|
-
|
|
209
|
+
if (!clientClosed) {
|
|
210
|
+
await client.close();
|
|
211
|
+
}
|
|
165
212
|
}
|
|
166
213
|
}
|
|
167
214
|
catch (error) {
|