@cogcoin/client 1.1.11 → 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/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +3 -0
- package/dist/bitcoind/types.d.ts +1 -0
- package/dist/wallet/mining/competitiveness.d.ts +6 -0
- package/dist/wallet/mining/competitiveness.js +137 -74
- package/dist/wallet/mining/cycle.js +28 -0
- package/dist/wallet/mining/engine-types.d.ts +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@cogcoin/client`
|
|
2
2
|
|
|
3
|
-
`@cogcoin/client@1.1.
|
|
3
|
+
`@cogcoin/client@1.1.12` is the reference Cogcoin client package for applications that want a local wallet, durable SQLite-backed state, and a managed Bitcoin Core integration around `@cogcoin/indexer`. It publishes the reusable client APIs, the SQLite adapter, the managed `bitcoind` integration, and the first-party `cogcoin` CLI in one package.
|
|
4
4
|
|
|
5
5
|
Use Node 22 or newer.
|
|
6
6
|
|
package/dist/bitcoind/rpc.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RpcBlock, RpcBlockchainInfo, RpcChainStatesResponse, RpcCreateWalletResult, RpcDecodedPsbt, RpcDescriptorInfo, RpcEstimateSmartFeeResult, RpcFinalizePsbtResult, RpcImportDescriptorRequest, RpcImportDescriptorResult, RpcListUnspentEntry, RpcMempoolEntry, RpcMempoolInfo, RpcRawMempoolVerbose, RpcListDescriptorsResult, RpcLockedUnspent, RpcLoadTxOutSetResult, RpcLoadWalletResult, RpcNetworkInfo, RpcTestMempoolAcceptResult, RpcWalletInfo, RpcWalletCreateFundedPsbtResult, RpcWalletProcessPsbtResult, RpcTransaction, RpcWalletTransaction, RpcZmqNotification } from "./types.js";
|
|
1
|
+
import type { RpcBlock, RpcBlockchainInfo, RpcChainStatesResponse, RpcCreateWalletResult, RpcDecodedPsbt, RpcDescriptorInfo, RpcEstimateSmartFeeResult, RpcFinalizePsbtResult, RpcImportDescriptorRequest, RpcImportDescriptorResult, RpcListUnspentEntry, RpcMempoolEntry, RpcMempoolInfo, RpcRawMempoolVerbose, RpcRawMempoolEntries, RpcListDescriptorsResult, RpcLockedUnspent, RpcLoadTxOutSetResult, RpcLoadWalletResult, RpcNetworkInfo, RpcTestMempoolAcceptResult, RpcWalletInfo, RpcWalletCreateFundedPsbtResult, RpcWalletProcessPsbtResult, RpcTransaction, RpcWalletTransaction, RpcZmqNotification } from "./types.js";
|
|
2
2
|
interface RpcRequestPayload {
|
|
3
3
|
readonly body: string;
|
|
4
4
|
readonly headers: Record<string, string>;
|
|
@@ -62,6 +62,7 @@ export declare class BitcoinRpcClient {
|
|
|
62
62
|
sendRawTransaction(hex: string): Promise<string>;
|
|
63
63
|
getRawMempool(): Promise<string[]>;
|
|
64
64
|
getRawMempoolVerbose(): Promise<RpcRawMempoolVerbose>;
|
|
65
|
+
getRawMempoolEntries(): Promise<RpcRawMempoolEntries>;
|
|
65
66
|
getMempoolInfo(): Promise<RpcMempoolInfo>;
|
|
66
67
|
getMempoolEntry(txid: string): Promise<RpcMempoolEntry>;
|
|
67
68
|
estimateSmartFee(confirmTarget: number, mode: "conservative" | "economical"): Promise<RpcEstimateSmartFeeResult>;
|
package/dist/bitcoind/rpc.js
CHANGED
|
@@ -351,6 +351,9 @@ export class BitcoinRpcClient {
|
|
|
351
351
|
getRawMempoolVerbose() {
|
|
352
352
|
return this.call("getrawmempool", [false, true]);
|
|
353
353
|
}
|
|
354
|
+
getRawMempoolEntries() {
|
|
355
|
+
return this.call("getrawmempool", [true]);
|
|
356
|
+
}
|
|
354
357
|
getMempoolInfo() {
|
|
355
358
|
return this.call("getmempoolinfo");
|
|
356
359
|
}
|
package/dist/bitcoind/types.d.ts
CHANGED
|
@@ -313,6 +313,7 @@ export interface RpcRawMempoolVerbose {
|
|
|
313
313
|
txids: string[];
|
|
314
314
|
mempool_sequence: string | number;
|
|
315
315
|
}
|
|
316
|
+
export type RpcRawMempoolEntries = Record<string, RpcMempoolEntry>;
|
|
316
317
|
export interface RpcWalletTransaction {
|
|
317
318
|
txid: string;
|
|
318
319
|
walletconflicts?: string[];
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { assaySentences } from "@cogcoin/scoring";
|
|
2
2
|
import type { WalletReadContext } from "../read/index.js";
|
|
3
3
|
import type { CompetitivenessDecision, MiningCandidate, MiningCooperativeYield, MiningRpcClient } from "./engine-types.js";
|
|
4
|
+
interface MiningGateWarmupProgress {
|
|
5
|
+
processed: number;
|
|
6
|
+
total: number;
|
|
7
|
+
}
|
|
4
8
|
export declare function clearMiningGateCache(walletRootId: string | null | undefined): void;
|
|
5
9
|
export declare function topologicallyOrderAncestorTxidsForTesting(options: {
|
|
6
10
|
txid: string;
|
|
@@ -20,4 +24,6 @@ export declare function runCompetitivenessGate(options: {
|
|
|
20
24
|
cooperativeYield?: MiningCooperativeYield;
|
|
21
25
|
cooperativeYieldEvery?: number;
|
|
22
26
|
throwIfStopping?: () => void;
|
|
27
|
+
onWarmupProgress?: (progress: MiningGateWarmupProgress) => Promise<void> | void;
|
|
23
28
|
}): Promise<CompetitivenessDecision>;
|
|
29
|
+
export {};
|
|
@@ -6,6 +6,8 @@ import { extractOpReturnPayloadFromScriptHex } from "../tx/register.js";
|
|
|
6
6
|
import { compareLexicographically, numberToSats, resolveBip39WordsFromIndices, rootDomain, tieBreakHash, } from "./engine-utils.js";
|
|
7
7
|
import { getIndexerTruthKey } from "./candidate.js";
|
|
8
8
|
const MINING_MEMPOOL_COOPERATIVE_YIELD_EVERY = 25;
|
|
9
|
+
const MINING_MEMPOOL_RAW_TX_FETCH_CONCURRENCY = 8;
|
|
10
|
+
const MINING_MEMPOOL_PROGRESS_REPORT_EVERY = 25;
|
|
9
11
|
const miningGateCache = new Map();
|
|
10
12
|
function defaultMiningCooperativeYield() {
|
|
11
13
|
return new Promise((resolve) => {
|
|
@@ -19,6 +21,98 @@ async function maybeYieldDuringMempoolScan(options) {
|
|
|
19
21
|
}
|
|
20
22
|
await (options.cooperativeYield ?? defaultMiningCooperativeYield)();
|
|
21
23
|
}
|
|
24
|
+
function getOrCreateMiningGateCacheState(walletRootId) {
|
|
25
|
+
const existing = miningGateCache.get(walletRootId);
|
|
26
|
+
if (existing !== undefined) {
|
|
27
|
+
return existing;
|
|
28
|
+
}
|
|
29
|
+
const created = {
|
|
30
|
+
rawTxContexts: new Map(),
|
|
31
|
+
decisionReuse: null,
|
|
32
|
+
};
|
|
33
|
+
miningGateCache.set(walletRootId, created);
|
|
34
|
+
return created;
|
|
35
|
+
}
|
|
36
|
+
function pruneRawTxContextsToVisibleTxids(options) {
|
|
37
|
+
const visibleSet = new Set(options.visibleTxids);
|
|
38
|
+
for (const txid of [...options.rawTxContexts.keys()]) {
|
|
39
|
+
if (!visibleSet.has(txid)) {
|
|
40
|
+
options.rawTxContexts.delete(txid);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function resolveEffectiveFeeRate(mempoolEntry) {
|
|
45
|
+
return Number([
|
|
46
|
+
mempoolEntry.vsize > 0 ? (numberToSats(mempoolEntry.fees.base) / BigInt(mempoolEntry.vsize)) : 0n,
|
|
47
|
+
(mempoolEntry.ancestorsize ?? 0) > 0
|
|
48
|
+
? (numberToSats(mempoolEntry.fees.ancestor) / BigInt(mempoolEntry.ancestorsize ?? 1))
|
|
49
|
+
: 0n,
|
|
50
|
+
(mempoolEntry.descendantsize ?? 0) > 0
|
|
51
|
+
? (numberToSats(mempoolEntry.fees.descendant) / BigInt(mempoolEntry.descendantsize ?? 1))
|
|
52
|
+
: 0n,
|
|
53
|
+
].reduce((best, candidate) => (candidate > best ? candidate : best), 0n));
|
|
54
|
+
}
|
|
55
|
+
async function warmMissingRawTxContexts(options) {
|
|
56
|
+
const missingTxids = options.visibleTxids.filter((txid) => !options.rawTxContexts.has(txid));
|
|
57
|
+
if (missingTxids.length === 0) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
let completed = 0;
|
|
61
|
+
let nextIndex = 0;
|
|
62
|
+
let lastReportedProcessed = -1;
|
|
63
|
+
let reportPromise = Promise.resolve();
|
|
64
|
+
const reportProgress = async (processed, force = false) => {
|
|
65
|
+
if (options.onWarmupProgress === undefined) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (!force && processed !== missingTxids.length && (processed % MINING_MEMPOOL_PROGRESS_REPORT_EVERY) !== 0) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (processed === lastReportedProcessed) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
lastReportedProcessed = processed;
|
|
75
|
+
reportPromise = reportPromise.then(async () => {
|
|
76
|
+
await options.onWarmupProgress?.({
|
|
77
|
+
processed,
|
|
78
|
+
total: missingTxids.length,
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
await reportPromise;
|
|
82
|
+
};
|
|
83
|
+
await reportProgress(0, true);
|
|
84
|
+
const workerCount = Math.min(MINING_MEMPOOL_RAW_TX_FETCH_CONCURRENCY, missingTxids.length);
|
|
85
|
+
const workers = Array.from({ length: workerCount }, async () => {
|
|
86
|
+
while (true) {
|
|
87
|
+
const iteration = nextIndex;
|
|
88
|
+
if (iteration >= missingTxids.length) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
nextIndex += 1;
|
|
92
|
+
await maybeYieldDuringMempoolScan({
|
|
93
|
+
iteration,
|
|
94
|
+
cooperativeYield: options.cooperativeYield,
|
|
95
|
+
cooperativeYieldEvery: options.cooperativeYieldEvery,
|
|
96
|
+
});
|
|
97
|
+
options.throwIfStopping?.();
|
|
98
|
+
const txid = missingTxids[iteration];
|
|
99
|
+
const tx = await options.rpc.getRawTransaction(txid, true).catch(() => null);
|
|
100
|
+
options.throwIfStopping?.();
|
|
101
|
+
if (tx !== null) {
|
|
102
|
+
const payloadHex = tx.vout.find((entry) => entry.scriptPubKey?.hex?.startsWith("6a") === true)?.scriptPubKey?.hex;
|
|
103
|
+
options.rawTxContexts.set(txid, {
|
|
104
|
+
txid,
|
|
105
|
+
senderScriptHex: tx.vin[0]?.prevout?.scriptPubKey?.hex ?? null,
|
|
106
|
+
rawTransaction: tx,
|
|
107
|
+
payload: payloadHex === undefined ? null : extractOpReturnPayloadFromScriptHex(payloadHex),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
completed += 1;
|
|
111
|
+
await reportProgress(completed, completed === missingTxids.length);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
await Promise.all(workers);
|
|
115
|
+
}
|
|
22
116
|
export function clearMiningGateCache(walletRootId) {
|
|
23
117
|
if (walletRootId === null || walletRootId === undefined) {
|
|
24
118
|
miningGateCache.clear();
|
|
@@ -368,9 +462,25 @@ export async function runCompetitivenessGate(options) {
|
|
|
368
462
|
options.candidate.canonicalBlend.toString(),
|
|
369
463
|
options.candidate.sender.scriptPubKeyHex,
|
|
370
464
|
].join(":");
|
|
465
|
+
const cacheState = getOrCreateMiningGateCacheState(walletRootId);
|
|
466
|
+
const setDecisionReuse = (decision) => {
|
|
467
|
+
cacheState.decisionReuse = {
|
|
468
|
+
indexerDaemonInstanceId: indexerTruthKey?.daemonInstanceId ?? "none",
|
|
469
|
+
indexerSnapshotSeq: indexerTruthKey?.snapshotSeq ?? "none",
|
|
470
|
+
referencedBlockHashDisplay: options.candidate.referencedBlockHashDisplay,
|
|
471
|
+
localAssayTupleKey,
|
|
472
|
+
excludedTxidsKey: excludedTxids.join(","),
|
|
473
|
+
mempoolSequence,
|
|
474
|
+
decision,
|
|
475
|
+
};
|
|
476
|
+
};
|
|
371
477
|
let mempoolVerbose;
|
|
478
|
+
let mempoolEntries;
|
|
372
479
|
try {
|
|
373
|
-
mempoolVerbose = await
|
|
480
|
+
[mempoolVerbose, mempoolEntries] = await Promise.all([
|
|
481
|
+
options.rpc.getRawMempoolVerbose(),
|
|
482
|
+
options.rpc.getRawMempoolEntries(),
|
|
483
|
+
]);
|
|
374
484
|
options.throwIfStopping?.();
|
|
375
485
|
}
|
|
376
486
|
catch {
|
|
@@ -379,17 +489,17 @@ export async function runCompetitivenessGate(options) {
|
|
|
379
489
|
});
|
|
380
490
|
}
|
|
381
491
|
const mempoolSequence = String(mempoolVerbose.mempool_sequence);
|
|
382
|
-
const cached =
|
|
383
|
-
const cachedTruthMatches = cached !==
|
|
492
|
+
const cached = cacheState.decisionReuse;
|
|
493
|
+
const cachedTruthMatches = cached !== null
|
|
384
494
|
&& indexerTruthKey !== null
|
|
385
495
|
&& cached.indexerDaemonInstanceId === indexerTruthKey.daemonInstanceId
|
|
386
496
|
&& cached.indexerSnapshotSeq === indexerTruthKey.snapshotSeq;
|
|
387
|
-
const cachedReferencedBlockMatches = cached !==
|
|
497
|
+
const cachedReferencedBlockMatches = cached !== null
|
|
388
498
|
&& cached.referencedBlockHashDisplay === options.candidate.referencedBlockHashDisplay;
|
|
389
|
-
if (cached !==
|
|
390
|
-
|
|
499
|
+
if (cached !== null && (!cachedTruthMatches || !cachedReferencedBlockMatches)) {
|
|
500
|
+
cacheState.decisionReuse = null;
|
|
391
501
|
}
|
|
392
|
-
if (cached !==
|
|
502
|
+
if (cached !== null
|
|
393
503
|
&& cachedTruthMatches
|
|
394
504
|
&& cachedReferencedBlockMatches
|
|
395
505
|
&& cached.localAssayTupleKey === localAssayTupleKey
|
|
@@ -402,47 +512,19 @@ export async function runCompetitivenessGate(options) {
|
|
|
402
512
|
}
|
|
403
513
|
const referencedPrefix = Buffer.from(options.candidate.referencedBlockHashInternal.subarray(0, 4)).toString("hex");
|
|
404
514
|
const visibleTxids = mempoolVerbose.txids.filter((txid) => !excludedTxids.includes(txid));
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
});
|
|
419
|
-
options.throwIfStopping?.();
|
|
420
|
-
const txid = visibleTxids[index];
|
|
421
|
-
if (txContexts.has(txid)) {
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
const [tx, mempoolEntry] = await Promise.all([
|
|
425
|
-
options.rpc.getRawTransaction(txid, true).catch(() => null),
|
|
426
|
-
options.rpc.getMempoolEntry(txid).catch(() => null),
|
|
427
|
-
]);
|
|
428
|
-
options.throwIfStopping?.();
|
|
429
|
-
if (tx === null || mempoolEntry === null) {
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
const effectiveFeeRate = Number([
|
|
433
|
-
mempoolEntry.vsize > 0 ? (numberToSats(mempoolEntry.fees.base) / BigInt(mempoolEntry.vsize)) : 0n,
|
|
434
|
-
(mempoolEntry.ancestorsize ?? 0) > 0 ? (numberToSats(mempoolEntry.fees.ancestor) / BigInt(mempoolEntry.ancestorsize ?? 1)) : 0n,
|
|
435
|
-
(mempoolEntry.descendantsize ?? 0) > 0 ? (numberToSats(mempoolEntry.fees.descendant) / BigInt(mempoolEntry.descendantsize ?? 1)) : 0n,
|
|
436
|
-
].reduce((best, candidate) => (candidate > best ? candidate : best), 0n));
|
|
437
|
-
const payloadHex = tx.vout.find((entry) => entry.scriptPubKey?.hex?.startsWith("6a") === true)?.scriptPubKey?.hex;
|
|
438
|
-
txContexts.set(txid, {
|
|
439
|
-
txid,
|
|
440
|
-
effectiveFeeRate,
|
|
441
|
-
senderScriptHex: tx.vin[0]?.prevout?.scriptPubKey?.hex ?? null,
|
|
442
|
-
rawTransaction: tx,
|
|
443
|
-
payload: payloadHex === undefined ? null : extractOpReturnPayloadFromScriptHex(payloadHex),
|
|
444
|
-
});
|
|
445
|
-
}
|
|
515
|
+
pruneRawTxContextsToVisibleTxids({
|
|
516
|
+
rawTxContexts: cacheState.rawTxContexts,
|
|
517
|
+
visibleTxids,
|
|
518
|
+
});
|
|
519
|
+
await warmMissingRawTxContexts({
|
|
520
|
+
rpc: options.rpc,
|
|
521
|
+
rawTxContexts: cacheState.rawTxContexts,
|
|
522
|
+
visibleTxids,
|
|
523
|
+
cooperativeYield: options.cooperativeYield,
|
|
524
|
+
cooperativeYieldEvery: options.cooperativeYieldEvery,
|
|
525
|
+
throwIfStopping: options.throwIfStopping,
|
|
526
|
+
onWarmupProgress: options.onWarmupProgress,
|
|
527
|
+
});
|
|
446
528
|
const entries = new Map();
|
|
447
529
|
for (let index = 0; index < visibleTxids.length; index += 1) {
|
|
448
530
|
await maybeYieldDuringMempoolScan({
|
|
@@ -452,8 +534,9 @@ export async function runCompetitivenessGate(options) {
|
|
|
452
534
|
});
|
|
453
535
|
options.throwIfStopping?.();
|
|
454
536
|
const txid = visibleTxids[index];
|
|
455
|
-
const context =
|
|
456
|
-
|
|
537
|
+
const context = cacheState.rawTxContexts.get(txid);
|
|
538
|
+
const mempoolEntry = mempoolEntries[txid];
|
|
539
|
+
if (context === undefined || context.payload === null || context.senderScriptHex === null || mempoolEntry === undefined) {
|
|
457
540
|
continue;
|
|
458
541
|
}
|
|
459
542
|
const decoded = decodeMinePayload(context.payload);
|
|
@@ -463,7 +546,7 @@ export async function runCompetitivenessGate(options) {
|
|
|
463
546
|
const overlayDomain = await resolveOverlayAuthorizedMiningDomain({
|
|
464
547
|
readContext: options.readContext,
|
|
465
548
|
txid,
|
|
466
|
-
txContexts,
|
|
549
|
+
txContexts: cacheState.rawTxContexts,
|
|
467
550
|
domainId: decoded.domainId,
|
|
468
551
|
senderScriptHex: context.senderScriptHex,
|
|
469
552
|
});
|
|
@@ -475,17 +558,7 @@ export async function runCompetitivenessGate(options) {
|
|
|
475
558
|
mempoolSequenceCacheStatus: "refreshed",
|
|
476
559
|
lastMempoolSequence: mempoolSequence,
|
|
477
560
|
});
|
|
478
|
-
|
|
479
|
-
indexerDaemonInstanceId: indexerTruthKey?.daemonInstanceId ?? "none",
|
|
480
|
-
indexerSnapshotSeq: indexerTruthKey?.snapshotSeq ?? "none",
|
|
481
|
-
referencedBlockHashDisplay: options.candidate.referencedBlockHashDisplay,
|
|
482
|
-
localAssayTupleKey,
|
|
483
|
-
excludedTxidsKey: excludedTxids.join(","),
|
|
484
|
-
mempoolSequence,
|
|
485
|
-
txids: [...visibleTxids],
|
|
486
|
-
txContexts,
|
|
487
|
-
decision,
|
|
488
|
-
});
|
|
561
|
+
setDecisionReuse(decision);
|
|
489
562
|
return decision;
|
|
490
563
|
}
|
|
491
564
|
if (overlayDomain === null || overlayDomain.name === null || !rootDomain(overlayDomain.name)) {
|
|
@@ -499,7 +572,7 @@ export async function runCompetitivenessGate(options) {
|
|
|
499
572
|
}
|
|
500
573
|
entries.set(txid, {
|
|
501
574
|
txid,
|
|
502
|
-
effectiveFeeRate:
|
|
575
|
+
effectiveFeeRate: resolveEffectiveFeeRate(mempoolEntry),
|
|
503
576
|
domainId: decoded.domainId,
|
|
504
577
|
domainName: overlayDomain.name,
|
|
505
578
|
sentence: Buffer.from(decoded.sentenceBytes).toString("utf8"),
|
|
@@ -631,16 +704,6 @@ export async function runCompetitivenessGate(options) {
|
|
|
631
704
|
});
|
|
632
705
|
}
|
|
633
706
|
}
|
|
634
|
-
|
|
635
|
-
indexerDaemonInstanceId: indexerTruthKey?.daemonInstanceId ?? "none",
|
|
636
|
-
indexerSnapshotSeq: indexerTruthKey?.snapshotSeq ?? "none",
|
|
637
|
-
referencedBlockHashDisplay: options.candidate.referencedBlockHashDisplay,
|
|
638
|
-
localAssayTupleKey,
|
|
639
|
-
excludedTxidsKey: excludedTxids.join(","),
|
|
640
|
-
mempoolSequence,
|
|
641
|
-
txids: [...visibleTxids],
|
|
642
|
-
txContexts,
|
|
643
|
-
decision,
|
|
644
|
-
});
|
|
707
|
+
setDecisionReuse(decision);
|
|
645
708
|
return decision;
|
|
646
709
|
}
|
|
@@ -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: {
|
package/package.json
CHANGED