@cogcoin/client 0.5.5 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/dist/bitcoind/bootstrap/chainstate.d.ts +2 -1
- package/dist/bitcoind/bootstrap/chainstate.js +4 -1
- package/dist/bitcoind/bootstrap/controller.d.ts +4 -1
- package/dist/bitcoind/bootstrap/controller.js +42 -5
- package/dist/bitcoind/bootstrap/getblock-archive.d.ts +39 -0
- package/dist/bitcoind/bootstrap/getblock-archive.js +548 -0
- package/dist/bitcoind/bootstrap/headers.d.ts +12 -0
- package/dist/bitcoind/bootstrap/headers.js +95 -10
- package/dist/bitcoind/bootstrap.d.ts +1 -0
- package/dist/bitcoind/bootstrap.js +1 -0
- package/dist/bitcoind/client/factory.js +91 -28
- package/dist/bitcoind/client/managed-client.d.ts +1 -1
- package/dist/bitcoind/client/managed-client.js +4 -3
- package/dist/bitcoind/client/sync-engine.js +55 -13
- package/dist/bitcoind/errors.js +18 -0
- package/dist/bitcoind/indexer-daemon-main.js +78 -0
- package/dist/bitcoind/indexer-daemon.d.ts +10 -1
- package/dist/bitcoind/indexer-daemon.js +44 -28
- package/dist/bitcoind/node.js +2 -0
- package/dist/bitcoind/processing-start-height.d.ts +7 -0
- package/dist/bitcoind/processing-start-height.js +9 -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 +49 -23
- package/dist/bitcoind/progress/formatting.js +29 -1
- package/dist/bitcoind/progress/render-policy.d.ts +35 -0
- package/dist/bitcoind/progress/render-policy.js +81 -0
- package/dist/bitcoind/retryable-rpc.d.ts +11 -0
- package/dist/bitcoind/retryable-rpc.js +30 -0
- package/dist/bitcoind/service-paths.js +2 -6
- package/dist/bitcoind/service.d.ts +21 -2
- package/dist/bitcoind/service.js +274 -122
- package/dist/bitcoind/testing.d.ts +2 -2
- package/dist/bitcoind/testing.js +2 -2
- package/dist/bitcoind/types.d.ts +36 -1
- package/dist/cli/commands/follow.js +11 -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/service-runtime.js +150 -134
- package/dist/cli/commands/status.js +2 -0
- package/dist/cli/commands/sync.js +11 -0
- package/dist/cli/commands/wallet-admin.js +106 -24
- package/dist/cli/commands/wallet-mutation.js +57 -4
- package/dist/cli/commands/wallet-read.js +2 -0
- package/dist/cli/context.js +8 -4
- 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 +49 -0
- package/dist/cli/mutation-success.d.ts +1 -0
- package/dist/cli/mutation-success.js +2 -2
- package/dist/cli/output.js +86 -1
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +133 -3
- package/dist/cli/preview-json.d.ts +10 -1
- package/dist/cli/preview-json.js +32 -0
- package/dist/cli/prompt.js +1 -1
- package/dist/cli/runner.js +4 -0
- package/dist/cli/types.d.ts +15 -5
- package/dist/cli/types.js +1 -1
- package/dist/cli/wallet-format.js +140 -14
- package/dist/wallet/lifecycle.d.ts +21 -1
- package/dist/wallet/lifecycle.js +252 -116
- package/dist/wallet/mining/visualizer.d.ts +11 -6
- package/dist/wallet/mining/visualizer.js +32 -15
- package/dist/wallet/read/context.js +10 -4
- package/dist/wallet/reset.d.ts +61 -2
- package/dist/wallet/reset.js +246 -89
- package/dist/wallet/root-resolution.d.ts +20 -0
- package/dist/wallet/root-resolution.js +37 -0
- package/dist/wallet/runtime.d.ts +13 -1
- package/dist/wallet/runtime.js +54 -11
- package/dist/wallet/state/crypto.d.ts +3 -0
- package/dist/wallet/state/crypto.js +3 -0
- 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/state/storage.d.ts +7 -1
- package/dist/wallet/state/storage.js +39 -0
- package/dist/wallet/tx/anchor.d.ts +22 -0
- package/dist/wallet/tx/anchor.js +215 -8
- package/dist/wallet/tx/index.d.ts +1 -1
- package/dist/wallet/tx/index.js +1 -1
- package/dist/wallet/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/bitcoind/service.js
CHANGED
|
@@ -2,12 +2,14 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { execFile, spawn } from "node:child_process";
|
|
3
3
|
import { access, constants, mkdir, readFile, readdir, rm } from "node:fs/promises";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
|
+
import { totalmem } from "node:os";
|
|
5
6
|
import { promisify } from "node:util";
|
|
6
7
|
import net from "node:net";
|
|
7
8
|
import { getBitcoindPath } from "@cogcoin/bitcoin";
|
|
8
9
|
import { acquireFileLock, FileLockBusyError } from "../wallet/fs/lock.js";
|
|
9
10
|
import { writeFileAtomic } from "../wallet/fs/atomic.js";
|
|
10
11
|
import { writeRuntimeStatusFile } from "../wallet/fs/status-file.js";
|
|
12
|
+
import { stopIndexerDaemonServiceWithLockHeld } from "./indexer-daemon.js";
|
|
11
13
|
import { createRpcClient, validateNodeConfigForTesting } from "./node.js";
|
|
12
14
|
import { resolveManagedServicePaths, UNINITIALIZED_WALLET_ROOT_ID } from "./service-paths.js";
|
|
13
15
|
import { MANAGED_BITCOIND_SERVICE_API_VERSION as MANAGED_BITCOIND_SERVICE_API_VERSION_VALUE } from "./types.js";
|
|
@@ -16,6 +18,32 @@ const LOCAL_HOST = "127.0.0.1";
|
|
|
16
18
|
const SUPPORTED_BITCOIND_VERSION = "30.2.0";
|
|
17
19
|
const DEFAULT_STARTUP_TIMEOUT_MS = 30_000;
|
|
18
20
|
const DEFAULT_SHUTDOWN_TIMEOUT_MS = 15_000;
|
|
21
|
+
const DEFAULT_DBCACHE_MIB = 450;
|
|
22
|
+
const claimedUninitializedRuntimeKeys = new Set();
|
|
23
|
+
const GIB = 1024 ** 3;
|
|
24
|
+
export function resolveManagedBitcoindDbcacheMiB(totalRamBytes) {
|
|
25
|
+
if (!Number.isFinite(totalRamBytes) || totalRamBytes <= 0) {
|
|
26
|
+
return DEFAULT_DBCACHE_MIB;
|
|
27
|
+
}
|
|
28
|
+
if (totalRamBytes < 8 * GIB) {
|
|
29
|
+
return 450;
|
|
30
|
+
}
|
|
31
|
+
if (totalRamBytes < 16 * GIB) {
|
|
32
|
+
return 768;
|
|
33
|
+
}
|
|
34
|
+
if (totalRamBytes < 32 * GIB) {
|
|
35
|
+
return 1024;
|
|
36
|
+
}
|
|
37
|
+
return 2048;
|
|
38
|
+
}
|
|
39
|
+
function detectManagedBitcoindDbcacheMiB() {
|
|
40
|
+
try {
|
|
41
|
+
return resolveManagedBitcoindDbcacheMiB(totalmem());
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return DEFAULT_DBCACHE_MIB;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
19
47
|
function sleep(ms) {
|
|
20
48
|
return new Promise((resolve) => {
|
|
21
49
|
setTimeout(resolve, ms);
|
|
@@ -31,6 +59,20 @@ async function waitForProcessExit(pid, timeoutMs, errorCode) {
|
|
|
31
59
|
}
|
|
32
60
|
throw new Error(errorCode);
|
|
33
61
|
}
|
|
62
|
+
async function acquireFileLockWithRetry(lockPath, metadata, timeoutMs) {
|
|
63
|
+
const deadline = Date.now() + timeoutMs;
|
|
64
|
+
while (true) {
|
|
65
|
+
try {
|
|
66
|
+
return await acquireFileLock(lockPath, metadata);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (!(error instanceof FileLockBusyError) || Date.now() >= deadline) {
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
await sleep(250);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
34
76
|
function getWalletReplicaName(walletRootId) {
|
|
35
77
|
return `cogcoin-${walletRootId}`.replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 63);
|
|
36
78
|
}
|
|
@@ -184,15 +226,14 @@ async function waitForRpcReady(rpc, cookieFile, expectedChain, timeoutMs) {
|
|
|
184
226
|
throw lastError instanceof Error ? lastError : new Error("bitcoind_rpc_timeout");
|
|
185
227
|
}
|
|
186
228
|
function validateManagedBitcoindStatus(status, options, runtimeRoot) {
|
|
229
|
+
const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
230
|
+
const legacyRuntimeRoot = join(resolveManagedServicePaths(options.dataDir ?? "", walletRootId).runtimeRoot, walletRootId);
|
|
187
231
|
if (status.serviceApiVersion !== MANAGED_BITCOIND_SERVICE_API_VERSION_VALUE) {
|
|
188
232
|
throw new Error("managed_bitcoind_service_version_mismatch");
|
|
189
233
|
}
|
|
190
|
-
if (status.walletRootId !== (options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID)) {
|
|
191
|
-
throw new Error("managed_bitcoind_wallet_root_mismatch");
|
|
192
|
-
}
|
|
193
234
|
if (status.chain !== options.chain
|
|
194
235
|
|| status.dataDir !== (options.dataDir ?? "")
|
|
195
|
-
|| status.runtimeRoot !== runtimeRoot) {
|
|
236
|
+
|| (status.runtimeRoot !== runtimeRoot && status.runtimeRoot !== legacyRuntimeRoot)) {
|
|
196
237
|
throw new Error("managed_bitcoind_runtime_mismatch");
|
|
197
238
|
}
|
|
198
239
|
}
|
|
@@ -233,6 +274,8 @@ function createBitcoindServiceStatus(options) {
|
|
|
233
274
|
rpc: options.rpc,
|
|
234
275
|
zmq: options.zmq,
|
|
235
276
|
p2pPort: options.p2pPort,
|
|
277
|
+
getblockArchiveEndHeight: options.getblockArchiveEndHeight,
|
|
278
|
+
getblockArchiveSha256: options.getblockArchiveSha256,
|
|
236
279
|
walletReplica: options.walletReplica,
|
|
237
280
|
startedAtUnixMs: options.startedAtUnixMs,
|
|
238
281
|
heartbeatAtUnixMs: options.heartbeatAtUnixMs,
|
|
@@ -245,9 +288,7 @@ function mapManagedBitcoindValidationError(error) {
|
|
|
245
288
|
compatibility: error instanceof Error
|
|
246
289
|
? error.message === "managed_bitcoind_service_version_mismatch"
|
|
247
290
|
? "service-version-mismatch"
|
|
248
|
-
:
|
|
249
|
-
? "wallet-root-mismatch"
|
|
250
|
-
: "runtime-mismatch"
|
|
291
|
+
: "runtime-mismatch"
|
|
251
292
|
: "protocol-error",
|
|
252
293
|
status: null,
|
|
253
294
|
error: error instanceof Error ? error.message : "managed_bitcoind_protocol_error",
|
|
@@ -323,6 +364,9 @@ async function resolveRuntimeConfig(statusPath, configPath, options) {
|
|
|
323
364
|
},
|
|
324
365
|
zmqPort,
|
|
325
366
|
p2pPort,
|
|
367
|
+
dbcacheMiB: detectManagedBitcoindDbcacheMiB(),
|
|
368
|
+
getblockArchiveEndHeight: options.getblockArchiveEndHeight ?? null,
|
|
369
|
+
getblockArchiveSha256: options.getblockArchiveSha256 ?? null,
|
|
326
370
|
};
|
|
327
371
|
}
|
|
328
372
|
async function writeBitcoinConf(filePath, options, runtimeConfig) {
|
|
@@ -334,6 +378,7 @@ async function writeBitcoinConf(filePath, options, runtimeConfig) {
|
|
|
334
378
|
"prune=0",
|
|
335
379
|
"dnsseed=1",
|
|
336
380
|
"listen=0",
|
|
381
|
+
`dbcache=${runtimeConfig.dbcacheMiB}`,
|
|
337
382
|
`rpcbind=${LOCAL_HOST}`,
|
|
338
383
|
`rpcallowip=${LOCAL_HOST}`,
|
|
339
384
|
`rpcport=${runtimeConfig.rpc.port}`,
|
|
@@ -358,12 +403,22 @@ function buildManagedServiceArgs(options, runtimeConfig) {
|
|
|
358
403
|
"-prune=0",
|
|
359
404
|
"-dnsseed=1",
|
|
360
405
|
"-listen=0",
|
|
406
|
+
`-dbcache=${runtimeConfig.dbcacheMiB}`,
|
|
361
407
|
];
|
|
362
408
|
if (options.chain === "regtest") {
|
|
363
409
|
args.push("-chain=regtest");
|
|
364
410
|
}
|
|
411
|
+
if (options.getblockArchivePath !== undefined && options.getblockArchivePath !== null) {
|
|
412
|
+
args.push(`-loadblock=${options.getblockArchivePath}`);
|
|
413
|
+
}
|
|
365
414
|
return args;
|
|
366
415
|
}
|
|
416
|
+
export async function writeBitcoinConfForTesting(filePath, options, runtimeConfig) {
|
|
417
|
+
await writeBitcoinConf(filePath, options, runtimeConfig);
|
|
418
|
+
}
|
|
419
|
+
export function buildManagedServiceArgsForTesting(options, runtimeConfig) {
|
|
420
|
+
return buildManagedServiceArgs(options, runtimeConfig);
|
|
421
|
+
}
|
|
367
422
|
function isMissingWalletError(message) {
|
|
368
423
|
return message.includes("bitcoind_rpc_loadwallet_-18_")
|
|
369
424
|
|| message.includes("Path does not exist")
|
|
@@ -496,6 +551,8 @@ async function writeBitcoindStatus(paths, status) {
|
|
|
496
551
|
rpc: status.rpc,
|
|
497
552
|
zmqPort: status.zmq.port,
|
|
498
553
|
p2pPort: status.p2pPort,
|
|
554
|
+
getblockArchiveEndHeight: status.getblockArchiveEndHeight,
|
|
555
|
+
getblockArchiveSha256: status.getblockArchiveSha256,
|
|
499
556
|
});
|
|
500
557
|
}
|
|
501
558
|
async function clearManagedBitcoindRuntimeArtifacts(paths) {
|
|
@@ -504,15 +561,102 @@ async function clearManagedBitcoindRuntimeArtifacts(paths) {
|
|
|
504
561
|
await rm(paths.bitcoindReadyPath, { force: true }).catch(() => undefined);
|
|
505
562
|
await rm(paths.bitcoindWalletStatusPath, { force: true }).catch(() => undefined);
|
|
506
563
|
}
|
|
564
|
+
export async function stopManagedBitcoindServiceWithLockHeld(options) {
|
|
565
|
+
const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
566
|
+
const paths = options.paths ?? resolveManagedServicePaths(options.dataDir, walletRootId);
|
|
567
|
+
const status = await readJsonFile(paths.bitcoindStatusPath);
|
|
568
|
+
const processId = status?.processId ?? null;
|
|
569
|
+
if (status === null || processId === null || !await isProcessAlive(processId)) {
|
|
570
|
+
await clearManagedBitcoindRuntimeArtifacts(paths);
|
|
571
|
+
return {
|
|
572
|
+
status: "not-running",
|
|
573
|
+
walletRootId,
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
const rpc = createRpcClient(status.rpc);
|
|
577
|
+
try {
|
|
578
|
+
await rpc.stop();
|
|
579
|
+
}
|
|
580
|
+
catch {
|
|
581
|
+
try {
|
|
582
|
+
process.kill(processId, "SIGTERM");
|
|
583
|
+
}
|
|
584
|
+
catch (error) {
|
|
585
|
+
if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) {
|
|
586
|
+
throw error;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
await waitForProcessExit(processId, options.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS, "managed_bitcoind_service_stop_timeout");
|
|
591
|
+
await clearManagedBitcoindRuntimeArtifacts(paths);
|
|
592
|
+
return {
|
|
593
|
+
status: "stopped",
|
|
594
|
+
walletRootId,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
export async function withClaimedUninitializedManagedRuntime(options, callback) {
|
|
598
|
+
const targetWalletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
599
|
+
const targetPaths = resolveManagedServicePaths(options.dataDir, targetWalletRootId);
|
|
600
|
+
const uninitializedPaths = resolveManagedServicePaths(options.dataDir, UNINITIALIZED_WALLET_ROOT_ID);
|
|
601
|
+
if (targetPaths.walletRuntimeRoot === uninitializedPaths.walletRuntimeRoot) {
|
|
602
|
+
return callback();
|
|
603
|
+
}
|
|
604
|
+
if (targetWalletRootId === UNINITIALIZED_WALLET_ROOT_ID) {
|
|
605
|
+
return callback();
|
|
606
|
+
}
|
|
607
|
+
const claimKey = `${options.dataDir}\n${targetWalletRootId}`;
|
|
608
|
+
if (claimedUninitializedRuntimeKeys.has(claimKey)) {
|
|
609
|
+
return callback();
|
|
610
|
+
}
|
|
611
|
+
claimedUninitializedRuntimeKeys.add(claimKey);
|
|
612
|
+
const lockTimeoutMs = options.shutdownTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
613
|
+
const bitcoindLock = await acquireFileLockWithRetry(uninitializedPaths.bitcoindLockPath, {
|
|
614
|
+
purpose: "managed-bitcoind-claim-uninitialized",
|
|
615
|
+
walletRootId: UNINITIALIZED_WALLET_ROOT_ID,
|
|
616
|
+
dataDir: options.dataDir,
|
|
617
|
+
}, lockTimeoutMs);
|
|
618
|
+
try {
|
|
619
|
+
const indexerLock = await acquireFileLockWithRetry(uninitializedPaths.indexerDaemonLockPath, {
|
|
620
|
+
purpose: "managed-indexer-claim-uninitialized",
|
|
621
|
+
walletRootId: UNINITIALIZED_WALLET_ROOT_ID,
|
|
622
|
+
dataDir: options.dataDir,
|
|
623
|
+
}, lockTimeoutMs);
|
|
624
|
+
try {
|
|
625
|
+
await stopIndexerDaemonServiceWithLockHeld({
|
|
626
|
+
dataDir: options.dataDir,
|
|
627
|
+
walletRootId: UNINITIALIZED_WALLET_ROOT_ID,
|
|
628
|
+
shutdownTimeoutMs: options.shutdownTimeoutMs,
|
|
629
|
+
paths: uninitializedPaths,
|
|
630
|
+
});
|
|
631
|
+
await stopManagedBitcoindServiceWithLockHeld({
|
|
632
|
+
dataDir: options.dataDir,
|
|
633
|
+
walletRootId: UNINITIALIZED_WALLET_ROOT_ID,
|
|
634
|
+
shutdownTimeoutMs: options.shutdownTimeoutMs,
|
|
635
|
+
paths: uninitializedPaths,
|
|
636
|
+
});
|
|
637
|
+
return await callback();
|
|
638
|
+
}
|
|
639
|
+
finally {
|
|
640
|
+
await indexerLock.release();
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
finally {
|
|
644
|
+
claimedUninitializedRuntimeKeys.delete(claimKey);
|
|
645
|
+
await bitcoindLock.release();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
507
648
|
async function refreshManagedBitcoindStatus(status, paths, options) {
|
|
508
649
|
const nowUnixMs = Date.now();
|
|
509
650
|
const rpc = createRpcClient(status.rpc);
|
|
651
|
+
const targetWalletRootId = options.walletRootId ?? status.walletRootId;
|
|
510
652
|
try {
|
|
511
653
|
await waitForRpcReady(rpc, status.rpc.cookieFile, status.chain, options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS);
|
|
512
654
|
await validateNodeConfigForTesting(rpc, status.chain, status.zmq.endpoint);
|
|
513
|
-
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc,
|
|
655
|
+
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc, targetWalletRootId, status.dataDir);
|
|
514
656
|
const nextStatus = {
|
|
515
657
|
...status,
|
|
658
|
+
walletRootId: targetWalletRootId,
|
|
659
|
+
runtimeRoot: paths.walletRuntimeRoot,
|
|
516
660
|
state: "ready",
|
|
517
661
|
processId: await isProcessAlive(status.processId) ? status.processId : null,
|
|
518
662
|
walletReplica,
|
|
@@ -526,6 +670,8 @@ async function refreshManagedBitcoindStatus(status, paths, options) {
|
|
|
526
670
|
catch (error) {
|
|
527
671
|
const nextStatus = {
|
|
528
672
|
...status,
|
|
673
|
+
walletRootId: targetWalletRootId,
|
|
674
|
+
runtimeRoot: paths.walletRuntimeRoot,
|
|
529
675
|
state: "failed",
|
|
530
676
|
processId: await isProcessAlive(status.processId) ? status.processId : null,
|
|
531
677
|
heartbeatAtUnixMs: nowUnixMs,
|
|
@@ -546,6 +692,8 @@ function createNodeHandle(status, paths, options) {
|
|
|
546
692
|
expectedChain: currentStatus.chain,
|
|
547
693
|
startHeight: currentStatus.startHeight,
|
|
548
694
|
dataDir: currentStatus.dataDir,
|
|
695
|
+
getblockArchiveEndHeight: currentStatus.getblockArchiveEndHeight ?? null,
|
|
696
|
+
getblockArchiveSha256: currentStatus.getblockArchiveSha256 ?? null,
|
|
549
697
|
walletRootId: currentStatus.walletRootId,
|
|
550
698
|
runtimeRoot: paths.walletRuntimeRoot,
|
|
551
699
|
async validate() {
|
|
@@ -553,6 +701,9 @@ function createNodeHandle(status, paths, options) {
|
|
|
553
701
|
},
|
|
554
702
|
async refreshServiceStatus() {
|
|
555
703
|
currentStatus = await refreshManagedBitcoindStatus(currentStatus, paths, options);
|
|
704
|
+
this.getblockArchiveEndHeight = currentStatus.getblockArchiveEndHeight ?? null;
|
|
705
|
+
this.getblockArchiveSha256 = currentStatus.getblockArchiveSha256 ?? null;
|
|
706
|
+
this.walletRootId = currentStatus.walletRootId;
|
|
556
707
|
return currentStatus;
|
|
557
708
|
},
|
|
558
709
|
async stop() {
|
|
@@ -617,103 +768,128 @@ export async function attachOrStartManagedBitcoindService(options) {
|
|
|
617
768
|
dataDir: options.dataDir,
|
|
618
769
|
walletRootId: options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID,
|
|
619
770
|
};
|
|
620
|
-
const existingProbe = await probeManagedBitcoindService(resolvedOptions);
|
|
621
|
-
if (existingProbe.compatibility === "compatible") {
|
|
622
|
-
const existing = await tryAttachExistingManagedBitcoindService(resolvedOptions);
|
|
623
|
-
if (existing !== null) {
|
|
624
|
-
return existing;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
if (existingProbe.compatibility !== "unreachable") {
|
|
628
|
-
throw new Error(existingProbe.error ?? "managed_bitcoind_protocol_error");
|
|
629
|
-
}
|
|
630
|
-
const paths = resolveManagedServicePaths(resolvedOptions.dataDir ?? "", resolvedOptions.walletRootId);
|
|
631
771
|
const startupTimeoutMs = resolvedOptions.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
const
|
|
640
|
-
if (
|
|
641
|
-
|
|
642
|
-
if (reattached !== null) {
|
|
643
|
-
return reattached;
|
|
644
|
-
}
|
|
772
|
+
return withClaimedUninitializedManagedRuntime({
|
|
773
|
+
dataDir: resolvedOptions.dataDir ?? "",
|
|
774
|
+
walletRootId: resolvedOptions.walletRootId,
|
|
775
|
+
shutdownTimeoutMs: resolvedOptions.shutdownTimeoutMs,
|
|
776
|
+
}, async () => {
|
|
777
|
+
const existingProbe = await probeManagedBitcoindService(resolvedOptions);
|
|
778
|
+
if (existingProbe.compatibility === "compatible") {
|
|
779
|
+
const existing = await tryAttachExistingManagedBitcoindService(resolvedOptions);
|
|
780
|
+
if (existing !== null) {
|
|
781
|
+
return existing;
|
|
645
782
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
await
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
const zmqConfig = {
|
|
657
|
-
endpoint: `tcp://${LOCAL_HOST}:${runtimeConfig.zmqPort}`,
|
|
658
|
-
topic: "hashblock",
|
|
659
|
-
port: runtimeConfig.zmqPort,
|
|
660
|
-
pollIntervalMs: resolvedOptions.pollIntervalMs ?? 15_000,
|
|
661
|
-
};
|
|
662
|
-
const child = spawn(bitcoindPath, buildManagedServiceArgs(resolvedOptions, runtimeConfig), {
|
|
663
|
-
detached: true,
|
|
664
|
-
stdio: "ignore",
|
|
783
|
+
}
|
|
784
|
+
if (existingProbe.compatibility !== "unreachable") {
|
|
785
|
+
throw new Error(existingProbe.error ?? "managed_bitcoind_protocol_error");
|
|
786
|
+
}
|
|
787
|
+
const paths = resolveManagedServicePaths(resolvedOptions.dataDir ?? "", resolvedOptions.walletRootId);
|
|
788
|
+
try {
|
|
789
|
+
const lock = await acquireFileLock(paths.bitcoindLockPath, {
|
|
790
|
+
purpose: "managed-bitcoind-start",
|
|
791
|
+
walletRootId: resolvedOptions.walletRootId,
|
|
792
|
+
dataDir: resolvedOptions.dataDir,
|
|
665
793
|
});
|
|
666
|
-
child.unref();
|
|
667
|
-
const rpc = createRpcClient(rpcConfig);
|
|
668
794
|
try {
|
|
669
|
-
await
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
795
|
+
const liveProbe = await probeManagedBitcoindService(resolvedOptions);
|
|
796
|
+
if (liveProbe.compatibility === "compatible") {
|
|
797
|
+
const reattached = await tryAttachExistingManagedBitcoindService(resolvedOptions);
|
|
798
|
+
if (reattached !== null) {
|
|
799
|
+
return reattached;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (liveProbe.compatibility !== "unreachable") {
|
|
803
|
+
throw new Error(liveProbe.error ?? "managed_bitcoind_protocol_error");
|
|
804
|
+
}
|
|
805
|
+
const bitcoindPath = await getBitcoindPath();
|
|
806
|
+
await verifyBitcoindVersion(bitcoindPath);
|
|
807
|
+
const binaryVersion = SUPPORTED_BITCOIND_VERSION;
|
|
808
|
+
await mkdir(resolvedOptions.dataDir ?? "", { recursive: true });
|
|
809
|
+
const startManagedProcess = async (startOptions) => {
|
|
810
|
+
const runtimeConfig = await resolveRuntimeConfig(paths.bitcoindStatusPath, paths.bitcoindRuntimeConfigPath, startOptions);
|
|
811
|
+
await writeBitcoinConf(paths.bitcoinConfPath, startOptions, runtimeConfig);
|
|
812
|
+
const rpcConfig = runtimeConfig.rpc;
|
|
813
|
+
const zmqConfig = {
|
|
814
|
+
endpoint: `tcp://${LOCAL_HOST}:${runtimeConfig.zmqPort}`,
|
|
815
|
+
topic: "hashblock",
|
|
816
|
+
port: runtimeConfig.zmqPort,
|
|
817
|
+
pollIntervalMs: startOptions.pollIntervalMs ?? 15_000,
|
|
818
|
+
};
|
|
819
|
+
const child = spawn(bitcoindPath, buildManagedServiceArgs(startOptions, runtimeConfig), {
|
|
820
|
+
detached: true,
|
|
821
|
+
stdio: "ignore",
|
|
822
|
+
});
|
|
823
|
+
child.unref();
|
|
824
|
+
const rpc = createRpcClient(rpcConfig);
|
|
674
825
|
try {
|
|
675
|
-
|
|
826
|
+
await waitForRpcReady(rpc, rpcConfig.cookieFile, startOptions.chain, startupTimeoutMs);
|
|
827
|
+
await validateNodeConfigForTesting(rpc, startOptions.chain, zmqConfig.endpoint);
|
|
828
|
+
}
|
|
829
|
+
catch (error) {
|
|
830
|
+
if (child.pid !== undefined) {
|
|
831
|
+
try {
|
|
832
|
+
process.kill(child.pid, "SIGTERM");
|
|
833
|
+
}
|
|
834
|
+
catch {
|
|
835
|
+
// ignore kill failures during startup cleanup
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
throw error;
|
|
676
839
|
}
|
|
677
|
-
|
|
678
|
-
|
|
840
|
+
const nowUnixMs = Date.now();
|
|
841
|
+
const walletRootId = startOptions.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
842
|
+
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc, walletRootId, startOptions.dataDir ?? "");
|
|
843
|
+
return createBitcoindServiceStatus({
|
|
844
|
+
binaryVersion,
|
|
845
|
+
serviceInstanceId: randomBytes(16).toString("hex"),
|
|
846
|
+
state: "ready",
|
|
847
|
+
processId: child.pid ?? null,
|
|
848
|
+
walletRootId,
|
|
849
|
+
chain: startOptions.chain,
|
|
850
|
+
dataDir: startOptions.dataDir ?? "",
|
|
851
|
+
runtimeRoot: paths.walletRuntimeRoot,
|
|
852
|
+
startHeight: startOptions.startHeight,
|
|
853
|
+
rpc: rpcConfig,
|
|
854
|
+
zmq: zmqConfig,
|
|
855
|
+
p2pPort: runtimeConfig.p2pPort,
|
|
856
|
+
getblockArchiveEndHeight: runtimeConfig.getblockArchiveEndHeight ?? null,
|
|
857
|
+
getblockArchiveSha256: runtimeConfig.getblockArchiveSha256 ?? null,
|
|
858
|
+
walletReplica,
|
|
859
|
+
startedAtUnixMs: nowUnixMs,
|
|
860
|
+
heartbeatAtUnixMs: nowUnixMs,
|
|
861
|
+
lastError: walletReplica.message ?? null,
|
|
862
|
+
});
|
|
863
|
+
};
|
|
864
|
+
let status;
|
|
865
|
+
try {
|
|
866
|
+
status = await startManagedProcess(resolvedOptions);
|
|
867
|
+
}
|
|
868
|
+
catch (error) {
|
|
869
|
+
if (resolvedOptions.getblockArchivePath === undefined || resolvedOptions.getblockArchivePath === null) {
|
|
870
|
+
throw error;
|
|
679
871
|
}
|
|
872
|
+
status = await startManagedProcess({
|
|
873
|
+
...resolvedOptions,
|
|
874
|
+
getblockArchivePath: null,
|
|
875
|
+
getblockArchiveEndHeight: null,
|
|
876
|
+
getblockArchiveSha256: null,
|
|
877
|
+
});
|
|
680
878
|
}
|
|
681
|
-
|
|
879
|
+
await writeBitcoindStatus(paths, status);
|
|
880
|
+
return createNodeHandle(status, paths, resolvedOptions);
|
|
881
|
+
}
|
|
882
|
+
finally {
|
|
883
|
+
await lock.release();
|
|
682
884
|
}
|
|
683
|
-
const nowUnixMs = Date.now();
|
|
684
|
-
const walletRootId = resolvedOptions.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
685
|
-
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc, walletRootId, resolvedOptions.dataDir ?? "");
|
|
686
|
-
const status = createBitcoindServiceStatus({
|
|
687
|
-
binaryVersion,
|
|
688
|
-
serviceInstanceId: randomBytes(16).toString("hex"),
|
|
689
|
-
state: "ready",
|
|
690
|
-
processId: child.pid ?? null,
|
|
691
|
-
walletRootId,
|
|
692
|
-
chain: resolvedOptions.chain,
|
|
693
|
-
dataDir: resolvedOptions.dataDir ?? "",
|
|
694
|
-
runtimeRoot: paths.walletRuntimeRoot,
|
|
695
|
-
startHeight: resolvedOptions.startHeight,
|
|
696
|
-
rpc: rpcConfig,
|
|
697
|
-
zmq: zmqConfig,
|
|
698
|
-
p2pPort: runtimeConfig.p2pPort,
|
|
699
|
-
walletReplica,
|
|
700
|
-
startedAtUnixMs: nowUnixMs,
|
|
701
|
-
heartbeatAtUnixMs: nowUnixMs,
|
|
702
|
-
lastError: walletReplica.message ?? null,
|
|
703
|
-
});
|
|
704
|
-
await writeBitcoindStatus(paths, status);
|
|
705
|
-
return createNodeHandle(status, paths, resolvedOptions);
|
|
706
|
-
}
|
|
707
|
-
finally {
|
|
708
|
-
await lock.release();
|
|
709
885
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
886
|
+
catch (error) {
|
|
887
|
+
if (error instanceof FileLockBusyError) {
|
|
888
|
+
return waitForManagedBitcoindService(resolvedOptions, startupTimeoutMs);
|
|
889
|
+
}
|
|
890
|
+
throw error;
|
|
714
891
|
}
|
|
715
|
-
|
|
716
|
-
}
|
|
892
|
+
});
|
|
717
893
|
}
|
|
718
894
|
export async function stopManagedBitcoindService(options) {
|
|
719
895
|
const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
@@ -724,35 +900,11 @@ export async function stopManagedBitcoindService(options) {
|
|
|
724
900
|
dataDir: options.dataDir,
|
|
725
901
|
});
|
|
726
902
|
try {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
if (status === null || processId === null || !await isProcessAlive(processId)) {
|
|
730
|
-
await clearManagedBitcoindRuntimeArtifacts(paths);
|
|
731
|
-
return {
|
|
732
|
-
status: "not-running",
|
|
733
|
-
walletRootId,
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
const rpc = createRpcClient(status.rpc);
|
|
737
|
-
try {
|
|
738
|
-
await rpc.stop();
|
|
739
|
-
}
|
|
740
|
-
catch {
|
|
741
|
-
try {
|
|
742
|
-
process.kill(processId, "SIGTERM");
|
|
743
|
-
}
|
|
744
|
-
catch (error) {
|
|
745
|
-
if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) {
|
|
746
|
-
throw error;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
await waitForProcessExit(processId, options.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS, "managed_bitcoind_service_stop_timeout");
|
|
751
|
-
await clearManagedBitcoindRuntimeArtifacts(paths);
|
|
752
|
-
return {
|
|
753
|
-
status: "stopped",
|
|
903
|
+
return stopManagedBitcoindServiceWithLockHeld({
|
|
904
|
+
...options,
|
|
754
905
|
walletRootId,
|
|
755
|
-
|
|
906
|
+
paths,
|
|
907
|
+
});
|
|
756
908
|
}
|
|
757
909
|
finally {
|
|
758
910
|
await lock.release();
|
|
@@ -2,8 +2,8 @@ export { openManagedBitcoindClientInternal } from "./client.js";
|
|
|
2
2
|
export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, stopIndexerDaemonService, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
|
|
3
3
|
export { normalizeRpcBlock } from "./normalize.js";
|
|
4
4
|
export { BitcoinRpcClient } from "./rpc.js";
|
|
5
|
-
export { attachOrStartManagedBitcoindService, readManagedBitcoindServiceStatusForTesting, stopManagedBitcoindService, shutdownManagedBitcoindServiceForTesting, } from "./service.js";
|
|
6
|
-
export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, resolveBootstrapPathsForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
|
|
5
|
+
export { attachOrStartManagedBitcoindService, buildManagedServiceArgsForTesting, readManagedBitcoindServiceStatusForTesting, resolveManagedBitcoindDbcacheMiB, stopManagedBitcoindService, shutdownManagedBitcoindServiceForTesting, writeBitcoinConfForTesting, } from "./service.js";
|
|
6
|
+
export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, prepareLatestGetblockArchiveForTesting, resolveBootstrapPathsForTesting, resolveGetblockArchivePathsForTesting, resolveReadyGetblockArchiveForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForGetblockArchiveImportForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
|
|
7
7
|
export { buildBitcoindArgsForTesting, createRpcClient, launchManagedBitcoindNode, resolveDefaultBitcoindDataDirForTesting, validateNodeConfigForTesting, } from "./node.js";
|
|
8
8
|
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
9
|
export { WritingQuoteRotator, loadWritingQuotesForTesting, shuffleIndicesForTesting, } from "./quotes.js";
|
package/dist/bitcoind/testing.js
CHANGED
|
@@ -2,8 +2,8 @@ export { openManagedBitcoindClientInternal } from "./client.js";
|
|
|
2
2
|
export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, stopIndexerDaemonService, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
|
|
3
3
|
export { normalizeRpcBlock } from "./normalize.js";
|
|
4
4
|
export { BitcoinRpcClient } from "./rpc.js";
|
|
5
|
-
export { attachOrStartManagedBitcoindService, readManagedBitcoindServiceStatusForTesting, stopManagedBitcoindService, shutdownManagedBitcoindServiceForTesting, } from "./service.js";
|
|
6
|
-
export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, resolveBootstrapPathsForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
|
|
5
|
+
export { attachOrStartManagedBitcoindService, buildManagedServiceArgsForTesting, readManagedBitcoindServiceStatusForTesting, resolveManagedBitcoindDbcacheMiB, stopManagedBitcoindService, shutdownManagedBitcoindServiceForTesting, writeBitcoinConfForTesting, } from "./service.js";
|
|
6
|
+
export { AssumeUtxoBootstrapController, DEFAULT_SNAPSHOT_METADATA, createBootstrapStateForTesting, downloadSnapshotFileForTesting, loadBootstrapStateForTesting, prepareLatestGetblockArchiveForTesting, resolveBootstrapPathsForTesting, resolveGetblockArchivePathsForTesting, resolveReadyGetblockArchiveForTesting, saveBootstrapStateForTesting, validateSnapshotFileForTesting, waitForGetblockArchiveImportForTesting, waitForHeadersForTesting, } from "./bootstrap.js";
|
|
7
7
|
export { buildBitcoindArgsForTesting, createRpcClient, launchManagedBitcoindNode, resolveDefaultBitcoindDataDirForTesting, validateNodeConfigForTesting, } from "./node.js";
|
|
8
8
|
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
9
|
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;
|
|
@@ -62,6 +84,9 @@ export interface ManagedBitcoindRuntimeConfig {
|
|
|
62
84
|
rpc: BitcoindRpcConfig;
|
|
63
85
|
zmqPort: number;
|
|
64
86
|
p2pPort: number;
|
|
87
|
+
dbcacheMiB: number;
|
|
88
|
+
getblockArchiveEndHeight?: number | null;
|
|
89
|
+
getblockArchiveSha256?: string | null;
|
|
65
90
|
}
|
|
66
91
|
export declare const MANAGED_BITCOIND_SERVICE_API_VERSION = "cogcoin/bitcoind-service/v1";
|
|
67
92
|
export type ManagedBitcoindServiceState = "starting" | "ready" | "stopping" | "failed";
|
|
@@ -80,6 +105,8 @@ export interface ManagedBitcoindServiceStatus {
|
|
|
80
105
|
rpc: BitcoindRpcConfig;
|
|
81
106
|
zmq: BitcoindZmqConfig;
|
|
82
107
|
p2pPort: number;
|
|
108
|
+
getblockArchiveEndHeight: number | null;
|
|
109
|
+
getblockArchiveSha256: string | null;
|
|
83
110
|
walletReplica: ManagedCoreWalletReplicaStatus | null;
|
|
84
111
|
startedAtUnixMs: number;
|
|
85
112
|
heartbeatAtUnixMs: number;
|
|
@@ -122,6 +149,10 @@ export interface ManagedBitcoindStatus {
|
|
|
122
149
|
serviceStatus?: ManagedBitcoindObservedStatus | null;
|
|
123
150
|
indexerDaemon?: ManagedIndexerDaemonObservedStatus | null;
|
|
124
151
|
}
|
|
152
|
+
export interface ManagedGetblockArchiveRestartRequest {
|
|
153
|
+
currentArchiveEndHeight: number | null;
|
|
154
|
+
nextArchiveEndHeight: number;
|
|
155
|
+
}
|
|
125
156
|
export interface ManagedBitcoindOptions extends ClientOptions {
|
|
126
157
|
dataDir?: string;
|
|
127
158
|
databasePath?: string;
|
|
@@ -136,6 +167,8 @@ export interface ManagedBitcoindOptions extends ClientOptions {
|
|
|
136
167
|
managedWalletPassphrase?: string;
|
|
137
168
|
onProgress?: (event: ManagedBitcoindProgressEvent) => void;
|
|
138
169
|
progressOutput?: ProgressOutputMode;
|
|
170
|
+
fetchImpl?: typeof fetch;
|
|
171
|
+
confirmGetblockArchiveRestart?: (request: ManagedGetblockArchiveRestartRequest) => Promise<boolean>;
|
|
139
172
|
}
|
|
140
173
|
export interface ManagedBitcoindClient extends Client {
|
|
141
174
|
syncToTip(): Promise<SyncResult>;
|
|
@@ -396,6 +429,8 @@ export interface ManagedBitcoindNodeHandle {
|
|
|
396
429
|
expectedChain: "main" | "regtest";
|
|
397
430
|
startHeight: number;
|
|
398
431
|
dataDir: string;
|
|
432
|
+
getblockArchiveEndHeight: number | null;
|
|
433
|
+
getblockArchiveSha256: string | null;
|
|
399
434
|
walletRootId?: string;
|
|
400
435
|
runtimeRoot?: string;
|
|
401
436
|
validate(): Promise<void>;
|