@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.
- package/README.md +2 -2
- package/dist/bitcoind/indexer-daemon.js +29 -79
- 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-runtime.d.ts +15 -0
- package/dist/bitcoind/managed-runtime/indexer-runtime.js +82 -0
- package/dist/bitcoind/managed-runtime/types.d.ts +40 -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.js +47 -127
- 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/context.js +0 -1
- package/dist/wallet/lifecycle/repair-mining.d.ts +1 -5
- package/dist/wallet/lifecycle/repair-mining.js +5 -39
- package/dist/wallet/lifecycle/repair.js +0 -3
- package/dist/wallet/lifecycle/setup.js +10 -8
- package/dist/wallet/lifecycle/types.d.ts +1 -4
- 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-state.js +10 -0
- 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/mining/visualizer-sync.js +79 -15
- package/dist/wallet/read/context.d.ts +1 -5
- package/dist/wallet/read/context.js +21 -205
- package/dist/wallet/read/managed-services.d.ts +33 -0
- package/dist/wallet/read/managed-services.js +222 -0
- package/dist/wallet/reset/artifacts.d.ts +16 -0
- package/dist/wallet/reset/artifacts.js +141 -0
- package/dist/wallet/reset/execution.d.ts +38 -0
- package/dist/wallet/reset/execution.js +458 -0
- package/dist/wallet/reset/preflight.d.ts +7 -0
- package/dist/wallet/reset/preflight.js +116 -0
- package/dist/wallet/reset/preview.d.ts +2 -0
- package/dist/wallet/reset/preview.js +50 -0
- package/dist/wallet/reset/process-cleanup.d.ts +12 -0
- package/dist/wallet/reset/process-cleanup.js +179 -0
- package/dist/wallet/reset/types.d.ts +189 -0
- package/dist/wallet/reset/types.js +1 -0
- package/dist/wallet/reset.d.ts +4 -119
- package/dist/wallet/reset.js +4 -882
- 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.d.ts +0 -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
|
@@ -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,
|
|
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,
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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 {
|
|
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
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
|
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:
|
|
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
|
+
}
|