@cogcoin/client 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bitcoind/client/sync-engine.js +1 -1
- package/dist/bitcoind/indexer-daemon-main.js +2 -11
- package/dist/bitcoind/indexer-daemon.js +26 -4
- package/dist/bitcoind/indexer-monitor.js +5 -1
- package/dist/bitcoind/progress/controller.js +4 -1
- package/dist/bitcoind/progress/follow-scene.js +7 -1
- package/dist/cli/context.d.ts +0 -1
- package/dist/cli/context.js +2 -23
- package/dist/package-version.d.ts +1 -0
- package/dist/package-version.js +17 -0
- package/dist/wallet/read/context.js +5 -1
- package/package.json +1 -1
|
@@ -317,6 +317,6 @@ export async function syncToTip(dependencies) {
|
|
|
317
317
|
lastError: message,
|
|
318
318
|
message: "Managed sync can be resumed after the last error.",
|
|
319
319
|
});
|
|
320
|
-
throw new Error(message);
|
|
320
|
+
throw new Error(message, { cause: error instanceof Error ? error : undefined });
|
|
321
321
|
}
|
|
322
322
|
}
|
|
@@ -5,6 +5,7 @@ import { loadBundledGenesisParameters, serializeIndexerState } from "@cogcoin/in
|
|
|
5
5
|
import { openManagedBitcoindClientInternal } from "./client.js";
|
|
6
6
|
import { DEFAULT_SNAPSHOT_METADATA } from "./bootstrap.js";
|
|
7
7
|
import { openClient } from "../client.js";
|
|
8
|
+
import { readPackageVersionFromDisk } from "../package-version.js";
|
|
8
9
|
import { openSqliteStore } from "../sqlite/index.js";
|
|
9
10
|
import { writeRuntimeStatusFile } from "../wallet/fs/status-file.js";
|
|
10
11
|
import { createRpcClient } from "./node.js";
|
|
@@ -55,16 +56,6 @@ async function withTimeout(promise, timeoutMs, errorCode) {
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
|
-
async function readPackageVersionFromDisk() {
|
|
59
|
-
try {
|
|
60
|
-
const raw = await readFile(new URL("../../package.json", import.meta.url), "utf8");
|
|
61
|
-
const parsed = JSON.parse(raw);
|
|
62
|
-
return parsed.version ?? "0.0.0";
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return "0.0.0";
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
59
|
function createSnapshotKey(appliedTip) {
|
|
69
60
|
return appliedTip === null
|
|
70
61
|
? "__null__"
|
|
@@ -177,7 +168,7 @@ async function main() {
|
|
|
177
168
|
const walletRootId = parseArg("wallet-root-id") || UNINITIALIZED_WALLET_ROOT_ID;
|
|
178
169
|
const paths = resolveManagedServicePaths(dataDir, walletRootId);
|
|
179
170
|
const daemonInstanceId = randomUUID();
|
|
180
|
-
const binaryVersion = await readPackageVersionFromDisk();
|
|
171
|
+
const binaryVersion = await readPackageVersionFromDisk().catch(() => "0.0.0");
|
|
181
172
|
const genesisParameters = await loadBundledGenesisParameters();
|
|
182
173
|
const startedAtUnixMs = Date.now();
|
|
183
174
|
const snapshots = new Map();
|
|
@@ -3,12 +3,14 @@ import { spawn } from "node:child_process";
|
|
|
3
3
|
import { mkdir, readFile, rm } from "node:fs/promises";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import net from "node:net";
|
|
6
|
-
import { compareSemver } from "../semver.js";
|
|
6
|
+
import { compareSemver, parseSemver } from "../semver.js";
|
|
7
7
|
import { acquireFileLock, FileLockBusyError } from "../wallet/fs/lock.js";
|
|
8
8
|
import { writeRuntimeStatusFile } from "../wallet/fs/status-file.js";
|
|
9
9
|
import { INDEXER_DAEMON_SCHEMA_VERSION, INDEXER_DAEMON_SERVICE_API_VERSION, } from "./types.js";
|
|
10
10
|
import { resolveManagedServicePaths, UNINITIALIZED_WALLET_ROOT_ID } from "./service-paths.js";
|
|
11
11
|
const DEFAULT_STARTUP_TIMEOUT_MS = 30_000;
|
|
12
|
+
const DEFAULT_SHUTDOWN_TIMEOUT_MS = 5_000;
|
|
13
|
+
const FORCE_KILL_TIMEOUT_MS = 5_000;
|
|
12
14
|
const INDEXER_DAEMON_REQUEST_TIMEOUT_MS = 15_000;
|
|
13
15
|
const INDEXER_DAEMON_RESUME_BACKGROUND_FOLLOW_REQUEST_TIMEOUT_MS = 35_000;
|
|
14
16
|
const INDEXER_DAEMON_BACKGROUND_FOLLOW_NOT_ACTIVE = "indexer_daemon_background_follow_not_active";
|
|
@@ -58,6 +60,11 @@ async function clearIndexerDaemonRuntimeArtifacts(paths) {
|
|
|
58
60
|
await rm(paths.indexerDaemonStatusPath, { force: true }).catch(() => undefined);
|
|
59
61
|
await rm(paths.indexerDaemonSocketPath, { force: true }).catch(() => undefined);
|
|
60
62
|
}
|
|
63
|
+
function ignoreProcessNotFound(error) {
|
|
64
|
+
if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) {
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
61
68
|
export async function stopIndexerDaemonServiceWithLockHeld(options) {
|
|
62
69
|
const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
63
70
|
const paths = options.paths ?? resolveManagedServicePaths(options.dataDir, walletRootId);
|
|
@@ -74,11 +81,23 @@ export async function stopIndexerDaemonServiceWithLockHeld(options) {
|
|
|
74
81
|
process.kill(processId, "SIGTERM");
|
|
75
82
|
}
|
|
76
83
|
catch (error) {
|
|
77
|
-
|
|
84
|
+
ignoreProcessNotFound(error);
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
await waitForProcessExit(processId, options.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS, "indexer_daemon_stop_timeout");
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (!(error instanceof Error) || error.message !== "indexer_daemon_stop_timeout") {
|
|
78
91
|
throw error;
|
|
79
92
|
}
|
|
93
|
+
try {
|
|
94
|
+
process.kill(processId, "SIGKILL");
|
|
95
|
+
}
|
|
96
|
+
catch (killError) {
|
|
97
|
+
ignoreProcessNotFound(killError);
|
|
98
|
+
}
|
|
99
|
+
await waitForProcessExit(processId, FORCE_KILL_TIMEOUT_MS, "indexer_daemon_stop_timeout");
|
|
80
100
|
}
|
|
81
|
-
await waitForProcessExit(processId, options.shutdownTimeoutMs ?? 5_000, "indexer_daemon_stop_timeout");
|
|
82
101
|
await clearIndexerDaemonRuntimeArtifacts(paths);
|
|
83
102
|
return {
|
|
84
103
|
status: "stopped",
|
|
@@ -283,8 +302,11 @@ function isStaleIndexerDaemonVersion(status, expectedBinaryVersion) {
|
|
|
283
302
|
if (status === null || expectedBinaryVersion === null || expectedBinaryVersion === undefined) {
|
|
284
303
|
return false;
|
|
285
304
|
}
|
|
305
|
+
if (parseSemver(expectedBinaryVersion) === null) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
286
308
|
const comparison = compareSemver(status.binaryVersion, expectedBinaryVersion);
|
|
287
|
-
return comparison
|
|
309
|
+
return comparison === null || comparison < 0;
|
|
288
310
|
}
|
|
289
311
|
async function probeIndexerDaemonAtSocket(socketPath, expectedWalletRootId) {
|
|
290
312
|
const client = createIndexerDaemonClient(socketPath);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { loadBundledGenesisParameters } from "@cogcoin/indexer";
|
|
3
|
+
import { readPackageVersionFromDisk } from "../package-version.js";
|
|
3
4
|
import { attachOrStartIndexerDaemon, readObservedIndexerDaemonStatus, } from "./indexer-daemon.js";
|
|
4
5
|
import { resolveCogcoinProcessingStartHeight } from "./processing-start-height.js";
|
|
5
6
|
import { resolveManagedServicePaths, UNINITIALIZED_WALLET_ROOT_ID } from "./service-paths.js";
|
|
@@ -31,6 +32,9 @@ async function resolveStartOptions(options) {
|
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
34
|
export async function openManagedIndexerMonitor(options) {
|
|
35
|
+
const expectedBinaryVersion = options.expectedBinaryVersion === undefined
|
|
36
|
+
? await readPackageVersionFromDisk()
|
|
37
|
+
: options.expectedBinaryVersion;
|
|
34
38
|
const walletRootId = options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
|
|
35
39
|
const startOptions = await resolveStartOptions({
|
|
36
40
|
dataDir: options.dataDir,
|
|
@@ -49,7 +53,7 @@ export async function openManagedIndexerMonitor(options) {
|
|
|
49
53
|
walletRootId,
|
|
50
54
|
startupTimeoutMs: options.startupTimeoutMs,
|
|
51
55
|
ensureBackgroundFollow: true,
|
|
52
|
-
expectedBinaryVersion
|
|
56
|
+
expectedBinaryVersion,
|
|
53
57
|
});
|
|
54
58
|
return createManagedIndexerMonitor({
|
|
55
59
|
daemon,
|
|
@@ -128,8 +128,11 @@ export class ManagedProgressController {
|
|
|
128
128
|
this.#cogcoinSyncTargetHeight = null;
|
|
129
129
|
}
|
|
130
130
|
if (this.#followVisualMode) {
|
|
131
|
+
const followIndexedHeight = phase === "follow_tip"
|
|
132
|
+
? this.#cogcoinSyncHeight ?? this.#progress.blocks ?? this.#followScene.indexedHeight
|
|
133
|
+
: undefined;
|
|
131
134
|
syncFollowSceneState(this.#followScene, {
|
|
132
|
-
indexedHeight:
|
|
135
|
+
indexedHeight: followIndexedHeight,
|
|
133
136
|
nodeHeight: this.#progress.blocks,
|
|
134
137
|
liveActivated: phase === "follow_tip" || this.#followScene.liveActivated,
|
|
135
138
|
});
|
|
@@ -110,7 +110,13 @@ function renderFollowStatusField(statusFieldText, options) {
|
|
|
110
110
|
return field;
|
|
111
111
|
}
|
|
112
112
|
function highestTrackedFollowHeight(state) {
|
|
113
|
-
|
|
113
|
+
let highest = Math.max(state.indexedHeight ?? Number.NEGATIVE_INFINITY, state.displayedCenterHeight ?? Number.NEGATIVE_INFINITY, state.animation?.height ?? Number.NEGATIVE_INFINITY);
|
|
114
|
+
for (const height of state.queuedHeights) {
|
|
115
|
+
if (height > highest) {
|
|
116
|
+
highest = height;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return highest;
|
|
114
120
|
}
|
|
115
121
|
function resolveLatestAuthoritativeFollowHeight(indexedHeight, nodeHeight) {
|
|
116
122
|
if (indexedHeight === null) {
|
package/dist/cli/context.d.ts
CHANGED
package/dist/cli/context.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { mkdir
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
3
|
import { attachOrStartIndexerDaemon, probeIndexerDaemon, readObservedIndexerDaemonStatus, stopIndexerDaemonService, } from "../bitcoind/indexer-daemon.js";
|
|
4
4
|
import { createRpcClient } from "../bitcoind/node.js";
|
|
5
5
|
import { attachOrStartManagedBitcoindService, probeManagedBitcoindService, stopManagedBitcoindService, } from "../bitcoind/service.js";
|
|
6
6
|
import { resolveDefaultBitcoindDataDirForTesting, resolveDefaultClientDatabasePathForTesting, resolveDefaultUpdateCheckStatePathForTesting, } from "../app-paths.js";
|
|
7
7
|
import { openManagedBitcoindClient } from "../bitcoind/index.js";
|
|
8
8
|
import { openManagedIndexerMonitor } from "../bitcoind/indexer-monitor.js";
|
|
9
|
+
import { readPackageVersionFromDisk } from "../package-version.js";
|
|
9
10
|
import { inspectPassiveClientStatus } from "../passive-status.js";
|
|
10
11
|
import { openSqliteStore } from "../sqlite/index.js";
|
|
11
12
|
import { initializeWallet, deleteImportedWalletSeed, previewResetWallet, repairWallet, resetWallet, restoreWalletFromMnemonic, showWalletMnemonic, } from "../wallet/lifecycle.js";
|
|
@@ -16,28 +17,6 @@ import { ensureBuiltInMiningSetupIfNeeded, followMiningLog, inspectMiningControl
|
|
|
16
17
|
import { createLazyDefaultWalletSecretProvider } from "../wallet/state/provider.js";
|
|
17
18
|
import { anchorDomain, transferBitcoin, buyDomain, claimCogLock, clearDomainDelegate, clearDomainEndpoint, clearDomainMiner, clearField, createField, giveReputation, lockCogToDomain, registerDomain, reclaimCogLock, revokeReputation, sendCog, setField, setDomainCanonical, setDomainDelegate, setDomainEndpoint, setDomainMiner, sellDomain, transferDomain, } from "../wallet/tx/index.js";
|
|
18
19
|
import { createTerminalPrompter } from "./prompt.js";
|
|
19
|
-
export async function readPackageVersionFromDisk() {
|
|
20
|
-
const packageUrls = [
|
|
21
|
-
new URL("../../package.json", import.meta.url),
|
|
22
|
-
new URL("../../../package.json", import.meta.url),
|
|
23
|
-
];
|
|
24
|
-
for (const packageUrl of packageUrls) {
|
|
25
|
-
try {
|
|
26
|
-
const raw = await readFile(packageUrl, "utf8");
|
|
27
|
-
const parsed = JSON.parse(raw);
|
|
28
|
-
return parsed.version ?? "0.0.0";
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
const code = typeof error === "object" && error !== null && "code" in error
|
|
32
|
-
? String(error.code)
|
|
33
|
-
: null;
|
|
34
|
-
if (code !== "ENOENT") {
|
|
35
|
-
throw error;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return "0.0.0";
|
|
40
|
-
}
|
|
41
20
|
async function runGlobalClientUpdateInstall(options) {
|
|
42
21
|
const binary = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
43
22
|
await new Promise((resolve, reject) => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function readPackageVersionFromDisk(): Promise<string>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
export async function readPackageVersionFromDisk() {
|
|
3
|
+
try {
|
|
4
|
+
const raw = await readFile(new URL("../package.json", import.meta.url), "utf8");
|
|
5
|
+
const parsed = JSON.parse(raw);
|
|
6
|
+
return parsed.version ?? "0.0.0";
|
|
7
|
+
}
|
|
8
|
+
catch (error) {
|
|
9
|
+
const code = typeof error === "object" && error !== null && "code" in error
|
|
10
|
+
? String(error.code)
|
|
11
|
+
: null;
|
|
12
|
+
if (code === "ENOENT") {
|
|
13
|
+
return "0.0.0";
|
|
14
|
+
}
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { access, constants } from "node:fs/promises";
|
|
2
2
|
import { deserializeIndexerState, loadBundledGenesisParameters } from "@cogcoin/indexer";
|
|
3
|
+
import { readPackageVersionFromDisk } from "../../package-version.js";
|
|
3
4
|
import { attachOrStartIndexerDaemon, INDEXER_DAEMON_BACKGROUND_FOLLOW_RECOVERY_FAILED, probeIndexerDaemon, readObservedIndexerDaemonStatus, readSnapshotWithRetry, } from "../../bitcoind/indexer-daemon.js";
|
|
4
5
|
import { createRpcClient } from "../../bitcoind/node.js";
|
|
5
6
|
import { UNINITIALIZED_WALLET_ROOT_ID } from "../../bitcoind/service-paths.js";
|
|
@@ -495,6 +496,9 @@ async function readFundingSpendableSats(options) {
|
|
|
495
496
|
}
|
|
496
497
|
}
|
|
497
498
|
export async function openWalletReadContext(options) {
|
|
499
|
+
const expectedIndexerBinaryVersion = options.expectedIndexerBinaryVersion === undefined
|
|
500
|
+
? await readPackageVersionFromDisk()
|
|
501
|
+
: options.expectedIndexerBinaryVersion;
|
|
498
502
|
const startupTimeoutMs = options.startupTimeoutMs ?? DEFAULT_SERVICE_START_TIMEOUT_MS;
|
|
499
503
|
const now = options.now ?? Date.now();
|
|
500
504
|
const localState = await inspectWalletLocalState({
|
|
@@ -545,7 +549,7 @@ export async function openWalletReadContext(options) {
|
|
|
545
549
|
walletRootId,
|
|
546
550
|
startupTimeoutMs,
|
|
547
551
|
ensureBackgroundFollow: true,
|
|
548
|
-
expectedBinaryVersion:
|
|
552
|
+
expectedBinaryVersion: expectedIndexerBinaryVersion,
|
|
549
553
|
});
|
|
550
554
|
}
|
|
551
555
|
else {
|
package/package.json
CHANGED