@cogcoin/client 0.5.6 → 0.5.8
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 +11 -2
- package/dist/bitcoind/bootstrap/getblock-archive.d.ts +39 -0
- package/dist/bitcoind/bootstrap/getblock-archive.js +548 -0
- package/dist/bitcoind/bootstrap.d.ts +1 -0
- package/dist/bitcoind/bootstrap.js +1 -0
- package/dist/bitcoind/client/factory.js +92 -30
- package/dist/bitcoind/client/managed-client.d.ts +1 -1
- package/dist/bitcoind/client/managed-client.js +22 -2
- package/dist/bitcoind/client/sync-engine.js +7 -0
- package/dist/bitcoind/errors.js +18 -0
- package/dist/bitcoind/indexer-daemon-main.js +78 -0
- package/dist/bitcoind/indexer-daemon.d.ts +3 -1
- package/dist/bitcoind/indexer-daemon.js +13 -6
- package/dist/bitcoind/node.js +2 -0
- package/dist/bitcoind/progress/constants.d.ts +1 -0
- package/dist/bitcoind/progress/constants.js +1 -0
- package/dist/bitcoind/progress/controller.d.ts +22 -0
- package/dist/bitcoind/progress/controller.js +48 -23
- package/dist/bitcoind/progress/formatting.js +25 -0
- package/dist/bitcoind/progress/render-policy.d.ts +35 -0
- package/dist/bitcoind/progress/render-policy.js +81 -0
- package/dist/bitcoind/service-paths.js +2 -6
- package/dist/bitcoind/service.d.ts +5 -1
- package/dist/bitcoind/service.js +92 -54
- package/dist/bitcoind/testing.d.ts +2 -1
- package/dist/bitcoind/testing.js +2 -1
- package/dist/bitcoind/types.d.ts +35 -1
- package/dist/cli/commands/follow.js +2 -0
- package/dist/cli/commands/getblock-archive-restart.d.ts +5 -0
- package/dist/cli/commands/getblock-archive-restart.js +15 -0
- package/dist/cli/commands/mining-admin.js +4 -0
- package/dist/cli/commands/mining-read.js +8 -5
- package/dist/cli/commands/mining-runtime.js +4 -0
- package/dist/cli/commands/status.js +2 -0
- package/dist/cli/commands/sync.js +2 -0
- package/dist/cli/commands/wallet-admin.js +29 -3
- package/dist/cli/commands/wallet-mutation.js +57 -4
- package/dist/cli/commands/wallet-read.js +2 -0
- package/dist/cli/context.js +5 -3
- package/dist/cli/mutation-command-groups.d.ts +2 -1
- package/dist/cli/mutation-command-groups.js +5 -0
- package/dist/cli/mutation-json.d.ts +18 -2
- package/dist/cli/mutation-json.js +47 -0
- package/dist/cli/mutation-success.d.ts +1 -0
- package/dist/cli/mutation-success.js +2 -2
- package/dist/cli/output.js +97 -1
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +127 -3
- package/dist/cli/preview-json.d.ts +10 -1
- package/dist/cli/preview-json.js +30 -0
- package/dist/cli/prompt.js +1 -1
- package/dist/cli/runner.js +20 -0
- package/dist/cli/signals.js +1 -1
- package/dist/cli/types.d.ts +11 -4
- package/dist/cli/wallet-format.js +6 -0
- package/dist/wallet/lifecycle.d.ts +18 -1
- package/dist/wallet/lifecycle.js +170 -81
- package/dist/wallet/mining/visualizer.d.ts +11 -6
- package/dist/wallet/mining/visualizer.js +32 -15
- package/dist/wallet/reset.js +39 -27
- package/dist/wallet/runtime.d.ts +12 -1
- package/dist/wallet/runtime.js +53 -11
- package/dist/wallet/state/provider.d.ts +1 -0
- package/dist/wallet/state/provider.js +119 -3
- package/dist/wallet/state/seed-index.d.ts +43 -0
- package/dist/wallet/state/seed-index.js +151 -0
- package/dist/wallet/tx/anchor.d.ts +22 -0
- package/dist/wallet/tx/anchor.js +201 -8
- package/dist/wallet/tx/index.d.ts +1 -1
- package/dist/wallet/tx/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { FIELD_LEFT, FIELD_WIDTH, PREPARING_SYNC_LINE, PROGRESS_TICK_MS, SCROLL_WINDOW_LEFT, SCROLL_WINDOW_WIDTH, STATUS_ELLIPSIS_TICK_MS, STATUS_ELLIPSIS_WIDTH, } from "./constants.js";
|
|
2
2
|
export function createDefaultMessage(phase) {
|
|
3
3
|
switch (phase) {
|
|
4
|
+
case "getblock_archive_download":
|
|
5
|
+
return "Downloading getblock archive.";
|
|
6
|
+
case "getblock_archive_import":
|
|
7
|
+
return "Bitcoin Core is importing getblock archive blocks.";
|
|
4
8
|
case "snapshot_download":
|
|
5
9
|
return "Downloading UTXO snapshot.";
|
|
6
10
|
case "wait_headers_for_snapshot":
|
|
@@ -121,6 +125,10 @@ function animateStatusEllipsis(now) {
|
|
|
121
125
|
}
|
|
122
126
|
export function resolveStatusFieldText(progress, snapshotHeight, now = 0) {
|
|
123
127
|
switch (progress.phase) {
|
|
128
|
+
case "getblock_archive_download":
|
|
129
|
+
return `Downloading getblock archive${animateStatusEllipsis(now)}`;
|
|
130
|
+
case "getblock_archive_import":
|
|
131
|
+
return `Importing getblock archive${animateStatusEllipsis(now)}`;
|
|
124
132
|
case "paused":
|
|
125
133
|
case "snapshot_download":
|
|
126
134
|
return `Downloading snapshot to ${snapshotHeight}${animateStatusEllipsis(now)}`;
|
|
@@ -166,6 +174,16 @@ export const formatQuoteLineForTesting = formatQuoteLine;
|
|
|
166
174
|
export function formatProgressLine(progress, cogcoinSyncHeight, cogcoinSyncTargetHeight, width = 120, now = Date.now()) {
|
|
167
175
|
let line;
|
|
168
176
|
switch (progress.phase) {
|
|
177
|
+
case "getblock_archive_download": {
|
|
178
|
+
const current = progress.downloadedBytes ?? 0;
|
|
179
|
+
const total = progress.totalBytes ?? 0;
|
|
180
|
+
const bar = renderBar(current, total, 20);
|
|
181
|
+
const percent = progress.percent ?? (total > 0 ? (current / total) * 100 : 0);
|
|
182
|
+
const speed = progress.bytesPerSecond === null ? "--" : `${formatBytes(progress.bytesPerSecond)}/s`;
|
|
183
|
+
const resumed = progress.resumed ? " resumed" : "";
|
|
184
|
+
line = `${bar} ${percent.toFixed(2)}% ${formatBytes(current)} / ${formatBytes(total)} ${speed} ETA ${formatDuration(progress.etaSeconds)}${resumed}`;
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
169
187
|
case "snapshot_download": {
|
|
170
188
|
const current = progress.downloadedBytes ?? 0;
|
|
171
189
|
const total = progress.totalBytes ?? 0;
|
|
@@ -190,6 +208,13 @@ export function formatProgressLine(progress, cogcoinSyncHeight, cogcoinSyncTarge
|
|
|
190
208
|
line = `${bar} Bitcoin ${blocks.toLocaleString()} / ${target.toLocaleString()} ETA ${formatDuration(progress.etaSeconds)} ${progress.message}`;
|
|
191
209
|
break;
|
|
192
210
|
}
|
|
211
|
+
case "getblock_archive_import": {
|
|
212
|
+
const blocks = progress.blocks ?? 0;
|
|
213
|
+
const target = progress.targetHeight ?? blocks;
|
|
214
|
+
const bar = renderBar(blocks, target, 20);
|
|
215
|
+
line = `${bar} Bitcoin ${blocks.toLocaleString()} / ${target.toLocaleString()} ${progress.message}`;
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
193
218
|
case "cogcoin_sync": {
|
|
194
219
|
const current = cogcoinSyncHeight ?? 0;
|
|
195
220
|
const target = cogcoinSyncTargetHeight ?? current;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ProgressOutputMode } from "../types.js";
|
|
2
|
+
export interface TtyRenderStream {
|
|
3
|
+
isTTY?: boolean;
|
|
4
|
+
columns?: number;
|
|
5
|
+
write(chunk: string): boolean | void;
|
|
6
|
+
}
|
|
7
|
+
export interface RenderClock {
|
|
8
|
+
now(): number;
|
|
9
|
+
setTimeout: typeof setTimeout;
|
|
10
|
+
clearTimeout: typeof clearTimeout;
|
|
11
|
+
setInterval: typeof setInterval;
|
|
12
|
+
clearInterval: typeof clearInterval;
|
|
13
|
+
}
|
|
14
|
+
export interface TtyRenderPolicy {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
linuxHeadlessThrottle: boolean;
|
|
17
|
+
repaintIntervalMs: number;
|
|
18
|
+
}
|
|
19
|
+
export declare const DEFAULT_RENDER_CLOCK: RenderClock;
|
|
20
|
+
export declare function resolveTtyRenderPolicy(progressOutput: ProgressOutputMode, stream: Pick<TtyRenderStream, "isTTY">, options?: {
|
|
21
|
+
platform?: NodeJS.Platform;
|
|
22
|
+
env?: NodeJS.ProcessEnv;
|
|
23
|
+
}): TtyRenderPolicy;
|
|
24
|
+
export declare class TtyRenderThrottle {
|
|
25
|
+
#private;
|
|
26
|
+
constructor(options: {
|
|
27
|
+
clock?: RenderClock;
|
|
28
|
+
intervalMs: number;
|
|
29
|
+
onRender: () => void;
|
|
30
|
+
throttled: boolean;
|
|
31
|
+
});
|
|
32
|
+
request(): void;
|
|
33
|
+
flush(): void;
|
|
34
|
+
cancel(): void;
|
|
35
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { HEADLESS_PROGRESS_TICK_MS, PROGRESS_TICK_MS } from "./constants.js";
|
|
2
|
+
export const DEFAULT_RENDER_CLOCK = {
|
|
3
|
+
now: () => Date.now(),
|
|
4
|
+
setTimeout,
|
|
5
|
+
clearTimeout,
|
|
6
|
+
setInterval,
|
|
7
|
+
clearInterval,
|
|
8
|
+
};
|
|
9
|
+
export function resolveTtyRenderPolicy(progressOutput, stream, options = {}) {
|
|
10
|
+
const ttyActive = stream.isTTY === true;
|
|
11
|
+
const enabled = progressOutput === "none"
|
|
12
|
+
? false
|
|
13
|
+
: progressOutput === "tty"
|
|
14
|
+
? true
|
|
15
|
+
: ttyActive;
|
|
16
|
+
const env = options.env ?? process.env;
|
|
17
|
+
const linuxHeadlessThrottle = enabled
|
|
18
|
+
&& ttyActive
|
|
19
|
+
&& (options.platform ?? process.platform) === "linux"
|
|
20
|
+
&& (env.DISPLAY?.trim() ?? "").length === 0
|
|
21
|
+
&& (env.WAYLAND_DISPLAY?.trim() ?? "").length === 0;
|
|
22
|
+
return {
|
|
23
|
+
enabled,
|
|
24
|
+
linuxHeadlessThrottle,
|
|
25
|
+
repaintIntervalMs: linuxHeadlessThrottle ? HEADLESS_PROGRESS_TICK_MS : PROGRESS_TICK_MS,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export class TtyRenderThrottle {
|
|
29
|
+
#clock;
|
|
30
|
+
#intervalMs;
|
|
31
|
+
#onRender;
|
|
32
|
+
#throttled;
|
|
33
|
+
#lastRenderAt = null;
|
|
34
|
+
#pendingTimer = null;
|
|
35
|
+
constructor(options) {
|
|
36
|
+
this.#clock = options.clock ?? DEFAULT_RENDER_CLOCK;
|
|
37
|
+
this.#intervalMs = options.intervalMs;
|
|
38
|
+
this.#onRender = options.onRender;
|
|
39
|
+
this.#throttled = options.throttled;
|
|
40
|
+
}
|
|
41
|
+
request() {
|
|
42
|
+
if (!this.#throttled) {
|
|
43
|
+
this.cancel();
|
|
44
|
+
this.#renderNow();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const now = this.#clock.now();
|
|
48
|
+
if (this.#lastRenderAt === null || (now - this.#lastRenderAt) >= this.#intervalMs) {
|
|
49
|
+
this.cancel();
|
|
50
|
+
this.#renderNow();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (this.#pendingTimer !== null) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const delayMs = Math.max(0, this.#intervalMs - (now - this.#lastRenderAt));
|
|
57
|
+
this.#pendingTimer = this.#clock.setTimeout(() => {
|
|
58
|
+
this.#pendingTimer = null;
|
|
59
|
+
this.#renderNow();
|
|
60
|
+
}, delayMs);
|
|
61
|
+
}
|
|
62
|
+
flush() {
|
|
63
|
+
if (this.#pendingTimer === null) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.#clock.clearTimeout(this.#pendingTimer);
|
|
67
|
+
this.#pendingTimer = null;
|
|
68
|
+
this.#renderNow();
|
|
69
|
+
}
|
|
70
|
+
cancel() {
|
|
71
|
+
if (this.#pendingTimer === null) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.#clock.clearTimeout(this.#pendingTimer);
|
|
75
|
+
this.#pendingTimer = null;
|
|
76
|
+
}
|
|
77
|
+
#renderNow() {
|
|
78
|
+
this.#lastRenderAt = this.#clock.now();
|
|
79
|
+
this.#onRender();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -3,9 +3,6 @@ import { tmpdir } from "node:os";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { resolveCogcoinPathsForTesting, resolveDefaultBitcoindDataDirForTesting } from "../app-paths.js";
|
|
5
5
|
export const UNINITIALIZED_WALLET_ROOT_ID = "wallet-root-uninitialized";
|
|
6
|
-
function sanitizeWalletRootId(walletRootId) {
|
|
7
|
-
return walletRootId.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
8
|
-
}
|
|
9
6
|
function createDataDirSuffix(dataDir) {
|
|
10
7
|
return createHash("sha256").update(dataDir).digest("hex").slice(0, 12);
|
|
11
8
|
}
|
|
@@ -17,7 +14,6 @@ function resolveIndexerDaemonSocketPath(serviceRootId) {
|
|
|
17
14
|
return join(tmpdir(), `cogcoin-indexer-${socketId}.sock`);
|
|
18
15
|
}
|
|
19
16
|
export function resolveManagedServicePaths(dataDir, walletRootId = UNINITIALIZED_WALLET_ROOT_ID) {
|
|
20
|
-
const normalizedWalletRootId = sanitizeWalletRootId(walletRootId);
|
|
21
17
|
const defaultPaths = resolveCogcoinPathsForTesting();
|
|
22
18
|
const defaultBitcoindDataDir = resolveDefaultBitcoindDataDirForTesting();
|
|
23
19
|
const useDefaultRoots = dataDir === defaultBitcoindDataDir;
|
|
@@ -25,8 +21,8 @@ export function resolveManagedServicePaths(dataDir, walletRootId = UNINITIALIZED
|
|
|
25
21
|
const runtimeRoot = useDefaultRoots ? defaultPaths.runtimeRoot : join(dataRoot, "runtime");
|
|
26
22
|
const indexerRoot = useDefaultRoots ? defaultPaths.indexerRoot : join(dataRoot, "indexer");
|
|
27
23
|
const serviceRootId = useDefaultRoots
|
|
28
|
-
?
|
|
29
|
-
:
|
|
24
|
+
? "managed"
|
|
25
|
+
: `managed-${createDataDirSuffix(dataDir)}`;
|
|
30
26
|
const walletRuntimeRoot = join(runtimeRoot, serviceRootId);
|
|
31
27
|
const indexerServiceRoot = join(indexerRoot, serviceRootId);
|
|
32
28
|
return {
|
|
@@ -20,7 +20,11 @@ interface ManagedWalletReplicaRpc {
|
|
|
20
20
|
}>;
|
|
21
21
|
walletLock(walletName: string): Promise<null>;
|
|
22
22
|
}
|
|
23
|
-
type ManagedBitcoindServiceOptions = Pick<InternalManagedBitcoindOptions, "dataDir" | "chain" | "startHeight" | "walletRootId" | "rpcPort" | "zmqPort" | "p2pPort" | "pollIntervalMs" | "startupTimeoutMs" | "shutdownTimeoutMs" | "managedWalletPassphrase"
|
|
23
|
+
type ManagedBitcoindServiceOptions = Pick<InternalManagedBitcoindOptions, "dataDir" | "chain" | "startHeight" | "walletRootId" | "rpcPort" | "zmqPort" | "p2pPort" | "pollIntervalMs" | "startupTimeoutMs" | "shutdownTimeoutMs" | "managedWalletPassphrase"> & {
|
|
24
|
+
getblockArchivePath?: string | null;
|
|
25
|
+
getblockArchiveEndHeight?: number | null;
|
|
26
|
+
getblockArchiveSha256?: string | null;
|
|
27
|
+
};
|
|
24
28
|
export type ManagedBitcoindServiceCompatibility = "compatible" | "service-version-mismatch" | "wallet-root-mismatch" | "runtime-mismatch" | "unreachable" | "protocol-error";
|
|
25
29
|
export interface ManagedBitcoindServiceProbeResult {
|
|
26
30
|
compatibility: ManagedBitcoindServiceCompatibility;
|
package/dist/bitcoind/service.js
CHANGED
|
@@ -226,15 +226,13 @@ async function waitForRpcReady(rpc, cookieFile, expectedChain, timeoutMs) {
|
|
|
226
226
|
throw lastError instanceof Error ? lastError : new Error("bitcoind_rpc_timeout");
|
|
227
227
|
}
|
|
228
228
|
function validateManagedBitcoindStatus(status, options, runtimeRoot) {
|
|
229
|
+
const legacyRuntimeRoot = join(resolveManagedServicePaths(options.dataDir ?? "", options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID).runtimeRoot, status.walletRootId);
|
|
229
230
|
if (status.serviceApiVersion !== MANAGED_BITCOIND_SERVICE_API_VERSION_VALUE) {
|
|
230
231
|
throw new Error("managed_bitcoind_service_version_mismatch");
|
|
231
232
|
}
|
|
232
|
-
if (status.walletRootId !== (options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID)) {
|
|
233
|
-
throw new Error("managed_bitcoind_wallet_root_mismatch");
|
|
234
|
-
}
|
|
235
233
|
if (status.chain !== options.chain
|
|
236
234
|
|| status.dataDir !== (options.dataDir ?? "")
|
|
237
|
-
|| status.runtimeRoot !== runtimeRoot) {
|
|
235
|
+
|| (status.runtimeRoot !== runtimeRoot && status.runtimeRoot !== legacyRuntimeRoot)) {
|
|
238
236
|
throw new Error("managed_bitcoind_runtime_mismatch");
|
|
239
237
|
}
|
|
240
238
|
}
|
|
@@ -275,6 +273,8 @@ function createBitcoindServiceStatus(options) {
|
|
|
275
273
|
rpc: options.rpc,
|
|
276
274
|
zmq: options.zmq,
|
|
277
275
|
p2pPort: options.p2pPort,
|
|
276
|
+
getblockArchiveEndHeight: options.getblockArchiveEndHeight,
|
|
277
|
+
getblockArchiveSha256: options.getblockArchiveSha256,
|
|
278
278
|
walletReplica: options.walletReplica,
|
|
279
279
|
startedAtUnixMs: options.startedAtUnixMs,
|
|
280
280
|
heartbeatAtUnixMs: options.heartbeatAtUnixMs,
|
|
@@ -287,9 +287,7 @@ function mapManagedBitcoindValidationError(error) {
|
|
|
287
287
|
compatibility: error instanceof Error
|
|
288
288
|
? error.message === "managed_bitcoind_service_version_mismatch"
|
|
289
289
|
? "service-version-mismatch"
|
|
290
|
-
:
|
|
291
|
-
? "wallet-root-mismatch"
|
|
292
|
-
: "runtime-mismatch"
|
|
290
|
+
: "runtime-mismatch"
|
|
293
291
|
: "protocol-error",
|
|
294
292
|
status: null,
|
|
295
293
|
error: error instanceof Error ? error.message : "managed_bitcoind_protocol_error",
|
|
@@ -366,6 +364,8 @@ async function resolveRuntimeConfig(statusPath, configPath, options) {
|
|
|
366
364
|
zmqPort,
|
|
367
365
|
p2pPort,
|
|
368
366
|
dbcacheMiB: detectManagedBitcoindDbcacheMiB(),
|
|
367
|
+
getblockArchiveEndHeight: options.getblockArchiveEndHeight ?? null,
|
|
368
|
+
getblockArchiveSha256: options.getblockArchiveSha256 ?? null,
|
|
369
369
|
};
|
|
370
370
|
}
|
|
371
371
|
async function writeBitcoinConf(filePath, options, runtimeConfig) {
|
|
@@ -407,6 +407,9 @@ function buildManagedServiceArgs(options, runtimeConfig) {
|
|
|
407
407
|
if (options.chain === "regtest") {
|
|
408
408
|
args.push("-chain=regtest");
|
|
409
409
|
}
|
|
410
|
+
if (options.getblockArchivePath !== undefined && options.getblockArchivePath !== null) {
|
|
411
|
+
args.push(`-loadblock=${options.getblockArchivePath}`);
|
|
412
|
+
}
|
|
410
413
|
return args;
|
|
411
414
|
}
|
|
412
415
|
export async function writeBitcoinConfForTesting(filePath, options, runtimeConfig) {
|
|
@@ -547,6 +550,8 @@ async function writeBitcoindStatus(paths, status) {
|
|
|
547
550
|
rpc: status.rpc,
|
|
548
551
|
zmqPort: status.zmq.port,
|
|
549
552
|
p2pPort: status.p2pPort,
|
|
553
|
+
getblockArchiveEndHeight: status.getblockArchiveEndHeight,
|
|
554
|
+
getblockArchiveSha256: status.getblockArchiveSha256,
|
|
550
555
|
});
|
|
551
556
|
}
|
|
552
557
|
async function clearManagedBitcoindRuntimeArtifacts(paths) {
|
|
@@ -590,6 +595,11 @@ export async function stopManagedBitcoindServiceWithLockHeld(options) {
|
|
|
590
595
|
}
|
|
591
596
|
export async function withClaimedUninitializedManagedRuntime(options, callback) {
|
|
592
597
|
const targetWalletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
598
|
+
const targetPaths = resolveManagedServicePaths(options.dataDir, targetWalletRootId);
|
|
599
|
+
const uninitializedPaths = resolveManagedServicePaths(options.dataDir, UNINITIALIZED_WALLET_ROOT_ID);
|
|
600
|
+
if (targetPaths.walletRuntimeRoot === uninitializedPaths.walletRuntimeRoot) {
|
|
601
|
+
return callback();
|
|
602
|
+
}
|
|
593
603
|
if (targetWalletRootId === UNINITIALIZED_WALLET_ROOT_ID) {
|
|
594
604
|
return callback();
|
|
595
605
|
}
|
|
@@ -598,7 +608,6 @@ export async function withClaimedUninitializedManagedRuntime(options, callback)
|
|
|
598
608
|
return callback();
|
|
599
609
|
}
|
|
600
610
|
claimedUninitializedRuntimeKeys.add(claimKey);
|
|
601
|
-
const uninitializedPaths = resolveManagedServicePaths(options.dataDir, UNINITIALIZED_WALLET_ROOT_ID);
|
|
602
611
|
const lockTimeoutMs = options.shutdownTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
603
612
|
const bitcoindLock = await acquireFileLockWithRetry(uninitializedPaths.bitcoindLockPath, {
|
|
604
613
|
purpose: "managed-bitcoind-claim-uninitialized",
|
|
@@ -638,12 +647,15 @@ export async function withClaimedUninitializedManagedRuntime(options, callback)
|
|
|
638
647
|
async function refreshManagedBitcoindStatus(status, paths, options) {
|
|
639
648
|
const nowUnixMs = Date.now();
|
|
640
649
|
const rpc = createRpcClient(status.rpc);
|
|
650
|
+
const targetWalletRootId = options.walletRootId ?? status.walletRootId;
|
|
641
651
|
try {
|
|
642
652
|
await waitForRpcReady(rpc, status.rpc.cookieFile, status.chain, options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS);
|
|
643
653
|
await validateNodeConfigForTesting(rpc, status.chain, status.zmq.endpoint);
|
|
644
|
-
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc,
|
|
654
|
+
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc, targetWalletRootId, status.dataDir);
|
|
645
655
|
const nextStatus = {
|
|
646
656
|
...status,
|
|
657
|
+
walletRootId: targetWalletRootId,
|
|
658
|
+
runtimeRoot: paths.walletRuntimeRoot,
|
|
647
659
|
state: "ready",
|
|
648
660
|
processId: await isProcessAlive(status.processId) ? status.processId : null,
|
|
649
661
|
walletReplica,
|
|
@@ -657,6 +669,8 @@ async function refreshManagedBitcoindStatus(status, paths, options) {
|
|
|
657
669
|
catch (error) {
|
|
658
670
|
const nextStatus = {
|
|
659
671
|
...status,
|
|
672
|
+
walletRootId: targetWalletRootId,
|
|
673
|
+
runtimeRoot: paths.walletRuntimeRoot,
|
|
660
674
|
state: "failed",
|
|
661
675
|
processId: await isProcessAlive(status.processId) ? status.processId : null,
|
|
662
676
|
heartbeatAtUnixMs: nowUnixMs,
|
|
@@ -677,6 +691,8 @@ function createNodeHandle(status, paths, options) {
|
|
|
677
691
|
expectedChain: currentStatus.chain,
|
|
678
692
|
startHeight: currentStatus.startHeight,
|
|
679
693
|
dataDir: currentStatus.dataDir,
|
|
694
|
+
getblockArchiveEndHeight: currentStatus.getblockArchiveEndHeight ?? null,
|
|
695
|
+
getblockArchiveSha256: currentStatus.getblockArchiveSha256 ?? null,
|
|
680
696
|
walletRootId: currentStatus.walletRootId,
|
|
681
697
|
runtimeRoot: paths.walletRuntimeRoot,
|
|
682
698
|
async validate() {
|
|
@@ -684,6 +700,9 @@ function createNodeHandle(status, paths, options) {
|
|
|
684
700
|
},
|
|
685
701
|
async refreshServiceStatus() {
|
|
686
702
|
currentStatus = await refreshManagedBitcoindStatus(currentStatus, paths, options);
|
|
703
|
+
this.getblockArchiveEndHeight = currentStatus.getblockArchiveEndHeight ?? null;
|
|
704
|
+
this.getblockArchiveSha256 = currentStatus.getblockArchiveSha256 ?? null;
|
|
705
|
+
this.walletRootId = currentStatus.walletRootId;
|
|
687
706
|
return currentStatus;
|
|
688
707
|
},
|
|
689
708
|
async stop() {
|
|
@@ -786,57 +805,76 @@ export async function attachOrStartManagedBitcoindService(options) {
|
|
|
786
805
|
await verifyBitcoindVersion(bitcoindPath);
|
|
787
806
|
const binaryVersion = SUPPORTED_BITCOIND_VERSION;
|
|
788
807
|
await mkdir(resolvedOptions.dataDir ?? "", { recursive: true });
|
|
789
|
-
const
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
808
|
+
const startManagedProcess = async (startOptions) => {
|
|
809
|
+
const runtimeConfig = await resolveRuntimeConfig(paths.bitcoindStatusPath, paths.bitcoindRuntimeConfigPath, startOptions);
|
|
810
|
+
await writeBitcoinConf(paths.bitcoinConfPath, startOptions, runtimeConfig);
|
|
811
|
+
const rpcConfig = runtimeConfig.rpc;
|
|
812
|
+
const zmqConfig = {
|
|
813
|
+
endpoint: `tcp://${LOCAL_HOST}:${runtimeConfig.zmqPort}`,
|
|
814
|
+
topic: "hashblock",
|
|
815
|
+
port: runtimeConfig.zmqPort,
|
|
816
|
+
pollIntervalMs: startOptions.pollIntervalMs ?? 15_000,
|
|
817
|
+
};
|
|
818
|
+
const child = spawn(bitcoindPath, buildManagedServiceArgs(startOptions, runtimeConfig), {
|
|
819
|
+
detached: true,
|
|
820
|
+
stdio: "ignore",
|
|
821
|
+
});
|
|
822
|
+
child.unref();
|
|
823
|
+
const rpc = createRpcClient(rpcConfig);
|
|
824
|
+
try {
|
|
825
|
+
await waitForRpcReady(rpc, rpcConfig.cookieFile, startOptions.chain, startupTimeoutMs);
|
|
826
|
+
await validateNodeConfigForTesting(rpc, startOptions.chain, zmqConfig.endpoint);
|
|
827
|
+
}
|
|
828
|
+
catch (error) {
|
|
829
|
+
if (child.pid !== undefined) {
|
|
830
|
+
try {
|
|
831
|
+
process.kill(child.pid, "SIGTERM");
|
|
832
|
+
}
|
|
833
|
+
catch {
|
|
834
|
+
// ignore kill failures during startup cleanup
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
throw error;
|
|
838
|
+
}
|
|
839
|
+
const nowUnixMs = Date.now();
|
|
840
|
+
const walletRootId = startOptions.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
841
|
+
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc, walletRootId, startOptions.dataDir ?? "");
|
|
842
|
+
return createBitcoindServiceStatus({
|
|
843
|
+
binaryVersion,
|
|
844
|
+
serviceInstanceId: randomBytes(16).toString("hex"),
|
|
845
|
+
state: "ready",
|
|
846
|
+
processId: child.pid ?? null,
|
|
847
|
+
walletRootId,
|
|
848
|
+
chain: startOptions.chain,
|
|
849
|
+
dataDir: startOptions.dataDir ?? "",
|
|
850
|
+
runtimeRoot: paths.walletRuntimeRoot,
|
|
851
|
+
startHeight: startOptions.startHeight,
|
|
852
|
+
rpc: rpcConfig,
|
|
853
|
+
zmq: zmqConfig,
|
|
854
|
+
p2pPort: runtimeConfig.p2pPort,
|
|
855
|
+
getblockArchiveEndHeight: runtimeConfig.getblockArchiveEndHeight ?? null,
|
|
856
|
+
getblockArchiveSha256: runtimeConfig.getblockArchiveSha256 ?? null,
|
|
857
|
+
walletReplica,
|
|
858
|
+
startedAtUnixMs: nowUnixMs,
|
|
859
|
+
heartbeatAtUnixMs: nowUnixMs,
|
|
860
|
+
lastError: walletReplica.message ?? null,
|
|
861
|
+
});
|
|
797
862
|
};
|
|
798
|
-
|
|
799
|
-
detached: true,
|
|
800
|
-
stdio: "ignore",
|
|
801
|
-
});
|
|
802
|
-
child.unref();
|
|
803
|
-
const rpc = createRpcClient(rpcConfig);
|
|
863
|
+
let status;
|
|
804
864
|
try {
|
|
805
|
-
await
|
|
806
|
-
await validateNodeConfigForTesting(rpc, resolvedOptions.chain, zmqConfig.endpoint);
|
|
865
|
+
status = await startManagedProcess(resolvedOptions);
|
|
807
866
|
}
|
|
808
867
|
catch (error) {
|
|
809
|
-
if (
|
|
810
|
-
|
|
811
|
-
process.kill(child.pid, "SIGTERM");
|
|
812
|
-
}
|
|
813
|
-
catch {
|
|
814
|
-
// ignore kill failures during startup cleanup
|
|
815
|
-
}
|
|
868
|
+
if (resolvedOptions.getblockArchivePath === undefined || resolvedOptions.getblockArchivePath === null) {
|
|
869
|
+
throw error;
|
|
816
870
|
}
|
|
817
|
-
|
|
871
|
+
status = await startManagedProcess({
|
|
872
|
+
...resolvedOptions,
|
|
873
|
+
getblockArchivePath: null,
|
|
874
|
+
getblockArchiveEndHeight: null,
|
|
875
|
+
getblockArchiveSha256: null,
|
|
876
|
+
});
|
|
818
877
|
}
|
|
819
|
-
const nowUnixMs = Date.now();
|
|
820
|
-
const walletRootId = resolvedOptions.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
821
|
-
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc, walletRootId, resolvedOptions.dataDir ?? "");
|
|
822
|
-
const status = createBitcoindServiceStatus({
|
|
823
|
-
binaryVersion,
|
|
824
|
-
serviceInstanceId: randomBytes(16).toString("hex"),
|
|
825
|
-
state: "ready",
|
|
826
|
-
processId: child.pid ?? null,
|
|
827
|
-
walletRootId,
|
|
828
|
-
chain: resolvedOptions.chain,
|
|
829
|
-
dataDir: resolvedOptions.dataDir ?? "",
|
|
830
|
-
runtimeRoot: paths.walletRuntimeRoot,
|
|
831
|
-
startHeight: resolvedOptions.startHeight,
|
|
832
|
-
rpc: rpcConfig,
|
|
833
|
-
zmq: zmqConfig,
|
|
834
|
-
p2pPort: runtimeConfig.p2pPort,
|
|
835
|
-
walletReplica,
|
|
836
|
-
startedAtUnixMs: nowUnixMs,
|
|
837
|
-
heartbeatAtUnixMs: nowUnixMs,
|
|
838
|
-
lastError: walletReplica.message ?? null,
|
|
839
|
-
});
|
|
840
878
|
await writeBitcoindStatus(paths, status);
|
|
841
879
|
return createNodeHandle(status, paths, resolvedOptions);
|
|
842
880
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export { openManagedBitcoindClientInternal } from "./client.js";
|
|
2
|
+
export { DefaultManagedBitcoindClient } from "./client/managed-client.js";
|
|
2
3
|
export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, stopIndexerDaemonService, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
|
|
3
4
|
export { normalizeRpcBlock } from "./normalize.js";
|
|
4
5
|
export { BitcoinRpcClient } from "./rpc.js";
|
|
5
6
|
export { attachOrStartManagedBitcoindService, buildManagedServiceArgsForTesting, readManagedBitcoindServiceStatusForTesting, resolveManagedBitcoindDbcacheMiB, stopManagedBitcoindService, shutdownManagedBitcoindServiceForTesting, writeBitcoinConfForTesting, } from "./service.js";
|
|
6
|
-
export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, resolveBootstrapPathsForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
|
|
7
|
+
export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, prepareLatestGetblockArchiveForTesting, resolveBootstrapPathsForTesting, resolveGetblockArchivePathsForTesting, resolveReadyGetblockArchiveForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForGetblockArchiveImportForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
|
|
7
8
|
export { buildBitcoindArgsForTesting, createRpcClient, launchManagedBitcoindNode, resolveDefaultBitcoindDataDirForTesting, validateNodeConfigForTesting, } from "./node.js";
|
|
8
9
|
export { ManagedProgressController, TtyProgressRenderer, advanceFollowSceneStateForTesting, createFollowSceneStateForTesting, createBootstrapProgressForTesting, formatCompactFollowAgeLabelForTesting, loadBannerArtForTesting, loadScrollArtForTesting, loadTrainCarArtForTesting, loadTrainArtForTesting, loadTrainSmokeArtForTesting, formatProgressLineForTesting, formatQuoteLineForTesting, renderArtFrameForTesting, renderCompletionFrameForTesting, renderFollowFrameForTesting, renderIntroFrameForTesting, resolveCompletionMessageForTesting, resolveIntroMessageForTesting, resolveStatusFieldTextForTesting, setFollowBlockTimeForTesting, setFollowBlockTimesForTesting, syncFollowSceneStateForTesting, } from "./progress.js";
|
|
9
10
|
export { WritingQuoteRotator, loadWritingQuotesForTesting, shuffleIndicesForTesting, } from "./quotes.js";
|
package/dist/bitcoind/testing.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export { openManagedBitcoindClientInternal } from "./client.js";
|
|
2
|
+
export { DefaultManagedBitcoindClient } from "./client/managed-client.js";
|
|
2
3
|
export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, stopIndexerDaemonService, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
|
|
3
4
|
export { normalizeRpcBlock } from "./normalize.js";
|
|
4
5
|
export { BitcoinRpcClient } from "./rpc.js";
|
|
5
6
|
export { attachOrStartManagedBitcoindService, buildManagedServiceArgsForTesting, readManagedBitcoindServiceStatusForTesting, resolveManagedBitcoindDbcacheMiB, stopManagedBitcoindService, shutdownManagedBitcoindServiceForTesting, writeBitcoinConfForTesting, } from "./service.js";
|
|
6
|
-
export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, resolveBootstrapPathsForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
|
|
7
|
+
export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, prepareLatestGetblockArchiveForTesting, resolveBootstrapPathsForTesting, resolveGetblockArchivePathsForTesting, resolveReadyGetblockArchiveForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForGetblockArchiveImportForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
|
|
7
8
|
export { buildBitcoindArgsForTesting, createRpcClient, launchManagedBitcoindNode, resolveDefaultBitcoindDataDirForTesting, validateNodeConfigForTesting, } from "./node.js";
|
|
8
9
|
export { ManagedProgressController, TtyProgressRenderer, advanceFollowSceneStateForTesting, createFollowSceneStateForTesting, createBootstrapProgressForTesting, formatCompactFollowAgeLabelForTesting, loadBannerArtForTesting, loadScrollArtForTesting, loadTrainCarArtForTesting, loadTrainArtForTesting, loadTrainSmokeArtForTesting, formatProgressLineForTesting, formatQuoteLineForTesting, renderArtFrameForTesting, renderCompletionFrameForTesting, renderFollowFrameForTesting, renderIntroFrameForTesting, resolveCompletionMessageForTesting, resolveIntroMessageForTesting, resolveStatusFieldTextForTesting, setFollowBlockTimeForTesting, setFollowBlockTimesForTesting, syncFollowSceneStateForTesting, } from "./progress.js";
|
|
9
10
|
export { WritingQuoteRotator, loadWritingQuotesForTesting, shuffleIndicesForTesting, } from "./quotes.js";
|
package/dist/bitcoind/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BitcoinBlock, Client, ClientOptions, ClientTip } from "../types.js";
|
|
2
|
-
export type BootstrapPhase = "snapshot_download" | "wait_headers_for_snapshot" | "load_snapshot" | "bitcoin_sync" | "cogcoin_sync" | "follow_tip" | "paused" | "error" | "complete";
|
|
2
|
+
export type BootstrapPhase = "getblock_archive_download" | "getblock_archive_import" | "snapshot_download" | "wait_headers_for_snapshot" | "load_snapshot" | "bitcoin_sync" | "cogcoin_sync" | "follow_tip" | "paused" | "error" | "complete";
|
|
3
3
|
export type ProgressOutputMode = "auto" | "tty" | "none";
|
|
4
4
|
export interface SnapshotMetadata {
|
|
5
5
|
url: string;
|
|
@@ -17,6 +17,28 @@ export interface SnapshotChunkManifest {
|
|
|
17
17
|
snapshotSha256: string;
|
|
18
18
|
chunkSha256s: string[];
|
|
19
19
|
}
|
|
20
|
+
export interface GetblockArchiveManifestBlockRecord {
|
|
21
|
+
height: number;
|
|
22
|
+
blockHash: string;
|
|
23
|
+
previousBlockHash: string;
|
|
24
|
+
recordOffset: number;
|
|
25
|
+
recordLength: number;
|
|
26
|
+
rawBlockSizeBytes: number;
|
|
27
|
+
}
|
|
28
|
+
export interface GetblockArchiveManifest {
|
|
29
|
+
formatVersion: number;
|
|
30
|
+
chain: "main";
|
|
31
|
+
baseSnapshotHeight: number;
|
|
32
|
+
firstBlockHeight: number;
|
|
33
|
+
endHeight: number;
|
|
34
|
+
blockCount: number;
|
|
35
|
+
artifactFilename: string;
|
|
36
|
+
artifactSizeBytes: number;
|
|
37
|
+
artifactSha256: string;
|
|
38
|
+
chunkSizeBytes: number;
|
|
39
|
+
chunkSha256s: string[];
|
|
40
|
+
blocks: GetblockArchiveManifestBlockRecord[];
|
|
41
|
+
}
|
|
20
42
|
export interface WritingQuote {
|
|
21
43
|
quote: string;
|
|
22
44
|
author: string;
|
|
@@ -63,6 +85,8 @@ export interface ManagedBitcoindRuntimeConfig {
|
|
|
63
85
|
zmqPort: number;
|
|
64
86
|
p2pPort: number;
|
|
65
87
|
dbcacheMiB: number;
|
|
88
|
+
getblockArchiveEndHeight?: number | null;
|
|
89
|
+
getblockArchiveSha256?: string | null;
|
|
66
90
|
}
|
|
67
91
|
export declare const MANAGED_BITCOIND_SERVICE_API_VERSION = "cogcoin/bitcoind-service/v1";
|
|
68
92
|
export type ManagedBitcoindServiceState = "starting" | "ready" | "stopping" | "failed";
|
|
@@ -81,6 +105,8 @@ export interface ManagedBitcoindServiceStatus {
|
|
|
81
105
|
rpc: BitcoindRpcConfig;
|
|
82
106
|
zmq: BitcoindZmqConfig;
|
|
83
107
|
p2pPort: number;
|
|
108
|
+
getblockArchiveEndHeight: number | null;
|
|
109
|
+
getblockArchiveSha256: string | null;
|
|
84
110
|
walletReplica: ManagedCoreWalletReplicaStatus | null;
|
|
85
111
|
startedAtUnixMs: number;
|
|
86
112
|
heartbeatAtUnixMs: number;
|
|
@@ -123,6 +149,10 @@ export interface ManagedBitcoindStatus {
|
|
|
123
149
|
serviceStatus?: ManagedBitcoindObservedStatus | null;
|
|
124
150
|
indexerDaemon?: ManagedIndexerDaemonObservedStatus | null;
|
|
125
151
|
}
|
|
152
|
+
export interface ManagedGetblockArchiveRestartRequest {
|
|
153
|
+
currentArchiveEndHeight: number | null;
|
|
154
|
+
nextArchiveEndHeight: number;
|
|
155
|
+
}
|
|
126
156
|
export interface ManagedBitcoindOptions extends ClientOptions {
|
|
127
157
|
dataDir?: string;
|
|
128
158
|
databasePath?: string;
|
|
@@ -137,6 +167,8 @@ export interface ManagedBitcoindOptions extends ClientOptions {
|
|
|
137
167
|
managedWalletPassphrase?: string;
|
|
138
168
|
onProgress?: (event: ManagedBitcoindProgressEvent) => void;
|
|
139
169
|
progressOutput?: ProgressOutputMode;
|
|
170
|
+
fetchImpl?: typeof fetch;
|
|
171
|
+
confirmGetblockArchiveRestart?: (request: ManagedGetblockArchiveRestartRequest) => Promise<boolean>;
|
|
140
172
|
}
|
|
141
173
|
export interface ManagedBitcoindClient extends Client {
|
|
142
174
|
syncToTip(): Promise<SyncResult>;
|
|
@@ -397,6 +429,8 @@ export interface ManagedBitcoindNodeHandle {
|
|
|
397
429
|
expectedChain: "main" | "regtest";
|
|
398
430
|
startHeight: number;
|
|
399
431
|
dataDir: string;
|
|
432
|
+
getblockArchiveEndHeight: number | null;
|
|
433
|
+
getblockArchiveSha256: string | null;
|
|
400
434
|
walletRootId?: string;
|
|
401
435
|
runtimeRoot?: string;
|
|
402
436
|
validate(): Promise<void>;
|
|
@@ -3,6 +3,7 @@ import { resolveWalletRootIdFromLocalArtifacts } from "../../wallet/root-resolut
|
|
|
3
3
|
import { usesTtyProgress, writeLine } from "../io.js";
|
|
4
4
|
import { classifyCliError } from "../output.js";
|
|
5
5
|
import { createStopSignalWatcher } from "../signals.js";
|
|
6
|
+
import { confirmGetblockArchiveRestart } from "./getblock-archive-restart.js";
|
|
6
7
|
export async function runFollowCommand(parsed, context) {
|
|
7
8
|
const dbPath = parsed.dbPath ?? context.resolveDefaultClientDatabasePath();
|
|
8
9
|
const dataDir = parsed.dataDir ?? context.resolveDefaultBitcoindDataDir();
|
|
@@ -23,6 +24,7 @@ export async function runFollowCommand(parsed, context) {
|
|
|
23
24
|
dataDir,
|
|
24
25
|
walletRootId: walletRoot.walletRootId,
|
|
25
26
|
progressOutput: parsed.progressOutput,
|
|
27
|
+
confirmGetblockArchiveRestart: async (options) => confirmGetblockArchiveRestart(parsed, context, options),
|
|
26
28
|
});
|
|
27
29
|
storeOwned = false;
|
|
28
30
|
const stopWatcher = createStopSignalWatcher(context.signalSource, context.stderr, client, context.forceExit);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ParsedCliArgs, RequiredCliRunnerContext } from "../types.js";
|
|
2
|
+
export declare function confirmGetblockArchiveRestart(parsed: ParsedCliArgs, context: RequiredCliRunnerContext, options: {
|
|
3
|
+
currentArchiveEndHeight: number | null;
|
|
4
|
+
nextArchiveEndHeight: number;
|
|
5
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export async function confirmGetblockArchiveRestart(parsed, context, options) {
|
|
2
|
+
if (parsed.assumeYes) {
|
|
3
|
+
return true;
|
|
4
|
+
}
|
|
5
|
+
const prompter = context.createPrompter();
|
|
6
|
+
if (!prompter.isInteractive) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const currentLabel = options.currentArchiveEndHeight === null
|
|
10
|
+
? "without a getblock archive"
|
|
11
|
+
: `with a getblock archive through height ${options.currentArchiveEndHeight.toLocaleString()}`;
|
|
12
|
+
prompter.writeLine(`Managed bitcoind is already running ${currentLabel}. A newer getblock archive through height ${options.nextArchiveEndHeight.toLocaleString()} is available.`);
|
|
13
|
+
const answer = (await prompter.prompt(`Restart managed bitcoind to load the getblock archive through height ${options.nextArchiveEndHeight.toLocaleString()}? [y/N]: `)).trim().toLowerCase();
|
|
14
|
+
return answer === "y" || answer === "yes";
|
|
15
|
+
}
|
|
@@ -12,11 +12,13 @@ function createCommandPrompter(parsed, context) {
|
|
|
12
12
|
export async function runMiningAdminCommand(parsed, context) {
|
|
13
13
|
try {
|
|
14
14
|
const provider = context.walletSecretProvider;
|
|
15
|
+
const runtimePaths = context.resolveWalletRuntimePaths(parsed.seedName);
|
|
15
16
|
if (parsed.command === "hooks-mining-enable") {
|
|
16
17
|
const prompter = createCommandPrompter(parsed, context);
|
|
17
18
|
const view = await context.enableMiningHooks({
|
|
18
19
|
provider,
|
|
19
20
|
prompter,
|
|
21
|
+
paths: runtimePaths,
|
|
20
22
|
});
|
|
21
23
|
const nextSteps = getHooksEnableMiningNextSteps();
|
|
22
24
|
if (parsed.outputMode === "preview-json") {
|
|
@@ -40,6 +42,7 @@ export async function runMiningAdminCommand(parsed, context) {
|
|
|
40
42
|
if (parsed.command === "hooks-mining-disable") {
|
|
41
43
|
const view = await context.disableMiningHooks({
|
|
42
44
|
provider,
|
|
45
|
+
paths: runtimePaths,
|
|
43
46
|
});
|
|
44
47
|
if (parsed.outputMode === "preview-json") {
|
|
45
48
|
writeJsonValue(context.stdout, createPreviewSuccessEnvelope(resolvePreviewJsonSchema(parsed), describeCanonicalCommand(parsed), "disabled", buildHooksPreviewData("hooks-disable-mining", view)));
|
|
@@ -57,6 +60,7 @@ export async function runMiningAdminCommand(parsed, context) {
|
|
|
57
60
|
const view = await context.setupBuiltInMining({
|
|
58
61
|
provider,
|
|
59
62
|
prompter,
|
|
63
|
+
paths: runtimePaths,
|
|
60
64
|
});
|
|
61
65
|
const nextSteps = getMineSetupNextSteps();
|
|
62
66
|
if (parsed.outputMode === "preview-json") {
|