@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.
Files changed (132) hide show
  1. package/README.md +2 -2
  2. package/dist/bitcoind/indexer-daemon.d.ts +3 -7
  3. package/dist/bitcoind/indexer-daemon.js +39 -204
  4. package/dist/bitcoind/managed-runtime/bitcoind-policy.d.ts +16 -0
  5. package/dist/bitcoind/managed-runtime/bitcoind-policy.js +177 -0
  6. package/dist/bitcoind/managed-runtime/bitcoind-runtime.d.ts +20 -0
  7. package/dist/bitcoind/managed-runtime/bitcoind-runtime.js +74 -0
  8. package/dist/bitcoind/managed-runtime/bitcoind-status.d.ts +11 -0
  9. package/dist/bitcoind/managed-runtime/bitcoind-status.js +44 -0
  10. package/dist/bitcoind/managed-runtime/indexer-policy.d.ts +34 -0
  11. package/dist/bitcoind/managed-runtime/indexer-policy.js +200 -0
  12. package/dist/bitcoind/managed-runtime/indexer-runtime.d.ts +15 -0
  13. package/dist/bitcoind/managed-runtime/indexer-runtime.js +82 -0
  14. package/dist/bitcoind/managed-runtime/status.d.ts +11 -0
  15. package/dist/bitcoind/managed-runtime/status.js +59 -0
  16. package/dist/bitcoind/managed-runtime/types.d.ts +77 -0
  17. package/dist/bitcoind/node.d.ts +2 -2
  18. package/dist/bitcoind/node.js +2 -2
  19. package/dist/bitcoind/rpc.d.ts +2 -1
  20. package/dist/bitcoind/rpc.js +53 -3
  21. package/dist/bitcoind/service.d.ts +2 -7
  22. package/dist/bitcoind/service.js +79 -207
  23. package/dist/cli/command-registry.d.ts +1 -1
  24. package/dist/cli/command-registry.js +2 -64
  25. package/dist/cli/commands/client-admin.js +3 -18
  26. package/dist/cli/commands/mining-runtime.js +4 -60
  27. package/dist/cli/commands/wallet-admin.js +6 -6
  28. package/dist/cli/context.js +1 -3
  29. package/dist/cli/mining-json.d.ts +1 -22
  30. package/dist/cli/mining-json.js +0 -23
  31. package/dist/cli/output.js +16 -2
  32. package/dist/cli/parse.js +0 -2
  33. package/dist/cli/preview-json.d.ts +1 -22
  34. package/dist/cli/preview-json.js +0 -19
  35. package/dist/cli/types.d.ts +1 -3
  36. package/dist/cli/wallet-format.js +1 -1
  37. package/dist/cli/workflow-hints.d.ts +1 -2
  38. package/dist/cli/workflow-hints.js +5 -8
  39. package/dist/wallet/lifecycle/access.d.ts +5 -0
  40. package/dist/wallet/lifecycle/access.js +79 -0
  41. package/dist/wallet/lifecycle/context.d.ts +26 -0
  42. package/dist/wallet/lifecycle/context.js +57 -0
  43. package/dist/wallet/lifecycle/managed-core.d.ts +1 -9
  44. package/dist/wallet/lifecycle/managed-core.js +3 -63
  45. package/dist/wallet/lifecycle/repair-bitcoind.d.ts +10 -0
  46. package/dist/wallet/lifecycle/repair-bitcoind.js +142 -0
  47. package/dist/wallet/lifecycle/repair-indexer.d.ts +8 -0
  48. package/dist/wallet/lifecycle/repair-indexer.js +117 -0
  49. package/dist/wallet/lifecycle/repair-mining.d.ts +1 -5
  50. package/dist/wallet/lifecycle/repair-mining.js +5 -39
  51. package/dist/wallet/lifecycle/repair.d.ts +2 -4
  52. package/dist/wallet/lifecycle/repair.js +74 -318
  53. package/dist/wallet/lifecycle/setup-prompts.d.ts +7 -0
  54. package/dist/wallet/lifecycle/setup-prompts.js +88 -0
  55. package/dist/wallet/lifecycle/setup-state.d.ts +26 -0
  56. package/dist/wallet/lifecycle/setup-state.js +159 -0
  57. package/dist/wallet/lifecycle/setup.d.ts +3 -4
  58. package/dist/wallet/lifecycle/setup.js +47 -351
  59. package/dist/wallet/lifecycle/types.d.ts +33 -5
  60. package/dist/wallet/managed-core-wallet.d.ts +2 -0
  61. package/dist/wallet/managed-core-wallet.js +27 -1
  62. package/dist/wallet/mining/candidate.d.ts +1 -0
  63. package/dist/wallet/mining/candidate.js +38 -6
  64. package/dist/wallet/mining/competitiveness.d.ts +1 -0
  65. package/dist/wallet/mining/competitiveness.js +6 -0
  66. package/dist/wallet/mining/cycle.d.ts +2 -0
  67. package/dist/wallet/mining/cycle.js +14 -4
  68. package/dist/wallet/mining/engine-types.d.ts +1 -0
  69. package/dist/wallet/mining/index.d.ts +1 -1
  70. package/dist/wallet/mining/index.js +1 -1
  71. package/dist/wallet/mining/publish.d.ts +3 -0
  72. package/dist/wallet/mining/publish.js +78 -6
  73. package/dist/wallet/mining/runner.d.ts +0 -32
  74. package/dist/wallet/mining/runner.js +59 -104
  75. package/dist/wallet/mining/stop.d.ts +7 -0
  76. package/dist/wallet/mining/stop.js +23 -0
  77. package/dist/wallet/mining/supervisor.d.ts +2 -36
  78. package/dist/wallet/mining/supervisor.js +139 -246
  79. package/dist/wallet/read/context.d.ts +1 -5
  80. package/dist/wallet/read/context.js +20 -379
  81. package/dist/wallet/read/managed-services.d.ts +33 -0
  82. package/dist/wallet/read/managed-services.js +222 -0
  83. package/dist/wallet/state/client-password/bootstrap.d.ts +2 -0
  84. package/dist/wallet/state/client-password/bootstrap.js +3 -0
  85. package/dist/wallet/state/client-password/context.d.ts +10 -0
  86. package/dist/wallet/state/client-password/context.js +46 -0
  87. package/dist/wallet/state/client-password/crypto.d.ts +34 -0
  88. package/dist/wallet/state/client-password/crypto.js +117 -0
  89. package/dist/wallet/state/client-password/files.d.ts +10 -0
  90. package/dist/wallet/state/client-password/files.js +109 -0
  91. package/dist/wallet/state/client-password/legacy-cleanup.d.ts +11 -0
  92. package/dist/wallet/state/client-password/legacy-cleanup.js +338 -0
  93. package/dist/wallet/state/client-password/messages.d.ts +3 -0
  94. package/dist/wallet/state/client-password/messages.js +9 -0
  95. package/dist/wallet/state/client-password/migration.d.ts +4 -0
  96. package/dist/wallet/state/client-password/migration.js +32 -0
  97. package/dist/wallet/state/client-password/prompts.d.ts +12 -0
  98. package/dist/wallet/state/client-password/prompts.js +79 -0
  99. package/dist/wallet/state/client-password/protected-secrets.d.ts +13 -0
  100. package/dist/wallet/state/client-password/protected-secrets.js +90 -0
  101. package/dist/wallet/state/client-password/readiness.d.ts +4 -0
  102. package/dist/wallet/state/client-password/readiness.js +48 -0
  103. package/dist/wallet/state/client-password/references.d.ts +1 -0
  104. package/dist/wallet/state/client-password/references.js +56 -0
  105. package/dist/wallet/state/client-password/rotation.d.ts +6 -0
  106. package/dist/wallet/state/client-password/rotation.js +98 -0
  107. package/dist/wallet/state/client-password/session-policy.d.ts +6 -0
  108. package/dist/wallet/state/client-password/session-policy.js +28 -0
  109. package/dist/wallet/state/client-password/session.d.ts +19 -0
  110. package/dist/wallet/state/client-password/session.js +170 -0
  111. package/dist/wallet/state/client-password/setup.d.ts +8 -0
  112. package/dist/wallet/state/client-password/setup.js +49 -0
  113. package/dist/wallet/state/client-password/types.d.ts +82 -0
  114. package/dist/wallet/state/client-password/types.js +5 -0
  115. package/dist/wallet/state/client-password.d.ts +7 -38
  116. package/dist/wallet/state/client-password.js +52 -937
  117. package/dist/wallet/tx/anchor.js +123 -216
  118. package/dist/wallet/tx/cog.js +294 -489
  119. package/dist/wallet/tx/common.d.ts +2 -0
  120. package/dist/wallet/tx/common.js +2 -0
  121. package/dist/wallet/tx/domain-admin.js +111 -220
  122. package/dist/wallet/tx/domain-market.js +401 -681
  123. package/dist/wallet/tx/executor.d.ts +176 -0
  124. package/dist/wallet/tx/executor.js +302 -0
  125. package/dist/wallet/tx/field.js +109 -215
  126. package/dist/wallet/tx/register.js +158 -269
  127. package/dist/wallet/tx/reputation.js +120 -227
  128. package/package.json +1 -1
  129. package/dist/wallet/mining/worker-main.js +0 -17
  130. package/dist/wallet/state/client-password-agent.d.ts +0 -1
  131. package/dist/wallet/state/client-password-agent.js +0 -211
  132. /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 { inspectMiningControlPlane } from "./control.js";
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
- processExecPath: overrides.processExecPath ?? process.execPath,
46
- resolveWorkerMainPath: overrides.resolveWorkerMainPath
47
- ?? (() => fileURLToPath(new URL("./worker-main.js", import.meta.url))),
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: options.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
- abortController.abort();
348
+ requestStop();
325
349
  };
