@cogcoin/client 1.1.9 → 1.1.10
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 +1 -1
- package/dist/bitcoind/managed-bitcoind-service-config.d.ts +13 -0
- package/dist/bitcoind/managed-bitcoind-service-config.js +165 -0
- package/dist/bitcoind/managed-bitcoind-service-lifecycle.d.ts +28 -0
- package/dist/bitcoind/managed-bitcoind-service-lifecycle.js +290 -0
- package/dist/bitcoind/managed-bitcoind-service-process.d.ts +8 -0
- package/dist/bitcoind/managed-bitcoind-service-process.js +48 -0
- package/dist/bitcoind/managed-bitcoind-service-replica.d.ts +8 -0
- package/dist/bitcoind/managed-bitcoind-service-replica.js +142 -0
- package/dist/bitcoind/managed-bitcoind-service-status.d.ts +42 -0
- package/dist/bitcoind/managed-bitcoind-service-status.js +178 -0
- package/dist/bitcoind/managed-bitcoind-service-types.d.ts +36 -0
- package/dist/bitcoind/managed-bitcoind-service-types.js +1 -0
- package/dist/bitcoind/service.d.ts +7 -63
- package/dist/bitcoind/service.js +7 -797
- package/dist/wallet/mining/engine-types.d.ts +1 -0
- package/dist/wallet/mining/engine-types.js +9 -1
- package/dist/wallet/mining/publish.js +3 -6
- package/dist/wallet/mining/runner.js +30 -18
- package/dist/wallet/mining/visualizer.js +7 -6
- package/dist/wallet/read/context.d.ts +4 -10
- package/dist/wallet/read/context.js +4 -227
- package/dist/wallet/read/local-state.d.ts +28 -0
- package/dist/wallet/read/local-state.js +233 -0
- package/dist/wallet/read/managed-bitcoind.d.ts +30 -0
- package/dist/wallet/read/managed-bitcoind.js +138 -0
- package/dist/wallet/read/managed-indexer.d.ts +23 -0
- package/dist/wallet/read/managed-indexer.js +87 -0
- package/dist/wallet/read/managed-services.d.ts +6 -21
- package/dist/wallet/read/managed-services.js +23 -196
- package/package.json +1 -1
|
@@ -88,6 +88,7 @@ export type ReadyMiningReadContext = WalletReadContext & {
|
|
|
88
88
|
snapshot: NonNullable<WalletReadContext["snapshot"]>;
|
|
89
89
|
model: NonNullable<WalletReadContext["model"]>;
|
|
90
90
|
};
|
|
91
|
+
export declare function resolveReadyMiningReadContext(readContext: WalletReadContext): ReadyMiningReadContext | null;
|
|
91
92
|
export interface MiningPublishSkipResult {
|
|
92
93
|
state: WalletStateV1;
|
|
93
94
|
txid: null;
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export function resolveReadyMiningReadContext(readContext) {
|
|
2
|
+
if (readContext.localState.availability !== "ready"
|
|
3
|
+
|| readContext.localState.state === null
|
|
4
|
+
|| readContext.snapshot === null
|
|
5
|
+
|| readContext.model === null) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
return readContext;
|
|
9
|
+
}
|
|
@@ -6,7 +6,7 @@ import { serializeMine } from "../cogop/index.js";
|
|
|
6
6
|
import { openWalletReadContext } from "../read/index.js";
|
|
7
7
|
import { assertFixedInputPrefixMatches, buildWalletMutationTransaction, fundAndValidateWalletMutationDraft, isAlreadyAcceptedError, isBroadcastUnknownError, isInsufficientFundsError, outpointKey as walletMutationOutpointKey, reconcilePersistentPolicyLocks, resolveWalletMutationFeeSelection, saveWalletStatePreservingUnlock, } from "../tx/common.js";
|
|
8
8
|
import { createMiningEventRecord } from "./events.js";
|
|
9
|
-
import {} from "./engine-types.js";
|
|
9
|
+
import { resolveReadyMiningReadContext, } from "./engine-types.js";
|
|
10
10
|
import { cloneMiningState, defaultMiningStatePatch, livePublishTargetsCandidateTip, miningCandidateIsCurrent, resolveSharedMiningConflictOutpoint, } from "./engine-state.js";
|
|
11
11
|
import { deriveMiningWordIndices, numberToSats, resolveBip39WordsFromIndices, } from "./engine-utils.js";
|
|
12
12
|
import { clearMiningPublishState, miningPublishMayStillExist, } from "./state.js";
|
|
@@ -576,13 +576,10 @@ export async function publishCandidate(options) {
|
|
|
576
576
|
});
|
|
577
577
|
try {
|
|
578
578
|
options.throwIfStopping?.();
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|| lockedReadContext.snapshot === null
|
|
582
|
-
|| lockedReadContext.model === null) {
|
|
579
|
+
const readyReadContext = resolveReadyMiningReadContext(lockedReadContext);
|
|
580
|
+
if (readyReadContext === null) {
|
|
583
581
|
return await createStaleCandidateSkipResult(options.fallbackState);
|
|
584
582
|
}
|
|
585
|
-
const readyReadContext = lockedReadContext;
|
|
586
583
|
const refreshedCandidate = refreshMiningCandidateFromCurrentState(readyReadContext, options.candidate);
|
|
587
584
|
if (refreshedCandidate === null) {
|
|
588
585
|
return await createStaleCandidateSkipResult(readyReadContext.localState.state);
|
|
@@ -27,6 +27,7 @@ import { createInsufficientFundsMiningPublishErrorMessage as createInsufficientF
|
|
|
27
27
|
import { runMiningPhaseMachine } from "./cycle.js";
|
|
28
28
|
import { attemptSaveMempool, handleDetectedMiningRuntimeResume, handleRecoverableMiningBitcoindFailure, isRecoverableMiningBitcoindError, refreshAndSaveMiningRuntimeStatus, resetMiningBitcoindRecoveryState, saveStopSnapshot, } from "./lifecycle.js";
|
|
29
29
|
import { compareLexicographically, deriveMiningWordIndices, getBlockRewardCogtoshi, numberToSats, resolveBip39WordsFromIndices, rootDomain, tieBreakHash, } from "./engine-utils.js";
|
|
30
|
+
import { resolveReadyMiningReadContext } from "./engine-types.js";
|
|
30
31
|
import { isMiningGenerationAbortRequested, markMiningGenerationActive, markMiningGenerationInactive, readMiningGenerationActivity, readMiningPreemptionRequest, requestMiningGenerationPreemption, } from "./coordination.js";
|
|
31
32
|
import { clearMiningPublishState, miningPublishIsInMempool, miningPublishMayStillExist, normalizeMiningPublishState, normalizeMiningStateRecord, } from "./state.js";
|
|
32
33
|
import { runForegroundMining as runForegroundMiningSupervisor, } from "./supervisor.js";
|
|
@@ -292,9 +293,20 @@ async function performMiningCycle(options) {
|
|
|
292
293
|
}
|
|
293
294
|
const displaySats = await resolveFundingDisplaySats(effectiveReadContext.localState.state, rpc).catch(() => null);
|
|
294
295
|
syncMiningVisualizerBalances(options.loopState, effectiveReadContext, displaySats);
|
|
295
|
-
|
|
296
|
+
const readyReadContext = resolveReadyMiningReadContext(effectiveReadContext);
|
|
297
|
+
if (readyReadContext === null) {
|
|
296
298
|
clearMiningProviderWait(options.loopState);
|
|
297
299
|
await saveCycleStatus(effectiveReadContext, {
|
|
300
|
+
runMode: options.runMode,
|
|
301
|
+
currentPhase: "waiting-indexer",
|
|
302
|
+
lastError: null,
|
|
303
|
+
note: "Mining is waiting for Bitcoin Core and the indexer to align.",
|
|
304
|
+
});
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (readyReadContext.localState.state.miningState.state === "repair-required") {
|
|
308
|
+
clearMiningProviderWait(options.loopState);
|
|
309
|
+
await saveCycleStatus(readyReadContext, {
|
|
298
310
|
runMode: options.runMode,
|
|
299
311
|
currentPhase: "waiting",
|
|
300
312
|
lastError: null,
|
|
@@ -302,9 +314,9 @@ async function performMiningCycle(options) {
|
|
|
302
314
|
});
|
|
303
315
|
return;
|
|
304
316
|
}
|
|
305
|
-
if (hasBlockingMutation(
|
|
317
|
+
if (hasBlockingMutation(readyReadContext.localState.state)) {
|
|
306
318
|
clearMiningProviderWait(options.loopState);
|
|
307
|
-
const nextState = defaultMiningStatePatch(
|
|
319
|
+
const nextState = defaultMiningStatePatch(readyReadContext.localState.state, {
|
|
308
320
|
state: "paused",
|
|
309
321
|
pauseReason: "wallet-busy",
|
|
310
322
|
});
|
|
@@ -313,15 +325,15 @@ async function performMiningCycle(options) {
|
|
|
313
325
|
provider: options.provider,
|
|
314
326
|
paths: options.paths,
|
|
315
327
|
});
|
|
316
|
-
|
|
317
|
-
...
|
|
328
|
+
const blockedReadContext = {
|
|
329
|
+
...readyReadContext,
|
|
318
330
|
localState: {
|
|
319
|
-
...
|
|
331
|
+
...readyReadContext.localState,
|
|
320
332
|
availability: "ready",
|
|
321
333
|
state: nextState,
|
|
322
334
|
},
|
|
323
335
|
};
|
|
324
|
-
await saveCycleStatus(
|
|
336
|
+
await saveCycleStatus(blockedReadContext, {
|
|
325
337
|
runMode: options.runMode,
|
|
326
338
|
currentPhase: "waiting",
|
|
327
339
|
lastError: null,
|
|
@@ -332,9 +344,9 @@ async function performMiningCycle(options) {
|
|
|
332
344
|
const preemptionRequest = await readMiningPreemptionRequest(options.paths);
|
|
333
345
|
if (preemptionRequest !== null) {
|
|
334
346
|
clearMiningProviderWait(options.loopState);
|
|
335
|
-
const nextState = defaultMiningStatePatch(
|
|
336
|
-
state:
|
|
337
|
-
&&
|
|
347
|
+
const nextState = defaultMiningStatePatch(readyReadContext.localState.state, {
|
|
348
|
+
state: readyReadContext.localState.state.miningState.livePublishInMempool
|
|
349
|
+
&& readyReadContext.localState.state.miningState.state === "paused-stale"
|
|
338
350
|
? "paused-stale"
|
|
339
351
|
: "paused",
|
|
340
352
|
pauseReason: preemptionRequest.reason,
|
|
@@ -345,9 +357,9 @@ async function performMiningCycle(options) {
|
|
|
345
357
|
paths: options.paths,
|
|
346
358
|
});
|
|
347
359
|
await saveCycleStatus({
|
|
348
|
-
...
|
|
360
|
+
...readyReadContext,
|
|
349
361
|
localState: {
|
|
350
|
-
...
|
|
362
|
+
...readyReadContext.localState,
|
|
351
363
|
state: nextState,
|
|
352
364
|
},
|
|
353
365
|
}, {
|
|
@@ -370,10 +382,10 @@ async function performMiningCycle(options) {
|
|
|
370
382
|
network: networkInfo,
|
|
371
383
|
mempool: mempoolInfo,
|
|
372
384
|
});
|
|
373
|
-
clearRecoveredBitcoindError = resetMiningBitcoindRecoveryState(options.loopState,
|
|
385
|
+
clearRecoveredBitcoindError = resetMiningBitcoindRecoveryState(options.loopState, readyReadContext.nodeStatus?.serviceStatus ?? { pid: service.pid });
|
|
374
386
|
if (targetBlockHeight !== null && getBlockRewardCogtoshi(targetBlockHeight) === 0n) {
|
|
375
387
|
clearMiningProviderWait(options.loopState);
|
|
376
|
-
const nextState = defaultMiningStatePatch(
|
|
388
|
+
const nextState = defaultMiningStatePatch(readyReadContext.localState.state, {
|
|
377
389
|
state: "paused",
|
|
378
390
|
pauseReason: "zero-reward",
|
|
379
391
|
});
|
|
@@ -383,9 +395,9 @@ async function performMiningCycle(options) {
|
|
|
383
395
|
paths: options.paths,
|
|
384
396
|
});
|
|
385
397
|
await saveCycleStatus({
|
|
386
|
-
...
|
|
398
|
+
...readyReadContext,
|
|
387
399
|
localState: {
|
|
388
|
-
...
|
|
400
|
+
...readyReadContext.localState,
|
|
389
401
|
state: nextState,
|
|
390
402
|
},
|
|
391
403
|
}, {
|
|
@@ -397,7 +409,7 @@ async function performMiningCycle(options) {
|
|
|
397
409
|
});
|
|
398
410
|
await appendEvent(options.paths, createEvent("publish-skipped-zero-reward", "Skipped mining because the target block reward is zero.", {
|
|
399
411
|
targetBlockHeight,
|
|
400
|
-
referencedBlockHashDisplay:
|
|
412
|
+
referencedBlockHashDisplay: readyReadContext.nodeStatus?.nodeBestHashHex ?? null,
|
|
401
413
|
runId: options.backgroundWorkerRunId,
|
|
402
414
|
}));
|
|
403
415
|
return;
|
|
@@ -409,7 +421,7 @@ async function performMiningCycle(options) {
|
|
|
409
421
|
paths: options.paths,
|
|
410
422
|
runMode: options.runMode,
|
|
411
423
|
backgroundWorkerRunId: options.backgroundWorkerRunId,
|
|
412
|
-
readContext:
|
|
424
|
+
readContext: readyReadContext,
|
|
413
425
|
rpc,
|
|
414
426
|
targetBlockHeight,
|
|
415
427
|
tipKey,
|
|
@@ -64,9 +64,6 @@ function formatRewardCogAmount(value) {
|
|
|
64
64
|
minFractionDigits: 1,
|
|
65
65
|
})} COG`;
|
|
66
66
|
}
|
|
67
|
-
function escapeRegExp(value) {
|
|
68
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
69
|
-
}
|
|
70
67
|
function consumeWrappedLine(text, capacity) {
|
|
71
68
|
const remaining = text.trimStart();
|
|
72
69
|
if (remaining.length <= capacity) {
|
|
@@ -91,12 +88,16 @@ function consumeWrappedLine(text, capacity) {
|
|
|
91
88
|
function highlightRequiredWords(sentence, requiredWords) {
|
|
92
89
|
const uniqueWords = [...new Set(requiredWords
|
|
93
90
|
.map((word) => word.trim().toLowerCase())
|
|
94
|
-
.filter((word) => word.length > 0))]
|
|
91
|
+
.filter((word) => word.length > 0))];
|
|
95
92
|
if (uniqueWords.length === 0) {
|
|
96
93
|
return sentence;
|
|
97
94
|
}
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
return sentence.replace(/[A-Za-z]+/g, (match) => {
|
|
96
|
+
const normalizedToken = match.toLowerCase();
|
|
97
|
+
return uniqueWords.some((word) => normalizedToken.includes(word))
|
|
98
|
+
? match.toUpperCase()
|
|
99
|
+
: match;
|
|
100
|
+
});
|
|
100
101
|
}
|
|
101
102
|
function formatSentenceSlot(prefix, sentence, requiredWords, lineCount) {
|
|
102
103
|
if (sentence === null) {
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
export { readSnapshotWithRetry, } from "../../bitcoind/indexer-daemon.js";
|
|
2
2
|
import { type WalletSecretProvider } from "../state/provider.js";
|
|
3
|
-
import
|
|
3
|
+
import { inspectWalletLocalState } from "./local-state.js";
|
|
4
|
+
import type { WalletReadContext } from "./types.js";
|
|
4
5
|
import type { WalletRuntimePaths } from "../runtime.js";
|
|
5
|
-
declare function inspectWalletLocalState(options?: {
|
|
6
|
-
dataDir?: string;
|
|
7
|
-
secretProvider?: WalletSecretProvider;
|
|
8
|
-
now?: number;
|
|
9
|
-
paths?: WalletRuntimePaths;
|
|
10
|
-
walletControlLockHeld?: boolean;
|
|
11
|
-
}): Promise<WalletLocalStateStatus>;
|
|
12
6
|
export declare function openWalletReadContext(options: {
|
|
13
7
|
dataDir: string;
|
|
14
8
|
databasePath: string;
|
|
@@ -19,4 +13,4 @@ export declare function openWalletReadContext(options: {
|
|
|
19
13
|
now?: number;
|
|
20
14
|
paths?: WalletRuntimePaths;
|
|
21
15
|
}): Promise<WalletReadContext>;
|
|
22
|
-
export { inspectWalletLocalState,
|
|
16
|
+
export { inspectWalletLocalState, };
|
|
@@ -1,236 +1,13 @@
|
|
|
1
|
-
import { access, constants } from "node:fs/promises";
|
|
2
1
|
import { readPackageVersionFromDisk } from "../../package-version.js";
|
|
3
|
-
|
|
4
|
-
import { createRpcClient } from "../../bitcoind/node.js";
|
|
2
|
+
export { readSnapshotWithRetry, } from "../../bitcoind/indexer-daemon.js";
|
|
5
3
|
import { UNINITIALIZED_WALLET_ROOT_ID } from "../../bitcoind/service-paths.js";
|
|
6
|
-
import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
|
|
7
|
-
import {} from "../../bitcoind/types.js";
|
|
8
|
-
import { normalizeWalletStateRecord, persistWalletCoinControlStateIfNeeded } from "../coin-control.js";
|
|
9
|
-
import { persistNormalizedWalletDescriptorStateIfNeeded } from "../descriptor-normalization.js";
|
|
10
4
|
import { inspectMiningControlPlane } from "../mining/index.js";
|
|
11
|
-
import { normalizeMiningStateRecord } from "../mining/state.js";
|
|
12
|
-
import { resolveWalletRootIdFromLocalArtifacts } from "../root-resolution.js";
|
|
13
5
|
import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
14
|
-
import {
|
|
15
|
-
import { createDefaultWalletSecretProvider, createWalletSecretReference, inspectClientPasswordSetupReadiness, } from "../state/provider.js";
|
|
16
|
-
import { describeClientPasswordLockedMessage, describeClientPasswordMigrationMessage, describeClientPasswordSetupMessage, } from "../state/client-password.js";
|
|
6
|
+
import { createDefaultWalletSecretProvider, } from "../state/provider.js";
|
|
17
7
|
import { openManagedWalletReadServiceBundle } from "./managed-services.js";
|
|
8
|
+
import { inspectWalletLocalState, readFundingSpendableSats } from "./local-state.js";
|
|
18
9
|
import { createWalletReadModel } from "./project.js";
|
|
19
10
|
const DEFAULT_SERVICE_START_TIMEOUT_MS = 60_000;
|
|
20
|
-
function btcAmountToSats(value) {
|
|
21
|
-
return BigInt(Math.round(value * 100_000_000));
|
|
22
|
-
}
|
|
23
|
-
function isSpendableFundingUtxo(entry, fundingScriptPubKeyHex) {
|
|
24
|
-
return entry.scriptPubKey === fundingScriptPubKeyHex
|
|
25
|
-
&& entry.confirmations >= 1
|
|
26
|
-
&& entry.spendable !== false
|
|
27
|
-
&& entry.safe !== false;
|
|
28
|
-
}
|
|
29
|
-
async function pathExists(path) {
|
|
30
|
-
try {
|
|
31
|
-
await access(path, constants.F_OK);
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function isWalletAccessError(error) {
|
|
39
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
40
|
-
return message.startsWith("wallet_secret_missing_")
|
|
41
|
-
|| message.startsWith("wallet_secret_provider_")
|
|
42
|
-
|| message.startsWith("wallet_client_password_")
|
|
43
|
-
|| message === "wallet_state_legacy_envelope_unsupported";
|
|
44
|
-
}
|
|
45
|
-
function describeWalletAccessMessage(options) {
|
|
46
|
-
const message = options.accessError instanceof Error ? options.accessError.message : String(options.accessError ?? "");
|
|
47
|
-
if (message === "wallet_state_legacy_envelope_unsupported") {
|
|
48
|
-
return "Wallet state exists but was created by an older Cogcoin wallet format that this version no longer loads directly.";
|
|
49
|
-
}
|
|
50
|
-
if (message === "wallet_client_password_setup_required") {
|
|
51
|
-
return describeClientPasswordSetupMessage();
|
|
52
|
-
}
|
|
53
|
-
if (message === "wallet_client_password_migration_required") {
|
|
54
|
-
return describeClientPasswordMigrationMessage();
|
|
55
|
-
}
|
|
56
|
-
if (message === "wallet_client_password_locked") {
|
|
57
|
-
return describeClientPasswordLockedMessage();
|
|
58
|
-
}
|
|
59
|
-
if (message.startsWith("wallet_secret_provider_")) {
|
|
60
|
-
return "Wallet state exists but the local secret provider is unavailable.";
|
|
61
|
-
}
|
|
62
|
-
if (message.startsWith("wallet_secret_missing_")) {
|
|
63
|
-
return "Wallet state exists but its local secret-provider material is unavailable.";
|
|
64
|
-
}
|
|
65
|
-
return message.length > 0
|
|
66
|
-
? message
|
|
67
|
-
: "Wallet state exists but could not be loaded from the local secret provider.";
|
|
68
|
-
}
|
|
69
|
-
async function normalizeLoadedWalletStateForRead(options) {
|
|
70
|
-
if (options.dataDir === undefined) {
|
|
71
|
-
return options.loaded;
|
|
72
|
-
}
|
|
73
|
-
const node = await attachOrStartManagedBitcoindService({
|
|
74
|
-
dataDir: options.dataDir,
|
|
75
|
-
chain: "main",
|
|
76
|
-
startHeight: 0,
|
|
77
|
-
walletRootId: options.loaded.state.walletRootId,
|
|
78
|
-
});
|
|
79
|
-
try {
|
|
80
|
-
const access = {
|
|
81
|
-
provider: options.access.provider,
|
|
82
|
-
secretReference: createWalletSecretReference(options.loaded.state.walletRootId),
|
|
83
|
-
};
|
|
84
|
-
const normalized = await persistNormalizedWalletDescriptorStateIfNeeded({
|
|
85
|
-
state: options.loaded.state,
|
|
86
|
-
access,
|
|
87
|
-
paths: options.paths,
|
|
88
|
-
nowUnixMs: options.now,
|
|
89
|
-
replacePrimary: options.loaded.source === "backup",
|
|
90
|
-
rpc: createRpcClient(node.rpc),
|
|
91
|
-
});
|
|
92
|
-
const coinControl = await persistWalletCoinControlStateIfNeeded({
|
|
93
|
-
state: normalized.state,
|
|
94
|
-
access,
|
|
95
|
-
paths: options.paths,
|
|
96
|
-
nowUnixMs: options.now,
|
|
97
|
-
replacePrimary: (normalized.changed ? "primary" : options.loaded.source) === "backup",
|
|
98
|
-
rpc: createRpcClient(node.rpc),
|
|
99
|
-
});
|
|
100
|
-
return {
|
|
101
|
-
source: coinControl.changed ? "primary" : normalized.changed ? "primary" : options.loaded.source,
|
|
102
|
-
state: coinControl.state,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
finally {
|
|
106
|
-
await node.stop?.().catch(() => undefined);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
async function inspectWalletLocalState(options = {}) {
|
|
110
|
-
const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
|
|
111
|
-
const now = options.now ?? Date.now();
|
|
112
|
-
const provider = options.secretProvider ?? createDefaultWalletSecretProvider();
|
|
113
|
-
const [hasPrimaryStateFile, hasBackupStateFile] = await Promise.all([
|
|
114
|
-
pathExists(paths.walletStatePath),
|
|
115
|
-
pathExists(paths.walletStateBackupPath),
|
|
116
|
-
]);
|
|
117
|
-
const clientPasswordReadiness = await inspectClientPasswordSetupReadiness(provider).catch(() => "ready");
|
|
118
|
-
if (!hasPrimaryStateFile && !hasBackupStateFile) {
|
|
119
|
-
return {
|
|
120
|
-
availability: "uninitialized",
|
|
121
|
-
clientPasswordReadiness,
|
|
122
|
-
unlockRequired: false,
|
|
123
|
-
walletRootId: null,
|
|
124
|
-
state: null,
|
|
125
|
-
source: null,
|
|
126
|
-
hasPrimaryStateFile,
|
|
127
|
-
hasBackupStateFile,
|
|
128
|
-
message: "Wallet state has not been initialized yet.",
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
if (clientPasswordReadiness !== "ready") {
|
|
132
|
-
const rawEnvelope = await loadRawWalletStateEnvelope({
|
|
133
|
-
primaryPath: paths.walletStatePath,
|
|
134
|
-
backupPath: paths.walletStateBackupPath,
|
|
135
|
-
}).catch(() => null);
|
|
136
|
-
if (rawEnvelope?.envelope.secretProvider == null) {
|
|
137
|
-
return {
|
|
138
|
-
availability: "local-state-corrupt",
|
|
139
|
-
clientPasswordReadiness: "ready",
|
|
140
|
-
unlockRequired: false,
|
|
141
|
-
walletRootId: extractWalletRootIdHintFromWalletStateEnvelope(rawEnvelope?.envelope ?? null),
|
|
142
|
-
state: null,
|
|
143
|
-
source: null,
|
|
144
|
-
hasPrimaryStateFile,
|
|
145
|
-
hasBackupStateFile,
|
|
146
|
-
message: "Wallet state exists but was created by an older Cogcoin wallet format that this version no longer loads directly.",
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
const resolvedRoot = await resolveWalletRootIdFromLocalArtifacts({
|
|
150
|
-
paths,
|
|
151
|
-
provider,
|
|
152
|
-
}).catch(() => null);
|
|
153
|
-
return {
|
|
154
|
-
availability: "local-state-corrupt",
|
|
155
|
-
clientPasswordReadiness,
|
|
156
|
-
unlockRequired: false,
|
|
157
|
-
walletRootId: resolvedRoot?.walletRootId ?? null,
|
|
158
|
-
state: null,
|
|
159
|
-
source: null,
|
|
160
|
-
hasPrimaryStateFile,
|
|
161
|
-
hasBackupStateFile,
|
|
162
|
-
message: clientPasswordReadiness === "migration-required"
|
|
163
|
-
? describeClientPasswordMigrationMessage()
|
|
164
|
-
: describeClientPasswordSetupMessage(),
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
try {
|
|
168
|
-
const loaded = await loadWalletState({
|
|
169
|
-
primaryPath: paths.walletStatePath,
|
|
170
|
-
backupPath: paths.walletStateBackupPath,
|
|
171
|
-
}, {
|
|
172
|
-
provider,
|
|
173
|
-
});
|
|
174
|
-
const normalized = await normalizeLoadedWalletStateForRead({
|
|
175
|
-
loaded,
|
|
176
|
-
access: { provider },
|
|
177
|
-
dataDir: options.dataDir,
|
|
178
|
-
now,
|
|
179
|
-
paths,
|
|
180
|
-
});
|
|
181
|
-
return {
|
|
182
|
-
availability: "ready",
|
|
183
|
-
clientPasswordReadiness,
|
|
184
|
-
unlockRequired: false,
|
|
185
|
-
walletRootId: normalized.state.walletRootId,
|
|
186
|
-
state: normalizeWalletStateRecord({
|
|
187
|
-
...normalized.state,
|
|
188
|
-
miningState: normalizeMiningStateRecord(normalized.state.miningState),
|
|
189
|
-
}),
|
|
190
|
-
source: normalized.source,
|
|
191
|
-
hasPrimaryStateFile,
|
|
192
|
-
hasBackupStateFile,
|
|
193
|
-
message: null,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
catch (error) {
|
|
197
|
-
const resolvedRoot = await resolveWalletRootIdFromLocalArtifacts({
|
|
198
|
-
paths,
|
|
199
|
-
provider,
|
|
200
|
-
}).catch(() => null);
|
|
201
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
202
|
-
return {
|
|
203
|
-
availability: "local-state-corrupt",
|
|
204
|
-
clientPasswordReadiness,
|
|
205
|
-
unlockRequired: message === "wallet_client_password_locked",
|
|
206
|
-
walletRootId: resolvedRoot?.walletRootId ?? null,
|
|
207
|
-
state: null,
|
|
208
|
-
source: null,
|
|
209
|
-
hasPrimaryStateFile,
|
|
210
|
-
hasBackupStateFile,
|
|
211
|
-
message: isWalletAccessError(error)
|
|
212
|
-
? describeWalletAccessMessage({ accessError: error })
|
|
213
|
-
: error instanceof Error
|
|
214
|
-
? error.message
|
|
215
|
-
: String(error),
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
async function readFundingSpendableSats(options) {
|
|
220
|
-
if (options.state === null || options.rpc === null) {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
const state = options.state;
|
|
224
|
-
try {
|
|
225
|
-
const utxos = await options.rpc.listUnspent(state.managedCoreWallet.walletName, 1);
|
|
226
|
-
return utxos.reduce((sum, entry) => isSpendableFundingUtxo(entry, state.funding.scriptPubKeyHex)
|
|
227
|
-
? sum + btcAmountToSats(entry.amount)
|
|
228
|
-
: sum, 0n);
|
|
229
|
-
}
|
|
230
|
-
catch {
|
|
231
|
-
return null;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
11
|
export async function openWalletReadContext(options) {
|
|
235
12
|
const expectedIndexerBinaryVersion = options.expectedIndexerBinaryVersion === undefined
|
|
236
13
|
? await readPackageVersionFromDisk()
|
|
@@ -288,4 +65,4 @@ export async function openWalletReadContext(options) {
|
|
|
288
65
|
},
|
|
289
66
|
};
|
|
290
67
|
}
|
|
291
|
-
export { inspectWalletLocalState,
|
|
68
|
+
export { inspectWalletLocalState, };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
|
|
2
|
+
import { createRpcClient } from "../../bitcoind/node.js";
|
|
3
|
+
import { type WalletRuntimePaths } from "../runtime.js";
|
|
4
|
+
import { type WalletSecretProvider } from "../state/provider.js";
|
|
5
|
+
import type { WalletLocalStateStatus } from "./types.js";
|
|
6
|
+
type WalletLocalStateDeps = {
|
|
7
|
+
attachOrStartManagedBitcoindService: typeof attachOrStartManagedBitcoindService;
|
|
8
|
+
createRpcClient: typeof createRpcClient;
|
|
9
|
+
};
|
|
10
|
+
export declare function inspectWalletLocalStateWithDependencies(options?: {
|
|
11
|
+
dataDir?: string;
|
|
12
|
+
secretProvider?: WalletSecretProvider;
|
|
13
|
+
now?: number;
|
|
14
|
+
paths?: WalletRuntimePaths;
|
|
15
|
+
walletControlLockHeld?: boolean;
|
|
16
|
+
}, dependencies?: WalletLocalStateDeps): Promise<WalletLocalStateStatus>;
|
|
17
|
+
export declare function inspectWalletLocalState(options?: {
|
|
18
|
+
dataDir?: string;
|
|
19
|
+
secretProvider?: WalletSecretProvider;
|
|
20
|
+
now?: number;
|
|
21
|
+
paths?: WalletRuntimePaths;
|
|
22
|
+
walletControlLockHeld?: boolean;
|
|
23
|
+
}): Promise<WalletLocalStateStatus>;
|
|
24
|
+
export declare function readFundingSpendableSats(options: {
|
|
25
|
+
state: WalletLocalStateStatus["state"];
|
|
26
|
+
rpc: ReturnType<typeof createRpcClient> | null;
|
|
27
|
+
}): Promise<bigint | null>;
|
|
28
|
+
export {};
|