@cogcoin/client 1.1.6 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.md +2 -2
  2. package/dist/bitcoind/indexer-daemon.js +29 -79
  3. package/dist/bitcoind/managed-runtime/bitcoind-runtime.d.ts +20 -0
  4. package/dist/bitcoind/managed-runtime/bitcoind-runtime.js +74 -0
  5. package/dist/bitcoind/managed-runtime/bitcoind-status.d.ts +11 -0
  6. package/dist/bitcoind/managed-runtime/bitcoind-status.js +44 -0
  7. package/dist/bitcoind/managed-runtime/indexer-runtime.d.ts +15 -0
  8. package/dist/bitcoind/managed-runtime/indexer-runtime.js +82 -0
  9. package/dist/bitcoind/managed-runtime/types.d.ts +40 -0
  10. package/dist/bitcoind/node.d.ts +2 -2
  11. package/dist/bitcoind/node.js +2 -2
  12. package/dist/bitcoind/rpc.d.ts +2 -1
  13. package/dist/bitcoind/rpc.js +53 -3
  14. package/dist/bitcoind/service.js +47 -127
  15. package/dist/cli/command-registry.d.ts +1 -1
  16. package/dist/cli/command-registry.js +2 -64
  17. package/dist/cli/commands/client-admin.js +3 -18
  18. package/dist/cli/commands/mining-runtime.js +4 -60
  19. package/dist/cli/commands/wallet-admin.js +6 -6
  20. package/dist/cli/context.js +1 -3
  21. package/dist/cli/mining-json.d.ts +1 -22
  22. package/dist/cli/mining-json.js +0 -23
  23. package/dist/cli/output.js +16 -2
  24. package/dist/cli/parse.js +0 -2
  25. package/dist/cli/preview-json.d.ts +1 -22
  26. package/dist/cli/preview-json.js +0 -19
  27. package/dist/cli/types.d.ts +1 -3
  28. package/dist/cli/wallet-format.js +1 -1
  29. package/dist/cli/workflow-hints.d.ts +1 -2
  30. package/dist/cli/workflow-hints.js +5 -8
  31. package/dist/wallet/lifecycle/context.js +0 -1
  32. package/dist/wallet/lifecycle/repair-mining.d.ts +1 -5
  33. package/dist/wallet/lifecycle/repair-mining.js +5 -39
  34. package/dist/wallet/lifecycle/repair.js +0 -3
  35. package/dist/wallet/lifecycle/setup.js +10 -8
  36. package/dist/wallet/lifecycle/types.d.ts +1 -4
  37. package/dist/wallet/managed-core-wallet.d.ts +2 -0
  38. package/dist/wallet/managed-core-wallet.js +27 -1
  39. package/dist/wallet/mining/candidate.d.ts +1 -0
  40. package/dist/wallet/mining/candidate.js +38 -6
  41. package/dist/wallet/mining/competitiveness.d.ts +1 -0
  42. package/dist/wallet/mining/competitiveness.js +6 -0
  43. package/dist/wallet/mining/cycle.d.ts +2 -0
  44. package/dist/wallet/mining/cycle.js +14 -4
  45. package/dist/wallet/mining/engine-state.js +10 -0
  46. package/dist/wallet/mining/engine-types.d.ts +1 -0
  47. package/dist/wallet/mining/index.d.ts +1 -1
  48. package/dist/wallet/mining/index.js +1 -1
  49. package/dist/wallet/mining/publish.d.ts +3 -0
  50. package/dist/wallet/mining/publish.js +78 -6
  51. package/dist/wallet/mining/runner.d.ts +0 -32
  52. package/dist/wallet/mining/runner.js +59 -104
  53. package/dist/wallet/mining/stop.d.ts +7 -0
  54. package/dist/wallet/mining/stop.js +23 -0
  55. package/dist/wallet/mining/supervisor.d.ts +2 -36
  56. package/dist/wallet/mining/supervisor.js +139 -246
  57. package/dist/wallet/mining/visualizer-sync.js +79 -15
  58. package/dist/wallet/read/context.d.ts +1 -5
  59. package/dist/wallet/read/context.js +21 -205
  60. package/dist/wallet/read/managed-services.d.ts +33 -0
  61. package/dist/wallet/read/managed-services.js +222 -0
  62. package/dist/wallet/reset/artifacts.d.ts +16 -0
  63. package/dist/wallet/reset/artifacts.js +141 -0
  64. package/dist/wallet/reset/execution.d.ts +38 -0
  65. package/dist/wallet/reset/execution.js +458 -0
  66. package/dist/wallet/reset/preflight.d.ts +7 -0
  67. package/dist/wallet/reset/preflight.js +116 -0
  68. package/dist/wallet/reset/preview.d.ts +2 -0
  69. package/dist/wallet/reset/preview.js +50 -0
  70. package/dist/wallet/reset/process-cleanup.d.ts +12 -0
  71. package/dist/wallet/reset/process-cleanup.js +179 -0
  72. package/dist/wallet/reset/types.d.ts +189 -0
  73. package/dist/wallet/reset/types.js +1 -0
  74. package/dist/wallet/reset.d.ts +4 -119
  75. package/dist/wallet/reset.js +4 -882
  76. package/dist/wallet/state/client-password/bootstrap.d.ts +2 -0
  77. package/dist/wallet/state/client-password/bootstrap.js +3 -0
  78. package/dist/wallet/state/client-password/context.d.ts +10 -0
  79. package/dist/wallet/state/client-password/context.js +46 -0
  80. package/dist/wallet/state/client-password/crypto.d.ts +34 -0
  81. package/dist/wallet/state/client-password/crypto.js +117 -0
  82. package/dist/wallet/state/client-password/files.d.ts +10 -0
  83. package/dist/wallet/state/client-password/files.js +109 -0
  84. package/dist/wallet/state/client-password/legacy-cleanup.d.ts +11 -0
  85. package/dist/wallet/state/client-password/legacy-cleanup.js +338 -0
  86. package/dist/wallet/state/client-password/messages.d.ts +3 -0
  87. package/dist/wallet/state/client-password/messages.js +9 -0
  88. package/dist/wallet/state/client-password/migration.d.ts +4 -0
  89. package/dist/wallet/state/client-password/migration.js +32 -0
  90. package/dist/wallet/state/client-password/prompts.d.ts +12 -0
  91. package/dist/wallet/state/client-password/prompts.js +79 -0
  92. package/dist/wallet/state/client-password/protected-secrets.d.ts +13 -0
  93. package/dist/wallet/state/client-password/protected-secrets.js +90 -0
  94. package/dist/wallet/state/client-password/readiness.d.ts +4 -0
  95. package/dist/wallet/state/client-password/readiness.js +48 -0
  96. package/dist/wallet/state/client-password/references.d.ts +1 -0
  97. package/dist/wallet/state/client-password/references.js +56 -0
  98. package/dist/wallet/state/client-password/rotation.d.ts +6 -0
  99. package/dist/wallet/state/client-password/rotation.js +98 -0
  100. package/dist/wallet/state/client-password/session-policy.d.ts +6 -0
  101. package/dist/wallet/state/client-password/session-policy.js +28 -0
  102. package/dist/wallet/state/client-password/session.d.ts +19 -0
  103. package/dist/wallet/state/client-password/session.js +170 -0
  104. package/dist/wallet/state/client-password/setup.d.ts +8 -0
  105. package/dist/wallet/state/client-password/setup.js +49 -0
  106. package/dist/wallet/state/client-password/types.d.ts +82 -0
  107. package/dist/wallet/state/client-password/types.js +5 -0
  108. package/dist/wallet/state/client-password.d.ts +7 -38
  109. package/dist/wallet/state/client-password.js +52 -937
  110. package/dist/wallet/tx/anchor.js +123 -216
  111. package/dist/wallet/tx/cog.js +294 -489
  112. package/dist/wallet/tx/common.d.ts +2 -0
  113. package/dist/wallet/tx/common.js +2 -0
  114. package/dist/wallet/tx/domain-admin.js +111 -220
  115. package/dist/wallet/tx/domain-market.js +401 -681
  116. package/dist/wallet/tx/executor.d.ts +176 -0
  117. package/dist/wallet/tx/executor.js +302 -0
  118. package/dist/wallet/tx/field.js +109 -215
  119. package/dist/wallet/tx/register.js +158 -269
  120. package/dist/wallet/tx/reputation.js +120 -227
  121. package/package.json +1 -1
  122. package/dist/wallet/mining/worker-main.d.ts +0 -1
  123. package/dist/wallet/mining/worker-main.js +0 -17
  124. package/dist/wallet/state/client-password-agent.d.ts +0 -1
  125. package/dist/wallet/state/client-password-agent.js +0 -211
