@cogcoin/client 1.1.5 → 1.1.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 +2 -2
- package/dist/bitcoind/indexer-daemon.d.ts +3 -7
- package/dist/bitcoind/indexer-daemon.js +39 -204
- package/dist/bitcoind/managed-runtime/bitcoind-policy.d.ts +16 -0
- package/dist/bitcoind/managed-runtime/bitcoind-policy.js +177 -0
- package/dist/bitcoind/managed-runtime/bitcoind-runtime.d.ts +20 -0
- package/dist/bitcoind/managed-runtime/bitcoind-runtime.js +74 -0
- package/dist/bitcoind/managed-runtime/bitcoind-status.d.ts +11 -0
- package/dist/bitcoind/managed-runtime/bitcoind-status.js +44 -0
- package/dist/bitcoind/managed-runtime/indexer-policy.d.ts +34 -0
- package/dist/bitcoind/managed-runtime/indexer-policy.js +200 -0
- package/dist/bitcoind/managed-runtime/indexer-runtime.d.ts +15 -0
- package/dist/bitcoind/managed-runtime/indexer-runtime.js +82 -0
- package/dist/bitcoind/managed-runtime/status.d.ts +11 -0
- package/dist/bitcoind/managed-runtime/status.js +59 -0
- package/dist/bitcoind/managed-runtime/types.d.ts +77 -0
- package/dist/bitcoind/node.d.ts +2 -2
- package/dist/bitcoind/node.js +2 -2
- package/dist/bitcoind/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +53 -3
- package/dist/bitcoind/service.d.ts +2 -7
- package/dist/bitcoind/service.js +79 -207
- package/dist/cli/command-registry.d.ts +1 -1
- package/dist/cli/command-registry.js +2 -64
- package/dist/cli/commands/client-admin.js +3 -18
- package/dist/cli/commands/mining-runtime.js +4 -60
- package/dist/cli/commands/wallet-admin.js +6 -6
- package/dist/cli/context.js +1 -3
- package/dist/cli/mining-json.d.ts +1 -22
- package/dist/cli/mining-json.js +0 -23
- package/dist/cli/output.js +16 -2
- package/dist/cli/parse.js +0 -2
- package/dist/cli/preview-json.d.ts +1 -22
- package/dist/cli/preview-json.js +0 -19
- package/dist/cli/types.d.ts +1 -3
- package/dist/cli/wallet-format.js +1 -1
- package/dist/cli/workflow-hints.d.ts +1 -2
- package/dist/cli/workflow-hints.js +5 -8
- package/dist/wallet/lifecycle/access.d.ts +5 -0
- package/dist/wallet/lifecycle/access.js +79 -0
- package/dist/wallet/lifecycle/context.d.ts +26 -0
- package/dist/wallet/lifecycle/context.js +57 -0
- package/dist/wallet/lifecycle/managed-core.d.ts +1 -9
- package/dist/wallet/lifecycle/managed-core.js +3 -63
- package/dist/wallet/lifecycle/repair-bitcoind.d.ts +10 -0
- package/dist/wallet/lifecycle/repair-bitcoind.js +142 -0
- package/dist/wallet/lifecycle/repair-indexer.d.ts +8 -0
- package/dist/wallet/lifecycle/repair-indexer.js +117 -0
- package/dist/wallet/lifecycle/repair-mining.d.ts +1 -5
- package/dist/wallet/lifecycle/repair-mining.js +5 -39
- package/dist/wallet/lifecycle/repair.d.ts +2 -4
- package/dist/wallet/lifecycle/repair.js +74 -318
- package/dist/wallet/lifecycle/setup-prompts.d.ts +7 -0
- package/dist/wallet/lifecycle/setup-prompts.js +88 -0
- package/dist/wallet/lifecycle/setup-state.d.ts +26 -0
- package/dist/wallet/lifecycle/setup-state.js +159 -0
- package/dist/wallet/lifecycle/setup.d.ts +3 -4
- package/dist/wallet/lifecycle/setup.js +47 -351
- package/dist/wallet/lifecycle/types.d.ts +33 -5
- package/dist/wallet/managed-core-wallet.d.ts +2 -0
- package/dist/wallet/managed-core-wallet.js +27 -1
- package/dist/wallet/mining/candidate.d.ts +1 -0
- package/dist/wallet/mining/candidate.js +38 -6
- package/dist/wallet/mining/competitiveness.d.ts +1 -0
- package/dist/wallet/mining/competitiveness.js +6 -0
- package/dist/wallet/mining/cycle.d.ts +2 -0
- package/dist/wallet/mining/cycle.js +14 -4
- package/dist/wallet/mining/engine-types.d.ts +1 -0
- package/dist/wallet/mining/index.d.ts +1 -1
- package/dist/wallet/mining/index.js +1 -1
- package/dist/wallet/mining/publish.d.ts +3 -0
- package/dist/wallet/mining/publish.js +78 -6
- package/dist/wallet/mining/runner.d.ts +0 -32
- package/dist/wallet/mining/runner.js +59 -104
- package/dist/wallet/mining/stop.d.ts +7 -0
- package/dist/wallet/mining/stop.js +23 -0
- package/dist/wallet/mining/supervisor.d.ts +2 -36
- package/dist/wallet/mining/supervisor.js +139 -246
- package/dist/wallet/read/context.d.ts +1 -5
- package/dist/wallet/read/context.js +20 -379
- package/dist/wallet/read/managed-services.d.ts +33 -0
- package/dist/wallet/read/managed-services.js +222 -0
- package/dist/wallet/state/client-password/bootstrap.d.ts +2 -0
- package/dist/wallet/state/client-password/bootstrap.js +3 -0
- package/dist/wallet/state/client-password/context.d.ts +10 -0
- package/dist/wallet/state/client-password/context.js +46 -0
- package/dist/wallet/state/client-password/crypto.d.ts +34 -0
- package/dist/wallet/state/client-password/crypto.js +117 -0
- package/dist/wallet/state/client-password/files.d.ts +10 -0
- package/dist/wallet/state/client-password/files.js +109 -0
- package/dist/wallet/state/client-password/legacy-cleanup.d.ts +11 -0
- package/dist/wallet/state/client-password/legacy-cleanup.js +338 -0
- package/dist/wallet/state/client-password/messages.d.ts +3 -0
- package/dist/wallet/state/client-password/messages.js +9 -0
- package/dist/wallet/state/client-password/migration.d.ts +4 -0
- package/dist/wallet/state/client-password/migration.js +32 -0
- package/dist/wallet/state/client-password/prompts.d.ts +12 -0
- package/dist/wallet/state/client-password/prompts.js +79 -0
- package/dist/wallet/state/client-password/protected-secrets.d.ts +13 -0
- package/dist/wallet/state/client-password/protected-secrets.js +90 -0
- package/dist/wallet/state/client-password/readiness.d.ts +4 -0
- package/dist/wallet/state/client-password/readiness.js +48 -0
- package/dist/wallet/state/client-password/references.d.ts +1 -0
- package/dist/wallet/state/client-password/references.js +56 -0
- package/dist/wallet/state/client-password/rotation.d.ts +6 -0
- package/dist/wallet/state/client-password/rotation.js +98 -0
- package/dist/wallet/state/client-password/session-policy.d.ts +6 -0
- package/dist/wallet/state/client-password/session-policy.js +28 -0
- package/dist/wallet/state/client-password/session.d.ts +19 -0
- package/dist/wallet/state/client-password/session.js +170 -0
- package/dist/wallet/state/client-password/setup.d.ts +8 -0
- package/dist/wallet/state/client-password/setup.js +49 -0
- package/dist/wallet/state/client-password/types.d.ts +82 -0
- package/dist/wallet/state/client-password/types.js +5 -0
- package/dist/wallet/state/client-password.d.ts +7 -38
- package/dist/wallet/state/client-password.js +52 -937
- package/dist/wallet/tx/anchor.js +123 -216
- package/dist/wallet/tx/cog.js +294 -489
- package/dist/wallet/tx/common.d.ts +2 -0
- package/dist/wallet/tx/common.js +2 -0
- package/dist/wallet/tx/domain-admin.js +111 -220
- package/dist/wallet/tx/domain-market.js +401 -681
- package/dist/wallet/tx/executor.d.ts +176 -0
- package/dist/wallet/tx/executor.js +302 -0
- package/dist/wallet/tx/field.js +109 -215
- package/dist/wallet/tx/register.js +158 -269
- package/dist/wallet/tx/reputation.js +120 -227
- package/package.json +1 -1
- package/dist/wallet/mining/worker-main.js +0 -17
- package/dist/wallet/state/client-password-agent.d.ts +0 -1
- package/dist/wallet/state/client-password-agent.js +0 -211
- /package/dist/{wallet/mining/worker-main.d.ts → bitcoind/managed-runtime/types.js} +0 -0
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
1
|
import { rm } from "node:fs/promises";
|
|
4
2
|
import { join } from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
3
|
import { createRpcClient } from "../../bitcoind/node.js";
|
|
7
4
|
import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
|
|
8
5
|
import { FileLockBusyError, acquireFileLock, clearOrphanedFileLock, readLockMetadata, } from "../fs/lock.js";
|
|
9
6
|
import { openWalletReadContext } from "../read/index.js";
|
|
7
|
+
import { destroyAllClientPasswordSessionsResolved } from "../state/client-password/session.js";
|
|
10
8
|
import { readMiningGenerationActivity, requestMiningGenerationPreemption, } from "./coordination.js";
|
|
11
|
-
import {
|
|
12
|
-
import { MINING_SHUTDOWN_GRACE_MS, MINING_WORKER_API_VERSION, } from "./constants.js";
|
|
9
|
+
import { MINING_SHUTDOWN_GRACE_MS, } from "./constants.js";
|
|
13
10
|
import { saveStopSnapshot } from "./lifecycle.js";
|
|
14
11
|
import { loadMiningRuntimeStatus, saveMiningRuntimeStatus, } from "./runtime-artifacts.js";
|
|
12
|
+
import { createMiningStopRequestedError } from "./stop.js";
|
|
15
13
|
import { MiningFollowVisualizer } from "./visualizer.js";
|
|
16
|
-
const BACKGROUND_START_TIMEOUT_MS = 15_000;
|
|
17
14
|
function sleep(ms, signal) {
|
|
18
15
|
return new Promise((resolve) => {
|
|
16
|
+
if (signal?.aborted) {
|
|
17
|
+
resolve();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
19
20
|
const timer = setTimeout(resolve, ms);
|
|
20
21
|
signal?.addEventListener("abort", () => {
|
|
21
22
|
clearTimeout(timer);
|
|
@@ -23,15 +24,23 @@ function sleep(ms, signal) {
|
|
|
23
24
|
}, { once: true });
|
|
24
25
|
});
|
|
25
26
|
}
|
|
27
|
+
function createOneShotClientPasswordSessionDestroyer() {
|
|
28
|
+
let destroyed = false;
|
|
29
|
+
return () => {
|
|
30
|
+
if (destroyed) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
destroyed = true;
|
|
34
|
+
destroyAllClientPasswordSessionsResolved();
|
|
35
|
+
};
|
|
36
|
+
}
|
|
26
37
|
function resolveSupervisorDependencies(overrides = {}) {
|
|
27
38
|
return {
|
|
28
39
|
requestMiningPreemption: overrides.requestMiningPreemption ?? requestMiningGenerationPreemption,
|
|
29
40
|
saveStopSnapshot: overrides.saveStopSnapshot ?? saveStopSnapshot,
|
|
30
|
-
spawnWorkerProcess: overrides.spawnWorkerProcess ?? spawn,
|
|
31
41
|
runMiningLoop: overrides.runMiningLoop ?? (() => {
|
|
32
42
|
throw new Error("mining_supervisor_run_loop_missing");
|
|
33
43
|
}),
|
|
34
|
-
inspectMiningControlPlane: overrides.inspectMiningControlPlane ?? inspectMiningControlPlane,
|
|
35
44
|
loadRuntimeStatus: overrides.loadRuntimeStatus ?? loadMiningRuntimeStatus,
|
|
36
45
|
saveRuntimeStatus: overrides.saveRuntimeStatus ?? saveMiningRuntimeStatus,
|
|
37
46
|
acquireLock: overrides.acquireLock ?? acquireFileLock,
|
|
@@ -42,11 +51,17 @@ function resolveSupervisorDependencies(overrides = {}) {
|
|
|
42
51
|
nowUnixMs: overrides.nowUnixMs ?? Date.now,
|
|
43
52
|
processKill: overrides.processKill ?? process.kill.bind(process),
|
|
44
53
|
processPid: overrides.processPid ?? process.pid,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
forceExit: overrides.forceExit ?? ((code) => {
|
|
55
|
+
process.exit(code);
|
|
56
|
+
}),
|
|
48
57
|
};
|
|
49
58
|
}
|
|
59
|
+
class ForegroundMiningShutdownTimeoutError extends Error {
|
|
60
|
+
constructor() {
|
|
61
|
+
super("mining_foreground_shutdown_timeout");
|
|
62
|
+
this.name = "ForegroundMiningShutdownTimeoutError";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
50
65
|
async function isProcessAlive(pid, deps) {
|
|
51
66
|
if (pid === null) {
|
|
52
67
|
return false;
|
|
@@ -294,265 +309,143 @@ async function acquireMiningStartControlLock(options) {
|
|
|
294
309
|
}
|
|
295
310
|
}
|
|
296
311
|
}
|
|
297
|
-
export async function waitForBackgroundHealthy(paths, depsOverrides = {}) {
|
|
298
|
-
const deps = resolveSupervisorDependencies(depsOverrides);
|
|
299
|
-
const deadline = deps.nowUnixMs() + BACKGROUND_START_TIMEOUT_MS;
|
|
300
|
-
while (deps.nowUnixMs() < deadline) {
|
|
301
|
-
const snapshot = await deps.loadRuntimeStatus(paths.miningStatusPath).catch(() => null);
|
|
302
|
-
if (snapshot !== null
|
|
303
|
-
&& snapshot.runMode === "background"
|
|
304
|
-
&& snapshot.backgroundWorkerHealth === "healthy") {
|
|
305
|
-
return snapshot;
|
|
306
|
-
}
|
|
307
|
-
await deps.sleep(250);
|
|
308
|
-
}
|
|
309
|
-
return deps.loadRuntimeStatus(paths.miningStatusPath).catch(() => null);
|
|
310
|
-
}
|
|
311
312
|
export async function runForegroundMining(options) {
|
|
312
313
|
const deps = resolveSupervisorDependencies(options.deps);
|
|
314
|
+
const shutdownGraceMs = options.shutdownGraceMs ?? MINING_SHUTDOWN_GRACE_MS;
|
|
315
|
+
const usesExternalSignal = options.signal !== undefined;
|
|
313
316
|
let visualizer = options.visualizer ?? null;
|
|
314
317
|
const ownsVisualizer = visualizer === null;
|
|
318
|
+
const destroyClientPasswordSessions = createOneShotClientPasswordSessionDestroyer();
|
|
315
319
|
const controlLock = await acquireMiningStartControlLock({
|
|
316
320
|
paths: options.runtime.paths,
|
|
317
321
|
purpose: "mine-foreground",
|
|
318
322
|
takeoverReason: "mine-foreground-replace",
|
|
319
|
-
shutdownGraceMs
|
|
323
|
+
shutdownGraceMs,
|
|
320
324
|
deps,
|
|
321
325
|
});
|
|
322
326
|
const abortController = new AbortController();
|
|
327
|
+
let stopRequested = false;
|
|
328
|
+
let shutdownDeadlineTimer = null;
|
|
329
|
+
let rejectShutdownDeadline = null;
|
|
330
|
+
let forceExitIssued = false;
|
|
331
|
+
const shutdownDeadline = new Promise((_, reject) => {
|
|
332
|
+
rejectShutdownDeadline = reject;
|
|
333
|
+
});
|
|
334
|
+
const requestStop = () => {
|
|
335
|
+
if (stopRequested) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
stopRequested = true;
|
|
339
|
+
if (!abortController.signal.aborted) {
|
|
340
|
+
abortController.abort(createMiningStopRequestedError());
|
|
341
|
+
}
|
|
342
|
+
shutdownDeadlineTimer = setTimeout(() => {
|
|
343
|
+
rejectShutdownDeadline?.(new ForegroundMiningShutdownTimeoutError());
|
|
344
|
+
}, shutdownGraceMs);
|
|
345
|
+
shutdownDeadlineTimer.unref?.();
|
|
346
|
+
};
|
|
323
347
|
const abortListener = () => {
|
|
324
|
-
|
|
348
|
+
requestStop();
|
|
325
349
|
};
|
|
326
|
-
const handleSigint = () =>
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
350
|
+
const handleSigint = () => {
|
|
351
|
+
requestStop();
|
|
352
|
+
};
|
|
353
|
+
const handleSigterm = () => {
|
|
354
|
+
requestStop();
|
|
355
|
+
};
|
|
356
|
+
const issueForcedExit = (code) => {
|
|
357
|
+
if (forceExitIssued) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
forceExitIssued = true;
|
|
361
|
+
visualizer?.close();
|
|
362
|
+
destroyClientPasswordSessions();
|
|
363
|
+
return deps.forceExit(code);
|
|
364
|
+
};
|
|
365
|
+
const gracefulRun = async () => {
|
|
366
|
+
try {
|
|
367
|
+
await takeOverMiningRuntime({
|
|
368
|
+
paths: options.runtime.paths,
|
|
369
|
+
reason: "mine-foreground-replace",
|
|
370
|
+
shutdownGraceMs,
|
|
371
|
+
deps,
|
|
372
|
+
});
|
|
373
|
+
if (visualizer === null) {
|
|
374
|
+
visualizer = new MiningFollowVisualizer({
|
|
375
|
+
clientVersion: options.clientVersion,
|
|
376
|
+
updateAvailable: options.updateAvailable,
|
|
377
|
+
progressOutput: options.progressOutput ?? "auto",
|
|
378
|
+
stream: options.stderr,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
await deps.runMiningLoop({
|
|
382
|
+
dataDir: options.dataDir,
|
|
383
|
+
databasePath: options.databasePath,
|
|
384
|
+
provider: options.runtime.provider,
|
|
385
|
+
paths: options.runtime.paths,
|
|
386
|
+
runMode: "foreground",
|
|
387
|
+
backgroundWorkerPid: null,
|
|
388
|
+
backgroundWorkerRunId: null,
|
|
389
|
+
signal: abortController.signal,
|
|
390
|
+
fetchImpl: options.fetchImpl,
|
|
391
|
+
openReadContext: options.runtime.openReadContext,
|
|
392
|
+
attachService: options.runtime.attachService,
|
|
393
|
+
rpcFactory: options.runtime.rpcFactory,
|
|
394
|
+
stdout: options.stdout,
|
|
395
|
+
visualizer,
|
|
396
|
+
});
|
|
397
|
+
await deps.saveStopSnapshot({
|
|
398
|
+
dataDir: options.dataDir,
|
|
399
|
+
databasePath: options.databasePath,
|
|
400
|
+
provider: options.runtime.provider,
|
|
401
|
+
paths: options.runtime.paths,
|
|
402
|
+
runMode: "foreground",
|
|
403
|
+
backgroundWorkerPid: null,
|
|
404
|
+
backgroundWorkerRunId: null,
|
|
405
|
+
note: "Foreground mining stopped cleanly.",
|
|
341
406
|
});
|
|
342
407
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
provider: options.runtime.provider,
|
|
350
|
-
paths: options.runtime.paths,
|
|
351
|
-
runMode: "foreground",
|
|
352
|
-
backgroundWorkerPid: null,
|
|
353
|
-
backgroundWorkerRunId: null,
|
|
354
|
-
signal: abortController.signal,
|
|
355
|
-
fetchImpl: options.fetchImpl,
|
|
356
|
-
openReadContext: options.runtime.openReadContext,
|
|
357
|
-
attachService: options.runtime.attachService,
|
|
358
|
-
rpcFactory: options.runtime.rpcFactory,
|
|
359
|
-
stdout: options.stdout,
|
|
360
|
-
visualizer,
|
|
361
|
-
});
|
|
362
|
-
await deps.saveStopSnapshot({
|
|
363
|
-
dataDir: options.dataDir,
|
|
364
|
-
databasePath: options.databasePath,
|
|
365
|
-
provider: options.runtime.provider,
|
|
366
|
-
paths: options.runtime.paths,
|
|
367
|
-
runMode: "foreground",
|
|
368
|
-
backgroundWorkerPid: null,
|
|
369
|
-
backgroundWorkerRunId: null,
|
|
370
|
-
note: "Foreground mining stopped cleanly.",
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
finally {
|
|
374
|
-
options.signal?.removeEventListener("abort", abortListener);
|
|
375
|
-
process.off("SIGINT", handleSigint);
|
|
376
|
-
process.off("SIGTERM", handleSigterm);
|
|
377
|
-
if (ownsVisualizer) {
|
|
378
|
-
visualizer?.close();
|
|
408
|
+
finally {
|
|
409
|
+
if (ownsVisualizer) {
|
|
410
|
+
visualizer?.close();
|
|
411
|
+
}
|
|
412
|
+
await controlLock.release();
|
|
413
|
+
destroyClientPasswordSessions();
|
|
379
414
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
}
|
|
383
|
-
export async function startBackgroundMining(options) {
|
|
384
|
-
const deps = resolveSupervisorDependencies(options.deps);
|
|
385
|
-
const waitForHealthy = options.waitForBackgroundHealthy
|
|
386
|
-
?? (async (paths) => await waitForBackgroundHealthy(paths, deps));
|
|
387
|
-
let controlLock;
|
|
415
|
+
};
|
|
416
|
+
const gracefulRunPromise = gracefulRun();
|
|
388
417
|
try {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
418
|
+
if (options.signal?.aborted) {
|
|
419
|
+
requestStop();
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
options.signal?.addEventListener("abort", abortListener, { once: true });
|
|
423
|
+
}
|
|
424
|
+
if (!usesExternalSignal) {
|
|
425
|
+
process.on("SIGINT", handleSigint);
|
|
426
|
+
process.on("SIGTERM", handleSigterm);
|
|
427
|
+
}
|
|
428
|
+
await Promise.race([
|
|
429
|
+
gracefulRunPromise,
|
|
430
|
+
shutdownDeadline,
|
|
431
|
+
]);
|
|
396
432
|
}
|
|
397
433
|
catch (error) {
|
|
398
|
-
if (error instanceof
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
};
|
|
434
|
+
if (error instanceof ForegroundMiningShutdownTimeoutError) {
|
|
435
|
+
gracefulRunPromise.catch(() => undefined);
|
|
436
|
+
issueForcedExit(130);
|
|
437
|
+
return;
|
|
403
438
|
}
|
|
404
439
|
throw error;
|
|
405
440
|
}
|
|
406
|
-
try {
|
|
407
|
-
await takeOverMiningRuntime({
|
|
408
|
-
paths: options.runtime.paths,
|
|
409
|
-
reason: "mine-start-replace",
|
|
410
|
-
shutdownGraceMs: options.shutdownGraceMs,
|
|
411
|
-
deps,
|
|
412
|
-
});
|
|
413
|
-
const runId = randomBytes(16).toString("hex");
|
|
414
|
-
const child = deps.spawnWorkerProcess(deps.processExecPath, [
|
|
415
|
-
deps.resolveWorkerMainPath(),
|
|
416
|
-
`--data-dir=${options.dataDir}`,
|
|
417
|
-
`--database-path=${options.databasePath}`,
|
|
418
|
-
`--run-id=${runId}`,
|
|
419
|
-
], {
|
|
420
|
-
detached: true,
|
|
421
|
-
stdio: "ignore",
|
|
422
|
-
});
|
|
423
|
-
child.unref();
|
|
424
|
-
const snapshot = await waitForHealthy(options.runtime.paths);
|
|
425
|
-
return {
|
|
426
|
-
started: true,
|
|
427
|
-
snapshot,
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
441
|
finally {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
export async function stopBackgroundMining(options) {
|
|
435
|
-
const deps = resolveSupervisorDependencies(options.deps);
|
|
436
|
-
const shutdownGraceMs = options.shutdownGraceMs ?? MINING_SHUTDOWN_GRACE_MS;
|
|
437
|
-
const controlLock = await deps.acquireLock(options.runtime.paths.miningControlLockPath, {
|
|
438
|
-
purpose: "mine-stop",
|
|
439
|
-
});
|
|
440
|
-
try {
|
|
441
|
-
const snapshot = await deps.loadRuntimeStatus(options.runtime.paths.miningStatusPath).catch(() => null);
|
|
442
|
-
if (snapshot === null || snapshot.runMode !== "background" || snapshot.backgroundWorkerPid === null) {
|
|
443
|
-
return snapshot;
|
|
444
|
-
}
|
|
445
|
-
const preemption = await deps.requestMiningPreemption({
|
|
446
|
-
paths: options.runtime.paths,
|
|
447
|
-
reason: "mine-stop",
|
|
448
|
-
timeoutMs: Math.min(shutdownGraceMs, 15_000),
|
|
449
|
-
}).catch(() => null);
|
|
450
|
-
try {
|
|
451
|
-
try {
|
|
452
|
-
deps.processKill(snapshot.backgroundWorkerPid, "SIGTERM");
|
|
453
|
-
}
|
|
454
|
-
catch (error) {
|
|
455
|
-
if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) {
|
|
456
|
-
throw error;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
const deadline = deps.nowUnixMs() + shutdownGraceMs;
|
|
460
|
-
while (deps.nowUnixMs() < deadline) {
|
|
461
|
-
if (!await isProcessAlive(snapshot.backgroundWorkerPid, deps)) {
|
|
462
|
-
break;
|
|
463
|
-
}
|
|
464
|
-
await deps.sleep(250);
|
|
465
|
-
}
|
|
466
|
-
if (await isProcessAlive(snapshot.backgroundWorkerPid, deps)) {
|
|
467
|
-
try {
|
|
468
|
-
deps.processKill(snapshot.backgroundWorkerPid, "SIGKILL");
|
|
469
|
-
}
|
|
470
|
-
catch {
|
|
471
|
-
// ignore
|
|
472
|
-
}
|
|
473
|
-
}
|
|
442
|
+
if (shutdownDeadlineTimer !== null) {
|
|
443
|
+
clearTimeout(shutdownDeadlineTimer);
|
|
474
444
|
}
|
|
475
|
-
|
|
476
|
-
|
|
445
|
+
options.signal?.removeEventListener("abort", abortListener);
|
|
446
|
+
if (!usesExternalSignal) {
|
|
447
|
+
process.off("SIGINT", handleSigint);
|
|
448
|
+
process.off("SIGTERM", handleSigterm);
|
|
477
449
|
}
|
|
478
|
-
await deps.saveStopSnapshot({
|
|
479
|
-
dataDir: options.dataDir,
|
|
480
|
-
databasePath: options.databasePath,
|
|
481
|
-
provider: options.runtime.provider,
|
|
482
|
-
paths: options.runtime.paths,
|
|
483
|
-
runMode: "background",
|
|
484
|
-
backgroundWorkerPid: snapshot.backgroundWorkerPid,
|
|
485
|
-
backgroundWorkerRunId: snapshot.backgroundWorkerRunId,
|
|
486
|
-
note: snapshot.livePublishInMempool
|
|
487
|
-
? "Background mining stopped. The last mining transaction may still confirm from mempool."
|
|
488
|
-
: "Background mining stopped.",
|
|
489
|
-
});
|
|
490
|
-
return deps.loadRuntimeStatus(options.runtime.paths.miningStatusPath).catch(() => null);
|
|
491
|
-
}
|
|
492
|
-
finally {
|
|
493
|
-
await controlLock.release();
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
export async function runBackgroundMiningWorker(options) {
|
|
497
|
-
const deps = resolveSupervisorDependencies(options.deps);
|
|
498
|
-
const abortController = new AbortController();
|
|
499
|
-
process.on("SIGINT", () => abortController.abort());
|
|
500
|
-
process.on("SIGTERM", () => abortController.abort());
|
|
501
|
-
const initialContext = await options.runtime.openReadContext({
|
|
502
|
-
dataDir: options.dataDir,
|
|
503
|
-
databasePath: options.databasePath,
|
|
504
|
-
secretProvider: options.runtime.provider,
|
|
505
|
-
paths: options.runtime.paths,
|
|
506
|
-
});
|
|
507
|
-
try {
|
|
508
|
-
const initialView = await deps.inspectMiningControlPlane({
|
|
509
|
-
provider: options.runtime.provider,
|
|
510
|
-
localState: initialContext.localState,
|
|
511
|
-
bitcoind: initialContext.bitcoind,
|
|
512
|
-
nodeStatus: initialContext.nodeStatus,
|
|
513
|
-
nodeHealth: initialContext.nodeHealth,
|
|
514
|
-
indexer: initialContext.indexer,
|
|
515
|
-
paths: options.runtime.paths,
|
|
516
|
-
});
|
|
517
|
-
await deps.saveRuntimeStatus(options.runtime.paths.miningStatusPath, {
|
|
518
|
-
...initialView.runtime,
|
|
519
|
-
walletRootId: initialContext.localState.walletRootId,
|
|
520
|
-
workerApiVersion: MINING_WORKER_API_VERSION,
|
|
521
|
-
workerBinaryVersion: process.version,
|
|
522
|
-
workerBuildId: options.runId,
|
|
523
|
-
runMode: "background",
|
|
524
|
-
backgroundWorkerPid: deps.processPid,
|
|
525
|
-
backgroundWorkerRunId: options.runId,
|
|
526
|
-
backgroundWorkerHeartbeatAtUnixMs: deps.nowUnixMs(),
|
|
527
|
-
currentPhase: "idle",
|
|
528
|
-
updatedAtUnixMs: deps.nowUnixMs(),
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
finally {
|
|
532
|
-
await initialContext.close();
|
|
533
450
|
}
|
|
534
|
-
await deps.runMiningLoop({
|
|
535
|
-
dataDir: options.dataDir,
|
|
536
|
-
databasePath: options.databasePath,
|
|
537
|
-
provider: options.runtime.provider,
|
|
538
|
-
paths: options.runtime.paths,
|
|
539
|
-
runMode: "background",
|
|
540
|
-
backgroundWorkerPid: deps.processPid,
|
|
541
|
-
backgroundWorkerRunId: options.runId,
|
|
542
|
-
signal: abortController.signal,
|
|
543
|
-
fetchImpl: options.fetchImpl,
|
|
544
|
-
openReadContext: options.runtime.openReadContext,
|
|
545
|
-
attachService: options.runtime.attachService,
|
|
546
|
-
rpcFactory: options.runtime.rpcFactory,
|
|
547
|
-
});
|
|
548
|
-
await deps.saveStopSnapshot({
|
|
549
|
-
dataDir: options.dataDir,
|
|
550
|
-
databasePath: options.databasePath,
|
|
551
|
-
provider: options.runtime.provider,
|
|
552
|
-
paths: options.runtime.paths,
|
|
553
|
-
runMode: "background",
|
|
554
|
-
backgroundWorkerPid: deps.processPid,
|
|
555
|
-
backgroundWorkerRunId: options.runId,
|
|
556
|
-
note: "Background mining worker stopped cleanly.",
|
|
557
|
-
});
|
|
558
451
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readSnapshotWithRetry } from "../../bitcoind/indexer-daemon.js";
|
|
2
2
|
import { type WalletSecretProvider } from "../state/provider.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { WalletLocalStateStatus, WalletReadContext } from "./types.js";
|
|
4
4
|
import type { WalletRuntimePaths } from "../runtime.js";
|
|
5
5
|
declare function inspectWalletLocalState(options?: {
|
|
6
6
|
dataDir?: string;
|
|
@@ -9,10 +9,6 @@ declare function inspectWalletLocalState(options?: {
|
|
|
9
9
|
paths?: WalletRuntimePaths;
|
|
10
10
|
walletControlLockHeld?: boolean;
|
|
11
11
|
}): Promise<WalletLocalStateStatus>;
|
|
12
|
-
export declare function deriveNodeHealthForTesting(status: WalletNodeStatus | null, bitcoindHealth: WalletBitcoindStatus["health"]): {
|
|
13
|
-
health: WalletServiceHealth;
|
|
14
|
-
message: string | null;
|
|
15
|
-
};
|
|
16
12
|
export declare function openWalletReadContext(options: {
|
|
17
13
|
dataDir: string;
|
|
18
14
|
databasePath: string;
|