326
- const handleSigint = () => abortController.abort();
327
- const handleSigterm = () => abortController.abort();
328
- try {
329
- await takeOverMiningRuntime({
330
- paths: options.runtime.paths,
331
- reason: "mine-foreground-replace",
332
- shutdownGraceMs: options.shutdownGraceMs,
333
- deps,
334
- });
335
- if (visualizer === null) {
336
- visualizer = new MiningFollowVisualizer({
337
- clientVersion: options.clientVersion,
338
- updateAvailable: options.updateAvailable,
339
- progressOutput: options.progressOutput ?? "auto",
340
- stream: options.stderr,
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
- options.signal?.addEventListener("abort", abortListener, { once: true });
344
- process.on("SIGINT", handleSigint);
345
- process.on("SIGTERM", handleSigterm);
346
- await deps.runMiningLoop({
347
- dataDir: options.dataDir,
348
- databasePath: options.databasePath,
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
- await controlLock.release();
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
- controlLock = await acquireMiningStartControlLock({
390
- paths: options.runtime.paths,
391
- purpose: "mine-start",
392
- takeoverReason: "mine-start-replace",
393
- shutdownGraceMs: options.shutdownGraceMs,
394
- deps,
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 FileLockBusyError && error.existingMetadata?.processId === deps.processPid) {
399
- return {
400
- started: false,
401
- snapshot: await deps.loadRuntimeStatus(options.runtime.paths.miningStatusPath).catch(() => null),
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
- await controlLock.release();
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
- finally {
476
- await preemption?.release().catch(() => undefined);
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 { WalletBitcoindStatus, WalletLocalStateStatus, WalletNodeStatus, WalletReadContext, WalletServiceHealth } from "./types.js";
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;