@@ -1,7 +1,7 @@
1
1
  export { isMiningGenerationAbortRequested, markMiningGenerationActive, markMiningGenerationInactive, readMiningGenerationActivity, readMiningPreemptionRequest, requestMiningGenerationPreemption, } from "./coordination.js";
2
2
  export { canonicalizeMiningDomainPromptName, inspectMiningDomainPromptState, updateMiningDomainPrompt, } from "./domain-prompts.js";
3
3
  export { followMiningLog, inspectMiningControlPlane, readMiningLog, refreshMiningRuntimeStatus, setupBuiltInMining, } from "./control.js";
4
- export { ensureBuiltInMiningSetupIfNeeded, runBackgroundMiningWorker, runForegroundMining, startBackgroundMining, stopBackgroundMining, type MiningStartResult, } from "./runner.js";
4
+ export { ensureBuiltInMiningSetupIfNeeded, runForegroundMining, } from "./runner.js";
5
5
  export { appendMiningEvent, loadMiningRuntimeStatus, readMiningEvents, resolveRotatedMiningEventsPath, saveMiningRuntimeStatus, } from "./runtime-artifacts.js";
6
6
  export type { MiningSentenceCandidateV1, MiningSentenceGenerationRequestV1, MiningSentenceGenerationResponseV1, } from "./sentence-protocol.js";
7
7
  export { loadClientConfig, saveBuiltInMiningProviderConfig, saveClientConfig, } from "./config.js";
@@ -1,6 +1,6 @@
1
1
  export { isMiningGenerationAbortRequested, markMiningGenerationActive, markMiningGenerationInactive, readMiningGenerationActivity, readMiningPreemptionRequest, requestMiningGenerationPreemption, } from "./coordination.js";
2
2
  export { canonicalizeMiningDomainPromptName, inspectMiningDomainPromptState, updateMiningDomainPrompt, } from "./domain-prompts.js";
