@cogcoin/client 1.1.10 → 1.1.12
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/client/managed-client.d.ts +2 -0
- package/dist/bitcoind/client/managed-client.js +6 -0
- package/dist/bitcoind/indexer-daemon/background-follow.d.ts +23 -0
- package/dist/bitcoind/indexer-daemon/background-follow.js +132 -0
- package/dist/bitcoind/indexer-daemon/client.d.ts +12 -0
- package/dist/bitcoind/indexer-daemon/client.js +137 -0
- package/dist/bitcoind/indexer-daemon/lifecycle.d.ts +30 -0
- package/dist/bitcoind/indexer-daemon/lifecycle.js +153 -0
- package/dist/bitcoind/indexer-daemon/process.d.ts +35 -0
- package/dist/bitcoind/indexer-daemon/process.js +140 -0
- package/dist/bitcoind/indexer-daemon/runtime.d.ts +23 -0
- package/dist/bitcoind/indexer-daemon/runtime.js +204 -0
- package/dist/bitcoind/indexer-daemon/server.d.ts +12 -0
- package/dist/bitcoind/indexer-daemon/server.js +87 -0
- package/dist/bitcoind/indexer-daemon/snapshot-leases.d.ts +23 -0
- package/dist/bitcoind/indexer-daemon/snapshot-leases.js +139 -0
- package/dist/bitcoind/indexer-daemon/status.d.ts +23 -0
- package/dist/bitcoind/indexer-daemon/status.js +282 -0
- package/dist/bitcoind/indexer-daemon/types.d.ts +141 -0
- package/dist/bitcoind/indexer-daemon/types.js +1 -0
- package/dist/bitcoind/indexer-daemon-main.js +14 -665
- package/dist/bitcoind/indexer-daemon.d.ts +4 -132
- package/dist/bitcoind/indexer-daemon.js +2 -417
- package/dist/bitcoind/managed-bitcoind-service-config.d.ts +18 -1
- package/dist/bitcoind/managed-bitcoind-service-config.js +38 -1
- package/dist/bitcoind/managed-bitcoind-service-lifecycle.js +30 -24
- package/dist/bitcoind/managed-bitcoind-service-status.js +0 -8
- package/dist/bitcoind/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +3 -0
- package/dist/bitcoind/types.d.ts +1 -0
- package/dist/cli/mining-format.js +6 -1
- package/dist/cli/wallet-format/balance.js +1 -1
- package/dist/client/default-client.d.ts +3 -1
- package/dist/client/default-client.js +22 -0
- package/dist/types.d.ts +13 -1
- package/dist/wallet/fs/atomic.d.ts +11 -2
- package/dist/wallet/fs/atomic.js +45 -5
- package/dist/wallet/mining/competitiveness.d.ts +6 -0
- package/dist/wallet/mining/competitiveness.js +137 -74
- package/dist/wallet/mining/cycle.js +32 -4
- package/dist/wallet/mining/engine-types.d.ts +10 -0
- package/dist/wallet/mining/projection.d.ts +1 -0
- package/dist/wallet/mining/projection.js +15 -1
- package/dist/wallet/mining/visualizer-sync.js +7 -9
- package/dist/wallet/mining/visualizer.js +2 -1
- package/dist/wallet/read/context.js +3 -2
- package/dist/wallet/read/local-state.d.ts +8 -0
- package/dist/wallet/read/local-state.js +32 -6
- package/dist/wallet/read/types.d.ts +1 -0
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ import { MiningProviderRequestError } from "./sentences.js";
|
|
|
10
10
|
import { isInsufficientFundsError } from "../tx/common.js";
|
|
11
11
|
import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
|
|
12
12
|
import { createRpcClient } from "../../bitcoind/node.js";
|
|
13
|
-
import { buildPrePublishStatusOverrides, } from "./projection.js";
|
|
13
|
+
import { buildPrePublishStatusOverrides, resolveWaitingProviderNote, } from "./projection.js";
|
|
14
14
|
function createInitialState(options) {
|
|
15
15
|
return {
|
|
16
16
|
phase: "idle",
|
|
@@ -149,7 +149,7 @@ export async function runMiningPhaseMachine(options) {
|
|
|
149
149
|
currentPublishDecision: null,
|
|
150
150
|
providerState: options.loopState.providerWaitState,
|
|
151
151
|
lastError: options.loopState.providerWaitLastError,
|
|
152
|
-
note:
|
|
152
|
+
note: resolveWaitingProviderNote(options.loopState.providerWaitState),
|
|
153
153
|
});
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
@@ -162,7 +162,7 @@ export async function runMiningPhaseMachine(options) {
|
|
|
162
162
|
currentPublishDecision: null,
|
|
163
163
|
providerState: options.loopState.providerWaitState,
|
|
164
164
|
lastError: options.loopState.providerWaitLastError,
|
|
165
|
-
note:
|
|
165
|
+
note: resolveWaitingProviderNote(options.loopState.providerWaitState),
|
|
166
166
|
});
|
|
167
167
|
return;
|
|
168
168
|
}
|
|
@@ -231,7 +231,7 @@ export async function runMiningPhaseMachine(options) {
|
|
|
231
231
|
currentPublishDecision: null,
|
|
232
232
|
providerState: options.loopState.providerWaitState ?? error.providerState,
|
|
233
233
|
lastError: error.message,
|
|
234
|
-
note:
|
|
234
|
+
note: resolveWaitingProviderNote(options.loopState.providerWaitState ?? error.providerState),
|
|
235
235
|
});
|
|
236
236
|
await options.appendEvent(createMiningEventRecord("publish-paused-provider", error.message, {
|
|
237
237
|
level: "warn",
|
|
@@ -339,6 +339,9 @@ export async function runMiningPhaseMachine(options) {
|
|
|
339
339
|
score: best.canonicalBlend.toString(),
|
|
340
340
|
runId: options.backgroundWorkerRunId,
|
|
341
341
|
}));
|
|
342
|
+
let lastScoringProgressProcessed = -1;
|
|
343
|
+
let lastScoringProgressSavedAtUnixMs = 0;
|
|
344
|
+
let scoringProgressWrite = Promise.resolve();
|
|
342
345
|
const gate = await runGateImpl({
|
|
343
346
|
rpc: options.rpc,
|
|
344
347
|
readContext: options.readContext,
|
|
@@ -348,7 +351,32 @@ export async function runMiningPhaseMachine(options) {
|
|
|
348
351
|
cooperativeYield: options.cooperativeYieldImpl,
|
|
349
352
|
cooperativeYieldEvery: options.cooperativeYieldEvery,
|
|
350
353
|
throwIfStopping: options.throwIfStopping,
|
|
354
|
+
onWarmupProgress: async (progress) => {
|
|
355
|
+
if (progress.total <= 0) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const nowUnixMs = now();
|
|
359
|
+
if (progress.processed === lastScoringProgressProcessed
|
|
360
|
+
|| (progress.processed !== 0
|
|
361
|
+
&& progress.processed !== progress.total
|
|
362
|
+
&& (nowUnixMs - lastScoringProgressSavedAtUnixMs) < 500)) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
lastScoringProgressProcessed = progress.processed;
|
|
366
|
+
lastScoringProgressSavedAtUnixMs = nowUnixMs;
|
|
367
|
+
scoringProgressWrite = scoringProgressWrite.then(async () => {
|
|
368
|
+
await options.saveCycleStatus(options.readContext, {
|
|
369
|
+
runMode: options.runMode,
|
|
370
|
+
currentPhase: "scoring",
|
|
371
|
+
currentPublishDecision: null,
|
|
372
|
+
lastError: null,
|
|
373
|
+
note: `Scoring mining candidates for the current tip (mempool ${progress.processed}/${progress.total}).`,
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
await scoringProgressWrite;
|
|
377
|
+
},
|
|
351
378
|
});
|
|
379
|
+
await scoringProgressWrite;
|
|
352
380
|
throwIfInterrupted();
|
|
353
381
|
state.gateSnapshot = {
|
|
354
382
|
higherRankedCompetitorDomainCount: gate.higherRankedCompetitorDomainCount,
|
|
@@ -28,6 +28,16 @@ export type MiningRpcClient = WalletMutationRpcClient & {
|
|
|
28
28
|
txids: string[];
|
|
29
29
|
mempool_sequence: string | number;
|
|
30
30
|
}>;
|
|
31
|
+
getRawMempoolEntries(): Promise<Record<string, {
|
|
32
|
+
vsize: number;
|
|
33
|
+
fees: {
|
|
34
|
+
base: number;
|
|
35
|
+
ancestor: number;
|
|
36
|
+
descendant: number;
|
|
37
|
+
};
|
|
38
|
+
ancestorsize?: number;
|
|
39
|
+
descendantsize?: number;
|
|
40
|
+
}>>;
|
|
31
41
|
getMempoolEntry(txid: string): Promise<{
|
|
32
42
|
vsize: number;
|
|
33
43
|
fees: {
|
|
@@ -37,6 +37,7 @@ export interface MiningRuntimeStatusOverrides {
|
|
|
37
37
|
note?: string | null;
|
|
38
38
|
livePublishInMempool?: boolean | null;
|
|
39
39
|
}
|
|
40
|
+
export declare function resolveWaitingProviderNote(providerState: MiningRuntimeStatusV1["providerState"] | null): string;
|
|
40
41
|
export declare function buildPrePublishStatusOverrides(options: {
|
|
41
42
|
state: WalletStateV1;
|
|
42
43
|
candidate: MiningCandidate;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { livePublishTargetsCandidateTip } from "./engine-state.js";
|
|
2
2
|
import { normalizeMiningPublishState, normalizeMiningStateRecord } from "./state.js";
|
|
3
3
|
import { MINING_WORKER_API_VERSION, MINING_WORKER_HEARTBEAT_STALE_MS, } from "./constants.js";
|
|
4
|
+
export function resolveWaitingProviderNote(providerState) {
|
|
5
|
+
switch (providerState) {
|
|
6
|
+
case "backoff":
|
|
7
|
+
return "Mining is waiting because the sentence provider had a transient failure and will be retried automatically.";
|
|
8
|
+
case "rate-limited":
|
|
9
|
+
return "Mining is waiting because the sentence provider is rate limited and will be retried automatically.";
|
|
10
|
+
case "auth-error":
|
|
11
|
+
return "Mining is waiting because the sentence provider rejected the configured API key.";
|
|
12
|
+
case "not-found":
|
|
13
|
+
return "Mining is waiting because the configured sentence-provider model was not found.";
|
|
14
|
+
default:
|
|
15
|
+
return "Mining is waiting for the sentence provider to recover.";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
4
18
|
export function buildPrePublishStatusOverrides(options) {
|
|
5
19
|
const replacing = options.state.miningState.currentTxid !== null;
|
|
6
20
|
const replacingAcrossTips = replacing && !livePublishTargetsCandidateTip({
|
|
@@ -249,7 +263,7 @@ export async function buildMiningRuntimeStatusSnapshot(options) {
|
|
|
249
263
|
: existing?.currentPhase === "resuming"
|
|
250
264
|
? "Mining discarded stale in-flight work after a large local runtime gap and is rechecking health."
|
|
251
265
|
: reuseExistingProviderWait
|
|
252
|
-
?
|
|
266
|
+
? resolveWaitingProviderNote(existing?.providerState ?? providerState)
|
|
253
267
|
: existing?.currentPhase === "waiting-indexer"
|
|
254
268
|
? "Mining is waiting for Bitcoin Core and the indexer to align."
|
|
255
269
|
: existing?.currentPhase === "waiting-bitcoin-network"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { getBalance, getBlockWinners, lookupDomainById, } from "@cogcoin/indexer/queries";
|
|
2
2
|
import { displayToInternalBlockhash } from "@cogcoin/scoring";
|
|
3
3
|
import { FOLLOW_VISIBLE_PRIOR_BLOCKS } from "../../bitcoind/client/follow-block-times.js";
|
|
4
|
+
import { readFundingBalanceSummary } from "../read/local-state.js";
|
|
4
5
|
import { buildMiningTipKey, resetMiningUiForTip } from "./engine-state.js";
|
|
5
|
-
import { deriveMiningWordIndices,
|
|
6
|
+
import { deriveMiningWordIndices, resolveBip39WordsFromIndices, } from "./engine-utils.js";
|
|
6
7
|
import { createEmptyMiningFollowVisualizerState } from "./visualizer.js";
|
|
7
8
|
function cloneSettledBoardEntries(entries) {
|
|
8
9
|
return entries.map((entry) => ({
|
|
@@ -156,14 +157,11 @@ export function syncMiningUiForCurrentTip(options) {
|
|
|
156
157
|
};
|
|
157
158
|
}
|
|
158
159
|
export async function resolveFundingDisplaySats(state, rpc) {
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
return sum + numberToSats(entry.amount);
|
|
166
|
-
}, 0n);
|
|
160
|
+
const summary = await readFundingBalanceSummary({
|
|
161
|
+
state,
|
|
162
|
+
rpc,
|
|
163
|
+
});
|
|
164
|
+
return summary.fundingDisplaySats ?? 0n;
|
|
167
165
|
}
|
|
168
166
|
export async function loadMiningVisibleFollowBlockTimes(options) {
|
|
169
167
|
if (options.indexedTipHeight === null || options.indexedTipHashHex === null) {
|
|
@@ -3,6 +3,7 @@ import { centerLine, normalizeInlineText, truncateLine } from "../../bitcoind/pr
|
|
|
3
3
|
import { advanceFollowSceneState, createFollowSceneState, replaceFollowBlockTimes, syncFollowSceneState, } from "../../bitcoind/progress/follow-scene.js";
|
|
4
4
|
import { DEFAULT_RENDER_CLOCK, resolveTtyRenderPolicy, TtyRenderThrottle, } from "../../bitcoind/progress/render-policy.js";
|
|
5
5
|
import { TtyProgressRenderer } from "../../bitcoind/progress/tty-renderer.js";
|
|
6
|
+
import { resolveWaitingProviderNote } from "./projection.js";
|
|
6
7
|
const MINING_ARTWORK_COG_WIDTH = 22;
|
|
7
8
|
const MINING_SENTENCE_BOARD_SIZE = 5;
|
|
8
9
|
const MINING_SENTENCE_BOARD_WRAP_WIDTH = 80;
|
|
@@ -282,7 +283,7 @@ export function describeMiningVisualizerProgress(snapshot) {
|
|
|
282
283
|
case "resuming":
|
|
283
284
|
return "Mining discarded stale in-flight work after a large local runtime gap and is rechecking health.";
|
|
284
285
|
case "waiting-provider":
|
|
285
|
-
return
|
|
286
|
+
return resolveWaitingProviderNote(snapshot.providerState);
|
|
286
287
|
case "waiting-indexer":
|
|
287
288
|
return "Mining is waiting for Bitcoin Core and the indexer to align.";
|
|
288
289
|
case "waiting-bitcoin-network":
|
|
@@ -5,7 +5,7 @@ import { inspectMiningControlPlane } from "../mining/index.js";
|
|
|
5
5
|
import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
6
6
|
import { createDefaultWalletSecretProvider, } from "../state/provider.js";
|
|
7
7
|
import { openManagedWalletReadServiceBundle } from "./managed-services.js";
|
|
8
|
-
import { inspectWalletLocalState,
|
|
8
|
+
import { inspectWalletLocalState, readFundingBalanceSummary } from "./local-state.js";
|
|
9
9
|
import { createWalletReadModel } from "./project.js";
|
|
10
10
|
const DEFAULT_SERVICE_START_TIMEOUT_MS = 60_000;
|
|
11
11
|
export async function openWalletReadContext(options) {
|
|
@@ -31,7 +31,7 @@ export async function openWalletReadContext(options) {
|
|
|
31
31
|
expectedIndexerBinaryVersion,
|
|
32
32
|
now,
|
|
33
33
|
});
|
|
34
|
-
const fundingSpendableSats = await
|
|
34
|
+
const { fundingDisplaySats, fundingSpendableSats, } = await readFundingBalanceSummary({
|
|
35
35
|
state: localState.state,
|
|
36
36
|
rpc: managedServices.node.rpc,
|
|
37
37
|
});
|
|
@@ -58,6 +58,7 @@ export async function openWalletReadContext(options) {
|
|
|
58
58
|
model: localState.state === null
|
|
59
59
|
? null
|
|
60
60
|
: createWalletReadModel(localState.state, managedServices.snapshot),
|
|
61
|
+
fundingDisplaySats,
|
|
61
62
|
fundingSpendableSats,
|
|
62
63
|
mining,
|
|
63
64
|
async close() {
|
|
@@ -7,6 +7,10 @@ type WalletLocalStateDeps = {
|
|
|
7
7
|
attachOrStartManagedBitcoindService: typeof attachOrStartManagedBitcoindService;
|
|
8
8
|
createRpcClient: typeof createRpcClient;
|
|
9
9
|
};
|
|
10
|
+
export interface FundingBalanceSummary {
|
|
11
|
+
fundingDisplaySats: bigint | null;
|
|
12
|
+
fundingSpendableSats: bigint | null;
|
|
13
|
+
}
|
|
10
14
|
export declare function inspectWalletLocalStateWithDependencies(options?: {
|
|
11
15
|
dataDir?: string;
|
|
12
16
|
secretProvider?: WalletSecretProvider;
|
|
@@ -25,4 +29,8 @@ export declare function readFundingSpendableSats(options: {
|
|
|
25
29
|
state: WalletLocalStateStatus["state"];
|
|
26
30
|
rpc: ReturnType<typeof createRpcClient> | null;
|
|
27
31
|
}): Promise<bigint | null>;
|
|
32
|
+
export declare function readFundingBalanceSummary(options: {
|
|
33
|
+
state: WalletLocalStateStatus["state"];
|
|
34
|
+
rpc: Pick<ReturnType<typeof createRpcClient>, "listUnspent"> | null;
|
|
35
|
+
}): Promise<FundingBalanceSummary>;
|
|
28
36
|
export {};
|
|
@@ -22,6 +22,10 @@ function isSpendableFundingUtxo(entry, fundingScriptPubKeyHex) {
|
|
|
22
22
|
&& entry.spendable !== false
|
|
23
23
|
&& entry.safe !== false;
|
|
24
24
|
}
|
|
25
|
+
function isDisplayFundingUtxo(entry, fundingScriptPubKeyHex) {
|
|
26
|
+
return entry.scriptPubKey === fundingScriptPubKeyHex
|
|
27
|
+
&& entry.spendable !== false;
|
|
28
|
+
}
|
|
25
29
|
async function pathExists(path) {
|
|
26
30
|
try {
|
|
27
31
|
await access(path, constants.F_OK);
|
|
@@ -217,17 +221,39 @@ export async function inspectWalletLocalState(options = {}) {
|
|
|
217
221
|
return inspectWalletLocalStateWithDependencies(options);
|
|
218
222
|
}
|
|
219
223
|
export async function readFundingSpendableSats(options) {
|
|
224
|
+
return (await readFundingBalanceSummary(options)).fundingSpendableSats;
|
|
225
|
+
}
|
|
226
|
+
export async function readFundingBalanceSummary(options) {
|
|
220
227
|
if (options.state === null || options.rpc === null) {
|
|
221
|
-
return
|
|
228
|
+
return {
|
|
229
|
+
fundingDisplaySats: null,
|
|
230
|
+
fundingSpendableSats: null,
|
|
231
|
+
};
|
|
222
232
|
}
|
|
223
233
|
const state = options.state;
|
|
224
234
|
try {
|
|
225
|
-
const utxos = await options.rpc.listUnspent(state.managedCoreWallet.walletName,
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
235
|
+
const utxos = await options.rpc.listUnspent(state.managedCoreWallet.walletName, 0);
|
|
236
|
+
let fundingDisplaySats = 0n;
|
|
237
|
+
let fundingSpendableSats = 0n;
|
|
238
|
+
for (const entry of utxos) {
|
|
239
|
+
if (!isDisplayFundingUtxo(entry, state.funding.scriptPubKeyHex)) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const amountSats = btcAmountToSats(entry.amount);
|
|
243
|
+
fundingDisplaySats += amountSats;
|
|
244
|
+
if (isSpendableFundingUtxo(entry, state.funding.scriptPubKeyHex)) {
|
|
245
|
+
fundingSpendableSats += amountSats;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
fundingDisplaySats,
|
|
250
|
+
fundingSpendableSats,
|
|
251
|
+
};
|
|
229
252
|
}
|
|
230
253
|
catch {
|
|
231
|
-
return
|
|
254
|
+
return {
|
|
255
|
+
fundingDisplaySats: null,
|
|
256
|
+
fundingSpendableSats: null,
|
|
257
|
+
};
|
|
232
258
|
}
|
|
233
259
|
}
|
|
@@ -94,6 +94,7 @@ export interface WalletReadContext {
|
|
|
94
94
|
indexer: WalletIndexerStatus;
|
|
95
95
|
snapshot: WalletSnapshotView | null;
|
|
96
96
|
model: WalletReadModel | null;
|
|
97
|
+
fundingDisplaySats: bigint | null;
|
|
97
98
|
fundingSpendableSats: bigint | null;
|
|
98
99
|
mining?: MiningControlPlaneView;
|
|
99
100
|
close(): Promise<void>;
|
package/package.json
CHANGED