3
3
  export { followMiningLog, inspectMiningControlPlane, readMiningLog, refreshMiningRuntimeStatus, setupBuiltInMining, } from "./control.js";
4
- export { ensureBuiltInMiningSetupIfNeeded, runBackgroundMiningWorker, runForegroundMining, startBackgroundMining, stopBackgroundMining, } from "./runner.js";
4
+ export { ensureBuiltInMiningSetupIfNeeded, runForegroundMining, } from "./runner.js";
5
5
  export { appendMiningEvent, loadMiningRuntimeStatus, readMiningEvents, resolveRotatedMiningEventsPath, saveMiningRuntimeStatus, } from "./runtime-artifacts.js";
6
6
  export { loadClientConfig, saveBuiltInMiningProviderConfig, saveClientConfig, } from "./config.js";
@@ -14,6 +14,7 @@ export declare class MiningPublishRejectedError extends Error {
14
14
  }
15
15
  export declare function createStaleMiningCandidateWaitingNote(): string;
16
16
  export declare function createRetryableMiningPublishWaitingNote(): string;
17
+ export declare function createManagedCoreWalletRelockRetryWaitingNote(): string;
17
18
  export declare function createInsufficientFundsMiningPublishWaitingNote(): string;
18
19
  export declare function createInsufficientFundsMiningPublishErrorMessage(): string;
19
20
  export declare function resolveMiningConflictOutpoint(options: {
@@ -56,6 +57,7 @@ export declare function publishCandidateOnce(options: {
56
57
  rpcFactory: (config: Parameters<typeof createRpcClient>[0]) => MiningRpcClient;
57
58
  runId: string | null;
58
59
  appendEventFn?: AppendMiningEventFn;
60
+ throwIfStopping?: () => void;
59
61
  }): Promise<{
60
62
  state: WalletStateV1;
61
63
  txid: string | null;
@@ -75,5 +77,6 @@ export declare function publishCandidate(options: {
75
77
  runId: string | null;
76
78
  publishAttempt?: typeof publishCandidateOnce;
77
79
  appendEventFn: AppendMiningEventFn;
80
+ throwIfStopping?: () => void;
78
81
  }): Promise<MiningPublishOutcome>;
79
82
  export {};
@@ -22,12 +22,21 @@ export class MiningPublishRejectedError extends Error {
22
22
  this.revertedState = revertedState;
23
23
  }
24
24
  }
25
+ class ManagedCoreWalletRelockPendingError extends Error {
26
+ constructor(message) {
27
+ super(message);
28
+ this.name = "ManagedCoreWalletRelockPendingError";
29
+ }
30
+ }
25
31
  export function createStaleMiningCandidateWaitingNote() {
26
32
  return "Mining candidate changed before broadcast: the selected root domain is no longer locally mineable. Skipping this tip and waiting for the next block.";
27
33
  }
28
34
  export function createRetryableMiningPublishWaitingNote() {
29
35
  return "Selected mining candidate did not reach mempool and will be retried on the current tip with refreshed wallet state.";
30
36
  }
37
+ export function createManagedCoreWalletRelockRetryWaitingNote() {
38
+ return "Mining temporarily lost the managed Bitcoin wallet unlock and is retrying.";
39
+ }
31
40
  export function createInsufficientFundsMiningPublishWaitingNote() {
32
41
  return "Insufficient BTC to mine.";
33
42
  }
@@ -114,6 +123,8 @@ async function buildMiningTransaction(options) {
114
123
  mempoolRejectPrefix: "wallet_mining_mempool_rejected",
115
124
  feeRate: options.plan.feeRateSatVb,
116
125
  availableFundingMinConf: MINING_FUNDING_MIN_CONF,
126
+ recoverManagedCoreWalletLockedOnce: options.recoverManagedCoreWalletLockedOnce,
127
+ onManagedCoreWalletLockedRecoveryOutcome: options.onManagedCoreWalletLockedRecoveryOutcome,
117
128
  });
118
129
  }
119
130
  export async function probeMiningFundingAvailability(options) {
@@ -301,6 +312,7 @@ export async function publishCandidateOnce(options) {
301
312
  startHeight: 0,
302
313
  walletRootId: options.readContext.localState.state.walletRootId,
303
314
  });
315
+ options.throwIfStopping?.();
304
316
  const rpc = options.rpcFactory(service.rpc);
305
317
  let state = (await reconcileLiveMiningState({
306
318
  state: options.readContext.localState.state,
@@ -309,7 +321,9 @@ export async function publishCandidateOnce(options) {
309
321
  nodeBestHeight: options.readContext.nodeStatus?.nodeBestHeight ?? null,
310
322
  snapshotState: options.readContext.snapshot.state,
311
323
  })).state;
324
+ options.throwIfStopping?.();
312
325
  const allUtxos = await rpc.listUnspent(state.managedCoreWallet.walletName, MINING_FUNDING_MIN_CONF);
326
+ options.throwIfStopping?.();
313
327
  const conflictOutpoint = resolveMiningConflictOutpoint({
314
328
  state,
315
329
  allUtxos,
@@ -330,6 +344,7 @@ export async function publishCandidateOnce(options) {
330
344
  const feeSelection = await resolveWalletMutationFeeSelection({
331
345
  rpc,
332
346
  });
347
+ options.throwIfStopping?.();
333
348
  const nextFeeRate = feeSelection.feeRateSatVb;
334
349
  const plan = createMiningPlan({
335
350
  state,
@@ -338,12 +353,40 @@ export async function publishCandidateOnce(options) {
338
353
  allUtxos,
339
354
  feeRateSatVb: nextFeeRate,
340
355
  });
341
- const built = await buildMiningTransaction({
342
- rpc,
343
- walletName: state.managedCoreWallet.walletName,
344
- state,
345
- plan,
346
- });
356
+ let managedCoreWalletRelockOutcome = null;
357
+ let built;
358
+ try {
359
+ built = await buildMiningTransaction({
360
+ rpc,
361
+ walletName: state.managedCoreWallet.walletName,
362
+ state,
363
+ plan,
364
+ recoverManagedCoreWalletLockedOnce: true,
365
+ onManagedCoreWalletLockedRecoveryOutcome: (outcome) => {
366
+ managedCoreWalletRelockOutcome = outcome;
367
+ },
368
+ });
369
+ }
370
+ catch (error) {
371
+ if (managedCoreWalletRelockOutcome === "still-locked" && error instanceof Error) {
372
+ throw new ManagedCoreWalletRelockPendingError(error.message);
373
+ }
374
+ throw error;
375
+ }
376
+ options.throwIfStopping?.();
377
+ if (managedCoreWalletRelockOutcome === "recovered" && appendEventFn !== undefined) {
378
+ await appendEventFn(options.paths, createMiningEventRecord("managed-core-wallet-relock-recovered", "Managed Bitcoin Core wallet relocked during signing and was recovered automatically.", {
379
+ level: "warn",
380
+ runId: options.runId,
381
+ targetBlockHeight: options.candidate.targetBlockHeight,
382
+ referencedBlockHashDisplay: options.candidate.referencedBlockHashDisplay,
383
+ domainId: options.candidate.domainId,
384
+ domainName: options.candidate.domainName,
385
+ feeRateSatVb: nextFeeRate,
386
+ score: options.candidate.canonicalBlend.toString(),
387
+ reason: "managed-core-wallet-locked",
388
+ }));
389
+ }
347
390
  const intentFingerprintHex = computeIntentFingerprint(state, options.candidate);
348
391
  state = defaultMiningStatePatch(state, {
349
392
  state: "live",
@@ -375,8 +418,10 @@ export async function publishCandidateOnce(options) {
375
418
  provider: options.provider,
376
419
  paths: options.paths,
377
420
  });
421
+ options.throwIfStopping?.();
378
422
  try {
379
423
  await rpc.sendRawTransaction(built.rawHex);
424
+ options.throwIfStopping?.();
380
425
  }
381
426
  catch (error) {
382
427
  if (isAlreadyAcceptedError(error)) {
@@ -521,6 +566,7 @@ export async function publishCandidate(options) {
521
566
  candidate: null,
522
567
  };
523
568
  };
569
+ options.throwIfStopping?.();
524
570
  const lockedReadContext = await options.openReadContext({
525
571
  dataDir: options.dataDir,
526
572
  databasePath: options.databasePath,
@@ -529,6 +575,7 @@ export async function publishCandidate(options) {
529
575
  paths: options.paths,
530
576
  });
531
577
  try {
578
+ options.throwIfStopping?.();
532
579
  if (lockedReadContext.localState.availability !== "ready"
533
580
  || lockedReadContext.localState.state === null
534
581
  || lockedReadContext.snapshot === null
@@ -541,6 +588,7 @@ export async function publishCandidate(options) {
541
588
  return await createStaleCandidateSkipResult(readyReadContext.localState.state);
542
589
  }
543
590
  try {
591
+ options.throwIfStopping?.();
544
592
  const published = await publishAttempt({
545
593
  readContext: readyReadContext,
546
594
  candidate: refreshedCandidate,
@@ -551,6 +599,7 @@ export async function publishCandidate(options) {
551
599
  rpcFactory: options.rpcFactory,
552
600
  runId: options.runId,
553
601
  appendEventFn: options.appendEventFn,
602
+ throwIfStopping: options.throwIfStopping,
554
603
  });
555
604
  return {
556
605
  ...published,
@@ -558,6 +607,29 @@ export async function publishCandidate(options) {
558
607
  };
559
608
  }
560
609
  catch (error) {
610
+ if (error instanceof ManagedCoreWalletRelockPendingError) {
611
+ const note = createManagedCoreWalletRelockRetryWaitingNote();
612
+ const lastError = error.message;
613
+ await options.appendEventFn(options.paths, createMiningEventRecord("publish-retry-pending", "Managed Bitcoin Core wallet relocked during mining publish and will be retried on the current tip.", {
614
+ level: "warn",
615
+ runId: options.runId,
616
+ targetBlockHeight: refreshedCandidate.targetBlockHeight,
617
+ referencedBlockHashDisplay: refreshedCandidate.referencedBlockHashDisplay,
618
+ domainId: refreshedCandidate.domainId,
619
+ domainName: refreshedCandidate.domainName,
620
+ score: refreshedCandidate.canonicalBlend.toString(),
621
+ reason: "managed-core-wallet-locked",
622
+ }));
623
+ return {
624
+ state: readyReadContext.localState.state,
625
+ txid: null,
626
+ decision: "publish-retry-pending",
627
+ note,
628
+ lastError,
629
+ retryable: true,
630
+ candidate: refreshedCandidate,
631
+ };
632
+ }
561
633
  if (error instanceof Error && error.message === "wallet_mining_mempool_rejected_missing-inputs") {
562
634
  const note = createRetryableMiningPublishWaitingNote();
563
635
  const revertedState = error instanceof MiningPublishRejectedError
@@ -1,4 +1,3 @@
1
- import { spawn } from "node:child_process";
2
1
  import { assaySentences } from "@cogcoin/scoring";
3
2
  import { attachOrStartManagedBitcoindService, probeManagedBitcoindService, stopManagedBitcoindService } from "../../bitcoind/service.js";
4
3
  import { createRpcClient } from "../../bitcoind/node.js";
@@ -13,7 +12,6 @@ import { type MiningRuntimeLoopState } from "./engine-state.js";
13
12
  import { saveStopSnapshot } from "./lifecycle.js";
14
13
  import type { CompetitivenessDecision, MiningCandidate, MiningCooperativeYield, MiningRpcClient } from "./engine-types.js";
15
14
  import { requestMiningGenerationPreemption } from "./coordination.js";
16
- import type { MiningRuntimeStatusV1 } from "./types.js";
17
15
  import { MiningFollowVisualizer } from "./visualizer.js";
18
16
  interface RunnerDependencies {
19
17
  openReadContext?: typeof openWalletReadContext;
@@ -23,8 +21,6 @@ interface RunnerDependencies {
23
21
  requestMiningPreemption?: typeof requestMiningGenerationPreemption;
24
22
  runMiningLoopImpl?: typeof runMiningLoop;
25
23
  saveStopSnapshotImpl?: typeof saveStopSnapshot;
26
- spawnWorkerProcess?: typeof spawn;
27
- waitForBackgroundHealthyImpl?: typeof waitForBackgroundHealthy;
28
24
  shutdownGraceMs?: number;
29
25
  sleepImpl?: typeof sleep;
30
26
  }
@@ -63,24 +59,6 @@ export interface RunForegroundMiningOptions extends RunnerDependencies {
63
59
  paths?: WalletRuntimePaths;
64
60
  visualizer?: MiningFollowVisualizer;
65
61
  }
66
- export interface StartBackgroundMiningOptions extends RunnerDependencies {
67
- dataDir: string;
68
- databasePath: string;
69
- provider?: WalletSecretProvider;
70
- prompter: WalletPrompter;
71
- builtInSetupEnsured?: boolean;
72
- paths?: WalletRuntimePaths;
73
- }
74
- export interface StopBackgroundMiningOptions extends RunnerDependencies {
75
- dataDir: string;
76
- databasePath: string;
77
- provider?: WalletSecretProvider;
78
- paths?: WalletRuntimePaths;
79
- }
80
- export interface MiningStartResult {
81
- started: boolean;
82
- snapshot: MiningRuntimeStatusV1 | null;
83
- }
84
62
  declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
85
63
  declare function generateCandidatesForDomains(options: Parameters<typeof generateCandidatesForDomainsModule>[0]): Promise<MiningCandidate[]>;
86
64
  declare function runCompetitivenessGate(options: Parameters<typeof runCompetitivenessGateModule>[0]): Promise<CompetitivenessDecision>;
@@ -119,17 +97,7 @@ declare function runMiningLoop(options: {
119
97
  cooperativeYieldImpl?: MiningCooperativeYield;
120
98
  cooperativeYieldEvery?: number;
121
99
  }): Promise<void>;
122
- declare function waitForBackgroundHealthy(paths: WalletRuntimePaths): Promise<MiningRuntimeStatusV1 | null>;
123
100
  export declare function runForegroundMining(options: RunForegroundMiningOptions): Promise<void>;
124
- export declare function startBackgroundMining(options: StartBackgroundMiningOptions): Promise<MiningStartResult>;
125
- export declare function stopBackgroundMining(options: StopBackgroundMiningOptions): Promise<MiningRuntimeStatusV1 | null>;
126
- export declare function runBackgroundMiningWorker(options: RunnerDependencies & {
127
- dataDir: string;
128
- databasePath: string;
129
- runId: string;
130
- provider?: WalletSecretProvider;
131
- paths?: WalletRuntimePaths;
132
- }): Promise<void>;
133
101
  export declare function performMiningCycleForTesting(options: {
134
102
  dataDir: string;
135
103
  databasePath: string;
@@ -1,5 +1,4 @@
1
1
  import { createHash } from "node:crypto";
2
- import { spawn } from "node:child_process";
3
2
  import { getBalance, getBlockWinners, lookupDomain, lookupDomainById, } from "@cogcoin/indexer/queries";
4
3
  import { assaySentences, deriveBlendSeed, displayToInternalBlockhash, getWords, settleBlock, } from "@cogcoin/scoring";
5
4
  import { probeIndexerDaemon } from "../../bitcoind/indexer-daemon.js";
@@ -12,7 +11,8 @@ import { extractOpReturnPayloadFromScriptHex } from "../tx/register.js";
12
11
  import { assertFixedInputPrefixMatches, buildWalletMutationTransaction, fundAndValidateWalletMutationDraft, isInsufficientFundsError, outpointKey as walletMutationOutpointKey, isAlreadyAcceptedError, isBroadcastUnknownError, reconcilePersistentPolicyLocks, resolveWalletMutationFeeSelection, saveWalletStatePreservingUnlock, } from "../tx/common.js";
13
12
  import { isMineableWalletDomain, openWalletReadContext, } from "../read/index.js";
14
13
  import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
15
- import { createDefaultWalletSecretProvider, } from "../state/provider.js";
14
+ import { createDefaultWalletSecretProvider, unlockClientPassword, withInteractiveWalletSecretProvider, } from "../state/provider.js";
15
+ import { bindClientPasswordPromptSessionPolicy } from "../state/client-password/session-policy.js";
16
16
  import { serializeMine } from "../cogop/index.js";
17
17
  import { appendMiningEvent } from "./runtime-artifacts.js";
18
18
  import { loadClientConfig } from "./config.js";
@@ -29,7 +29,8 @@ import { attemptSaveMempool, handleDetectedMiningRuntimeResume, handleRecoverabl
29
29
  import { compareLexicographically, deriveMiningWordIndices, getBlockRewardCogtoshi, numberToSats, resolveBip39WordsFromIndices, rootDomain, tieBreakHash, } from "./engine-utils.js";
30
30
  import { isMiningGenerationAbortRequested, markMiningGenerationActive, markMiningGenerationInactive, readMiningGenerationActivity, readMiningPreemptionRequest, requestMiningGenerationPreemption, } from "./coordination.js";
31
31
  import { clearMiningPublishState, miningPublishIsInMempool, miningPublishMayStillExist, normalizeMiningPublishState, normalizeMiningStateRecord, } from "./state.js";
32
- import { runBackgroundMiningWorker as runBackgroundMiningWorkerSupervisor, runForegroundMining as runForegroundMiningSupervisor, startBackgroundMining as startBackgroundMiningSupervisor, stopBackgroundMining as stopBackgroundMiningSupervisor, waitForBackgroundHealthy as waitForBackgroundHealthySupervisor, } from "./supervisor.js";
32
+ import { runForegroundMining as runForegroundMiningSupervisor, } from "./supervisor.js";
33
+ import { isMiningStopRequestedError, throwIfMiningStopRequested, } from "./stop.js";
33
34
  import { createMiningSentenceRequestLimits } from "./sentence-protocol.js";
34
35
  import { generateMiningSentences, MiningProviderRequestError } from "./sentences.js";
35
36
  import { MiningFollowVisualizer, } from "./visualizer.js";
@@ -106,6 +107,10 @@ function clearMiningGateCache(walletRootId) {
106
107
  }
107
108
  function sleep(ms, signal) {
108
109
  return new Promise((resolve) => {
110
+ if (signal?.aborted) {
111
+ resolve();
112
+ return;
113
+ }
109
114
  const timer = setTimeout(resolve, ms);
110
115
  signal?.addEventListener("abort", () => {
111
116
  clearTimeout(timer);
@@ -171,6 +176,9 @@ async function performMiningCycle(options) {
171
176
  const now = options.nowImpl ?? Date.now;
172
177
  const generateCandidatesForDomainsImpl = options.generateCandidatesForDomainsImpl ?? generateCandidatesForDomains;
173
178
  const runCompetitivenessGateImpl = options.runCompetitivenessGateImpl ?? runCompetitivenessGate;
179
+ const throwIfStopping = () => {
180
+ throwIfMiningStopRequested(options.signal);
181
+ };
174
182
  let readContext = await options.openReadContext({
175
183
  dataDir: options.dataDir,
176
184
  databasePath: options.databasePath,
@@ -179,6 +187,7 @@ async function performMiningCycle(options) {
179
187
  });
180
188
  let readContextClosed = false;
181
189
  try {
190
+ throwIfStopping();
182
191
  throwIfMiningSuspendDetected(options.suspendDetector);
183
192
  let clearRecoveredBitcoindError = false;
184
193
  const saveCycleStatus = async (readContext, overrides, includeVisualizer = true) => {
@@ -223,6 +232,7 @@ async function performMiningCycle(options) {
223
232
  startHeight: 0,
224
233
  walletRootId: readContext.localState.state.walletRootId,
225
234
  });
235
+ throwIfStopping();
226
236
  throwIfMiningSuspendDetected(options.suspendDetector);
227
237
  const rpc = options.rpcFactory(service.rpc);
228
238
  const reconciliation = await reconcileLiveMiningState({
@@ -232,6 +242,7 @@ async function performMiningCycle(options) {
232
242
  nodeBestHeight: readContext.nodeStatus?.nodeBestHeight ?? null,
233
243
  snapshotState: readContext.snapshot?.state ?? null,
234
244
  });
245
+ throwIfStopping();
235
246
  const reconciledState = reconciliation.state;
236
247
  throwIfMiningSuspendDetected(options.suspendDetector);
237
248
  let effectiveReadContext = readContext;
@@ -262,6 +273,7 @@ async function performMiningCycle(options) {
262
273
  indexedTipHeight: indexedTip?.height ?? null,
263
274
  indexedTipHashHex: indexedTip?.blockHashHex ?? null,
264
275
  }).catch(() => ({}));
276
+ throwIfStopping();
265
277
  syncMiningVisualizerBlockTimes(options.loopState, visibleBlockTimes);
266
278
  const { targetBlockHeight, tipKey, tipChanged } = syncMiningUiForCurrentTip({
267
279
  loopState: options.loopState,
@@ -351,6 +363,7 @@ async function performMiningCycle(options) {
351
363
  rpc.getNetworkInfo(),
352
364
  rpc.getMempoolInfo(),
353
365
  ]);
366
+ throwIfStopping();
354
367
  throwIfMiningSuspendDetected(options.suspendDetector);
355
368
  const corePublishState = determineCorePublishState({
356
369
  blockchain: blockchainInfo,
@@ -414,12 +427,17 @@ async function performMiningCycle(options) {
414
427
  nowImpl: now,
415
428
  saveCycleStatus: async (context, overrides) => await saveCycleStatus(context, overrides),
416
429
  appendEvent: async (event) => await appendEvent(options.paths, event),
430
+ stopSignal: options.signal,
431
+ throwIfStopping,
417
432
  throwIfSuspendDetected: () => {
418
433
  throwIfMiningSuspendDetected(options.suspendDetector);
419
434
  },
420
435
  });
421
436
  }
422
437
  catch (error) {
438
+ if (isMiningStopRequestedError(error)) {
439
+ return;
440
+ }
423
441
  if (error instanceof MiningSuspendDetectedError) {
424
442
  discardMiningLoopTransientWork(options.loopState, readContext?.localState.walletRootId ?? undefined);
425
443
  if (readContext !== null && !readContextClosed) {
@@ -482,9 +500,13 @@ async function runMiningLoop(options) {
482
500
  }));
483
501
  while (!options.signal?.aborted) {
484
502
  try {
503
+ throwIfMiningStopRequested(options.signal);
485
504
  throwIfMiningSuspendDetected(suspendDetector);
486
505
  }
487
506
  catch (error) {
507
+ if (isMiningStopRequestedError(error)) {
508
+ break;
509
+ }
488
510
  if (!(error instanceof MiningSuspendDetectedError)) {
489
511
  throw error;
490
512
  }
@@ -504,18 +526,35 @@ async function runMiningLoop(options) {
504
526
  });
505
527
  continue;
506
528
  }
507
- await performMiningCycle({
508
- ...options,
509
- suspendDetector,
510
- assaySentencesImpl: options.assaySentencesImpl,
511
- cooperativeYieldImpl: options.cooperativeYieldImpl,
512
- cooperativeYieldEvery: options.cooperativeYieldEvery,
513
- loopState,
514
- probeService,
515
- stopService,
516
- });
529
+ try {
530
+ await performMiningCycle({
531
+ ...options,
532
+ suspendDetector,
533
+ assaySentencesImpl: options.assaySentencesImpl,
534
+ cooperativeYieldImpl: options.cooperativeYieldImpl,
535
+ cooperativeYieldEvery: options.cooperativeYieldEvery,
536
+ loopState,
537
+ probeService,
538
+ stopService,
539
+ });
540
+ }
541
+ catch (error) {
542
+ if (isMiningStopRequestedError(error)) {
543
+ break;
544
+ }
545
+ throw error;
546
+ }
547
+ if (options.signal?.aborted) {
548
+ break;
549
+ }
517
550
  await sleepImpl(Math.min(MINING_LOOP_INTERVAL_MS, MINING_STATUS_HEARTBEAT_INTERVAL_MS), options.signal);
518
551
  }
552
+ if (options.signal?.aborted) {
553
+ await appendEvent(options.paths, createEvent("runtime-stop", `Stopped ${options.runMode} mining runtime.`, {
554
+ runId: options.backgroundWorkerRunId,
555
+ }));
556
+ return;
557
+ }
519
558
  const service = await options.attachService({
520
559
  dataDir: options.dataDir,
521
560
  chain: "main",
@@ -537,29 +576,30 @@ async function runMiningLoop(options) {
537
576
  stopMiningSuspendDetector(suspendDetector);
538
577
  }
539
578
  }
540
- async function waitForBackgroundHealthy(paths) {
541
- return await waitForBackgroundHealthySupervisor(paths);
542
- }
543
579
  export async function runForegroundMining(options) {
544
580
  if (!options.prompter.isInteractive) {
545
581
  throw new Error("mine_requires_tty");
546
582
  }
547
- const provider = options.provider ?? createDefaultWalletSecretProvider();
583
+ const miningPrompter = bindClientPasswordPromptSessionPolicy(options.prompter, "mining-indefinite");
584
+ const provider = withInteractiveWalletSecretProvider(options.provider ?? createDefaultWalletSecretProvider(), miningPrompter);
548
585
  const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
549
586
  const openReadContext = options.openReadContext ?? openWalletReadContext;
550
587
  const attachService = options.attachService ?? attachOrStartManagedBitcoindService;
551
- const rpcFactory = options.rpcFactory ?? createRpcClient;
588
+ const rpcFactory = options.rpcFactory ?? ((config) => createRpcClient(config, {
589
+ abortSignal: options.signal,
590
+ }));
552
591
  const requestMiningPreemption = options.requestMiningPreemption ?? requestMiningGenerationPreemption;
553
592
  const setupReady = options.builtInSetupEnsured === true
554
593
  ? true
555
594
  : await ensureBuiltInMiningSetupIfNeeded({
556
595
  provider,
557
- prompter: options.prompter,
596
+ prompter: miningPrompter,
558
597
  paths,
559
598
  });
560
599
  if (!setupReady) {
561
600
  throw new Error("Built-in mining provider is not configured. Run `cogcoin mine setup`.");
562
601
  }
602
+ await unlockClientPassword(provider, miningPrompter);
563
603
  await runForegroundMiningSupervisor({
564
604
  dataDir: options.dataDir,
565
605
  databasePath: options.databasePath,
@@ -587,91 +627,6 @@ export async function runForegroundMining(options) {
587
627
  },
588
628
  });
589
629
  }
590
- export async function startBackgroundMining(options) {
591
- const provider = options.provider ?? createDefaultWalletSecretProvider();
592
- const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
593
- const requestMiningPreemption = options.requestMiningPreemption ?? requestMiningGenerationPreemption;
594
- const waitForBackgroundHealthyImpl = options.waitForBackgroundHealthyImpl ?? waitForBackgroundHealthy;
595
- const openReadContext = options.openReadContext ?? openWalletReadContext;
596
- const attachService = options.attachService ?? attachOrStartManagedBitcoindService;
597
- const rpcFactory = options.rpcFactory ?? createRpcClient;
598
- const setupReady = options.builtInSetupEnsured === true
599
- ? true
600
- : await ensureBuiltInMiningSetupIfNeeded({
601
- provider,
602
- prompter: options.prompter,
603
- paths,
604
- });
605
- if (!setupReady) {
606
- throw new Error("Built-in mining provider is not configured. Run `cogcoin mine setup`.");
607
- }
608
- return await startBackgroundMiningSupervisor({
609
- dataDir: options.dataDir,
610
- databasePath: options.databasePath,
611
- shutdownGraceMs: options.shutdownGraceMs,
612
- waitForBackgroundHealthy: waitForBackgroundHealthyImpl,
613
- runtime: {
614
- provider,
615
- paths,
616
- openReadContext,
617
- attachService,
618
- rpcFactory,
619
- },
620
- deps: {
621
- requestMiningPreemption,
622
- spawnWorkerProcess: options.spawnWorkerProcess,
623
- sleep: options.sleepImpl,
624
- },
625
- });
626
- }
627
- export async function stopBackgroundMining(options) {
628
- const provider = options.provider ?? createDefaultWalletSecretProvider();
629
- const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
630
- const openReadContext = options.openReadContext ?? openWalletReadContext;
631
- const attachService = options.attachService ?? attachOrStartManagedBitcoindService;
632
- const rpcFactory = options.rpcFactory ?? createRpcClient;
633
- return await stopBackgroundMiningSupervisor({
634
- dataDir: options.dataDir,
635
- databasePath: options.databasePath,
636
- shutdownGraceMs: options.shutdownGraceMs,
637
- runtime: {
638
- provider,
639
- paths,
640
- openReadContext,
641
- attachService,
642
- rpcFactory,
643
- },
644
- deps: {
645
- requestMiningPreemption: options.requestMiningPreemption,
646
- saveStopSnapshot: options.saveStopSnapshotImpl,
647
- sleep: options.sleepImpl,
648
- },
649
- });
650
- }
651
- export async function runBackgroundMiningWorker(options) {
652
- const provider = options.provider ?? createDefaultWalletSecretProvider();
653
- const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
654
- const openReadContext = options.openReadContext ?? openWalletReadContext;
655
- const attachService = options.attachService ?? attachOrStartManagedBitcoindService;
656
- const rpcFactory = options.rpcFactory ?? createRpcClient;
657
- await runBackgroundMiningWorkerSupervisor({
658
- dataDir: options.dataDir,
659
- databasePath: options.databasePath,
660
- runId: options.runId,
661
- fetchImpl: options.fetchImpl,
662
- runtime: {
663
- provider,
664
- paths,
665
- openReadContext,
666
- attachService,
667
- rpcFactory,
668
- },
669
- deps: {
670
- runMiningLoop: options.runMiningLoopImpl ?? runMiningLoop,
671
- saveStopSnapshot: options.saveStopSnapshotImpl,
672
- },
673
- });
674
- }
675
630
  export async function performMiningCycleForTesting(options) {
676
631
  await performMiningCycle({
677
632
  ...options,
@@ -0,0 +1,7 @@
1
+ export declare const MINING_STOP_REQUESTED_ERROR_CODE = "mining_runtime_stop_requested";
2
+ export declare class MiningStopRequestedError extends Error {
3
+ constructor();
4
+ }
5
+ export declare function isMiningStopRequestedError(error: unknown): error is Error;
6
+ export declare function createMiningStopRequestedError(): MiningStopRequestedError;
7
+ export declare function throwIfMiningStopRequested(signal: AbortSignal | undefined): void;
@@ -0,0 +1,23 @@
1
+ export const MINING_STOP_REQUESTED_ERROR_CODE = "mining_runtime_stop_requested";
2
+ export class MiningStopRequestedError extends Error {
3
+ constructor() {
4
+ super(MINING_STOP_REQUESTED_ERROR_CODE);
5
+ this.name = "MiningStopRequestedError";
6
+ }
7
+ }
8
+ export function isMiningStopRequestedError(error) {
9
+ return error instanceof Error && error.message === MINING_STOP_REQUESTED_ERROR_CODE;
10
+ }
11
+ export function createMiningStopRequestedError() {
12
+ return new MiningStopRequestedError();
13
+ }
14
+ export function throwIfMiningStopRequested(signal) {
15
+ if (!signal?.aborted) {
16
+ return;
17
+ }
18
+ const reason = signal.reason;
19
+ if (reason instanceof Error) {
20
+ throw reason;
21
+ }
22
+ throw createMiningStopRequestedError();
23
+ }