@cogcoin/client 1.1.4 → 1.1.6
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 +4 -5
- package/dist/bitcoind/indexer-daemon.d.ts +3 -7
- package/dist/bitcoind/indexer-daemon.js +43 -158
- package/dist/bitcoind/managed-runtime/bitcoind-policy.d.ts +16 -0
- package/dist/bitcoind/managed-runtime/bitcoind-policy.js +177 -0
- package/dist/bitcoind/managed-runtime/indexer-policy.d.ts +34 -0
- package/dist/bitcoind/managed-runtime/indexer-policy.js +200 -0
- package/dist/bitcoind/managed-runtime/status.d.ts +11 -0
- package/dist/bitcoind/managed-runtime/status.js +59 -0
- package/dist/bitcoind/managed-runtime/types.d.ts +37 -0
- package/dist/bitcoind/managed-runtime/types.js +1 -0
- package/dist/bitcoind/progress/tty-renderer.js +3 -2
- package/dist/bitcoind/service.d.ts +2 -7
- package/dist/bitcoind/service.js +46 -94
- package/dist/cli/command-registry.d.ts +39 -0
- package/dist/cli/command-registry.js +1132 -0
- package/dist/cli/commands/client-admin.js +6 -56
- package/dist/cli/commands/mining-admin.js +9 -32
- package/dist/cli/commands/mining-read.js +15 -56
- package/dist/cli/commands/mining-runtime.js +258 -57
- package/dist/cli/commands/service-runtime.js +1 -64
- package/dist/cli/commands/status.js +2 -15
- package/dist/cli/commands/update.js +6 -21
- package/dist/cli/commands/wallet-admin.js +18 -120
- package/dist/cli/commands/wallet-mutation.js +4 -7
- package/dist/cli/commands/wallet-read.js +31 -138
- package/dist/cli/context.js +2 -4
- package/dist/cli/mining-format.js +8 -2
- package/dist/cli/mutation-command-groups.d.ts +11 -11
- package/dist/cli/mutation-command-groups.js +9 -18
- package/dist/cli/mutation-json.d.ts +1 -17
- package/dist/cli/mutation-json.js +1 -28
- package/dist/cli/mutation-success.d.ts +0 -1
- package/dist/cli/mutation-success.js +0 -19
- package/dist/cli/output.d.ts +1 -10
- package/dist/cli/output.js +52 -481
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +38 -695
- package/dist/cli/runner.js +28 -113
- package/dist/cli/types.d.ts +7 -8
- package/dist/cli/update-notifier.js +1 -1
- package/dist/cli/wallet-format.js +1 -1
- package/dist/wallet/lifecycle/access.d.ts +5 -0
- package/dist/wallet/lifecycle/access.js +79 -0
- package/dist/wallet/lifecycle/context.d.ts +26 -0
- package/dist/wallet/lifecycle/context.js +58 -0
- package/dist/wallet/lifecycle/managed-core.d.ts +15 -0
- package/dist/wallet/lifecycle/managed-core.js +197 -0
- package/dist/wallet/lifecycle/repair-bitcoind.d.ts +10 -0
- package/dist/wallet/lifecycle/repair-bitcoind.js +142 -0
- package/dist/wallet/lifecycle/repair-indexer.d.ts +8 -0
- package/dist/wallet/lifecycle/repair-indexer.js +117 -0
- package/dist/wallet/lifecycle/repair-mining.d.ts +49 -0
- package/dist/wallet/lifecycle/repair-mining.js +304 -0
- package/dist/wallet/lifecycle/repair-runtime.d.ts +36 -0
- package/dist/wallet/lifecycle/repair-runtime.js +206 -0
- package/dist/wallet/lifecycle/repair.d.ts +9 -0
- package/dist/wallet/lifecycle/repair.js +127 -0
- package/dist/wallet/lifecycle/setup-prompts.d.ts +7 -0
- package/dist/wallet/lifecycle/setup-prompts.js +88 -0
- package/dist/wallet/lifecycle/setup-state.d.ts +26 -0
- package/dist/wallet/lifecycle/setup-state.js +159 -0
- package/dist/wallet/lifecycle/setup.d.ts +15 -0
- package/dist/wallet/lifecycle/setup.js +124 -0
- package/dist/wallet/lifecycle/types.d.ts +156 -0
- package/dist/wallet/lifecycle/types.js +1 -0
- package/dist/wallet/lifecycle.d.ts +4 -165
- package/dist/wallet/lifecycle.js +3 -1656
- package/dist/wallet/mining/candidate.d.ts +60 -0
- package/dist/wallet/mining/candidate.js +290 -0
- package/dist/wallet/mining/competitiveness.d.ts +22 -0
- package/dist/wallet/mining/competitiveness.js +640 -0
- package/dist/wallet/mining/control.js +7 -251
- package/dist/wallet/mining/cycle.d.ts +39 -0
- package/dist/wallet/mining/cycle.js +542 -0
- package/dist/wallet/mining/engine-state.d.ts +66 -0
- package/dist/wallet/mining/engine-state.js +211 -0
- package/dist/wallet/mining/engine-types.d.ts +173 -0
- package/dist/wallet/mining/engine-types.js +1 -0
- package/dist/wallet/mining/engine-utils.d.ts +7 -0
- package/dist/wallet/mining/engine-utils.js +75 -0
- package/dist/wallet/mining/events.d.ts +2 -0
- package/dist/wallet/mining/events.js +19 -0
- package/dist/wallet/mining/lifecycle.d.ts +71 -0
- package/dist/wallet/mining/lifecycle.js +355 -0
- package/dist/wallet/mining/projection.d.ts +61 -0
- package/dist/wallet/mining/projection.js +319 -0
- package/dist/wallet/mining/publish.d.ts +79 -0
- package/dist/wallet/mining/publish.js +614 -0
- package/dist/wallet/mining/runner.d.ts +12 -418
- package/dist/wallet/mining/runner.js +274 -3433
- package/dist/wallet/mining/supervisor.d.ts +134 -0
- package/dist/wallet/mining/supervisor.js +558 -0
- package/dist/wallet/mining/visualizer-sync.d.ts +42 -0
- package/dist/wallet/mining/visualizer-sync.js +166 -0
- package/dist/wallet/mining/visualizer.d.ts +1 -0
- package/dist/wallet/mining/visualizer.js +33 -18
- package/dist/wallet/read/context.js +13 -188
- package/dist/wallet/reset.d.ts +1 -1
- package/dist/wallet/reset.js +35 -11
- package/dist/wallet/runtime.d.ts +0 -6
- package/dist/wallet/runtime.js +2 -38
- package/dist/wallet/tx/common.d.ts +18 -0
- package/dist/wallet/tx/common.js +40 -26
- package/package.json +1 -1
- package/dist/wallet/state/seed-index.d.ts +0 -43
- package/dist/wallet/state/seed-index.js +0 -151
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { MiningCandidate, MiningRpcClient, ReadyMiningReadContext } from "./engine-types.js";
|
|
2
|
+
import type { WalletRuntimePaths } from "../runtime.js";
|
|
3
|
+
import type { WalletSecretProvider } from "../state/provider.js";
|
|
4
|
+
import type { WalletReadContext } from "../read/index.js";
|
|
5
|
+
import type { WalletStateV1 } from "../types.js";
|
|
6
|
+
import type { MiningRuntimeStatusV1 } from "./types.js";
|
|
7
|
+
import { type MiningSentenceGenerationRequest } from "./sentences.js";
|
|
8
|
+
export interface MiningEligibleAnchoredRoot {
|
|
9
|
+
domainId: number;
|
|
10
|
+
domainName: string;
|
|
11
|
+
localIndex: number;
|
|
12
|
+
sender: MiningCandidate["sender"];
|
|
13
|
+
}
|
|
14
|
+
export interface IndexerTruthKey {
|
|
15
|
+
walletRootId: string;
|
|
16
|
+
daemonInstanceId: string;
|
|
17
|
+
snapshotSeq: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function getIndexerTruthKey(readContext: WalletReadContext & {
|
|
20
|
+
localState: {
|
|
21
|
+
availability: "ready";
|
|
22
|
+
state: WalletStateV1;
|
|
23
|
+
};
|
|
24
|
+
snapshot: NonNullable<WalletReadContext["snapshot"]>;
|
|
25
|
+
}): IndexerTruthKey | null;
|
|
26
|
+
export declare function ensureIndexerTruthIsCurrent(options: {
|
|
27
|
+
dataDir: string;
|
|
28
|
+
truthKey: IndexerTruthKey | null;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
export declare function determineCorePublishState(info: {
|
|
31
|
+
blockchain: Awaited<ReturnType<MiningRpcClient["getBlockchainInfo"]>>;
|
|
32
|
+
network: Awaited<ReturnType<MiningRpcClient["getNetworkInfo"]>>;
|
|
33
|
+
mempool: Awaited<ReturnType<MiningRpcClient["getMempoolInfo"]>>;
|
|
34
|
+
}): MiningRuntimeStatusV1["corePublishState"];
|
|
35
|
+
export declare function resolveEligibleAnchoredRoots(context: WalletReadContext): MiningEligibleAnchoredRoot[];
|
|
36
|
+
export declare function refreshMiningCandidateFromCurrentState(context: ReadyMiningReadContext, candidate: MiningCandidate): MiningCandidate | null;
|
|
37
|
+
export declare function buildMiningGenerationRequest(options: {
|
|
38
|
+
targetBlockHeight: number;
|
|
39
|
+
referencedBlockHashDisplay: string;
|
|
40
|
+
generatedAtUnixMs?: number;
|
|
41
|
+
requestId?: string;
|
|
42
|
+
domains: Array<{
|
|
43
|
+
domainId: number;
|
|
44
|
+
domainName: string;
|
|
45
|
+
requiredWords: [string, string, string, string, string];
|
|
46
|
+
}>;
|
|
47
|
+
domainExtraPrompts: Record<string, string>;
|
|
48
|
+
extraPrompt: string | null;
|
|
49
|
+
}): MiningSentenceGenerationRequest;
|
|
50
|
+
export declare function generateCandidatesForDomains(options: {
|
|
51
|
+
rpc: MiningRpcClient;
|
|
52
|
+
readContext: ReadyMiningReadContext;
|
|
53
|
+
domains: MiningEligibleAnchoredRoot[];
|
|
54
|
+
provider: WalletSecretProvider;
|
|
55
|
+
paths: WalletRuntimePaths;
|
|
56
|
+
indexerTruthKey: IndexerTruthKey | null;
|
|
57
|
+
runId?: string | null;
|
|
58
|
+
fetchImpl?: typeof fetch;
|
|
59
|
+
}): Promise<MiningCandidate[]>;
|
|
60
|
+
export declare function chooseBestLocalCandidate(candidates: MiningCandidate[]): Promise<MiningCandidate | null>;
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { assaySentences, deriveBlendSeed, displayToInternalBlockhash, getWords, settleBlock, } from "@cogcoin/scoring";
|
|
3
|
+
import { probeIndexerDaemon } from "../../bitcoind/indexer-daemon.js";
|
|
4
|
+
import { loadClientConfig } from "./config.js";
|
|
5
|
+
import { isMiningGenerationAbortRequested, markMiningGenerationActive, markMiningGenerationInactive, } from "./coordination.js";
|
|
6
|
+
import { createMiningSentenceRequestLimits } from "./sentence-protocol.js";
|
|
7
|
+
import { generateMiningSentences } from "./sentences.js";
|
|
8
|
+
import { isMineableWalletDomain } from "../read/index.js";
|
|
9
|
+
import { lookupDomain } from "@cogcoin/indexer/queries";
|
|
10
|
+
const BEST_BLOCK_POLL_INTERVAL_MS = 500;
|
|
11
|
+
export function getIndexerTruthKey(readContext) {
|
|
12
|
+
if (readContext.snapshot.daemonInstanceId == null
|
|
13
|
+
|| readContext.snapshot.snapshotSeq == null) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
walletRootId: readContext.localState.state.walletRootId,
|
|
18
|
+
daemonInstanceId: readContext.snapshot.daemonInstanceId,
|
|
19
|
+
snapshotSeq: readContext.snapshot.snapshotSeq,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async function indexerTruthIsCurrent(options) {
|
|
23
|
+
if (options.truthKey === null) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
const probe = await probeIndexerDaemon({
|
|
27
|
+
dataDir: options.dataDir,
|
|
28
|
+
walletRootId: options.truthKey.walletRootId,
|
|
29
|
+
});
|
|
30
|
+
try {
|
|
31
|
+
return probe.compatibility === "compatible"
|
|
32
|
+
&& probe.status !== null
|
|
33
|
+
&& probe.status.state === "synced"
|
|
34
|
+
&& probe.status.daemonInstanceId === options.truthKey.daemonInstanceId
|
|
35
|
+
&& probe.status.snapshotSeq === options.truthKey.snapshotSeq;
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await probe.client?.close().catch(() => undefined);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export async function ensureIndexerTruthIsCurrent(options) {
|
|
42
|
+
if (!await indexerTruthIsCurrent(options)) {
|
|
43
|
+
throw new Error("mining_generation_stale_indexer_truth");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function determineCorePublishState(info) {
|
|
47
|
+
if (info.network.networkactive === false) {
|
|
48
|
+
return "network-inactive";
|
|
49
|
+
}
|
|
50
|
+
if ((info.network.connections_out ?? 0) <= 0) {
|
|
51
|
+
return "no-outbound-peers";
|
|
52
|
+
}
|
|
53
|
+
if (info.blockchain.initialblockdownload === true) {
|
|
54
|
+
return "ibd";
|
|
55
|
+
}
|
|
56
|
+
if (info.mempool.loaded === false) {
|
|
57
|
+
return "mempool-loading";
|
|
58
|
+
}
|
|
59
|
+
return "healthy";
|
|
60
|
+
}
|
|
61
|
+
export function resolveEligibleAnchoredRoots(context) {
|
|
62
|
+
const state = context.localState.state;
|
|
63
|
+
const model = context.model;
|
|
64
|
+
const snapshot = context.snapshot;
|
|
65
|
+
if (state === null || model === null || snapshot === null) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
const domains = [];
|
|
69
|
+
for (const domain of model.domains) {
|
|
70
|
+
if (!isMineableWalletDomain(context, domain)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const domainId = domain.domainId;
|
|
74
|
+
if (domainId === null
|
|
75
|
+
|| domainId === undefined
|
|
76
|
+
|| domain.ownerAddress == null
|
|
77
|
+
|| domain.ownerScriptPubKeyHex !== model.walletScriptPubKeyHex) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const chainDomain = lookupDomain(snapshot.state, domain.name);
|
|
81
|
+
if (chainDomain === null || !chainDomain.anchored) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
domains.push({
|
|
85
|
+
domainId,
|
|
86
|
+
domainName: domain.name,
|
|
87
|
+
localIndex: 0,
|
|
88
|
+
sender: {
|
|
89
|
+
localIndex: 0,
|
|
90
|
+
scriptPubKeyHex: model.walletScriptPubKeyHex,
|
|
91
|
+
address: domain.ownerAddress,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return domains.sort((left, right) => left.domainId - right.domainId || left.domainName.localeCompare(right.domainName));
|
|
96
|
+
}
|
|
97
|
+
export function refreshMiningCandidateFromCurrentState(context, candidate) {
|
|
98
|
+
const refreshed = resolveEligibleAnchoredRoots(context).find((domain) => domain.domainId === candidate.domainId);
|
|
99
|
+
if (refreshed === undefined) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
...candidate,
|
|
104
|
+
domainName: refreshed.domainName,
|
|
105
|
+
localIndex: refreshed.localIndex,
|
|
106
|
+
sender: refreshed.sender,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function buildMiningGenerationRequest(options) {
|
|
110
|
+
return {
|
|
111
|
+
schemaVersion: 1,
|
|
112
|
+
requestId: options.requestId ?? `mining-${options.targetBlockHeight}-${randomBytes(8).toString("hex")}`,
|
|
113
|
+
targetBlockHeight: options.targetBlockHeight,
|
|
114
|
+
referencedBlockHashDisplay: options.referencedBlockHashDisplay,
|
|
115
|
+
generatedAtUnixMs: options.generatedAtUnixMs ?? Date.now(),
|
|
116
|
+
extraPrompt: options.extraPrompt,
|
|
117
|
+
limits: createMiningSentenceRequestLimits(),
|
|
118
|
+
rootDomains: options.domains.map((domain) => ({
|
|
119
|
+
domainId: domain.domainId,
|
|
120
|
+
domainName: domain.domainName,
|
|
121
|
+
requiredWords: domain.requiredWords,
|
|
122
|
+
extraPrompt: options.domainExtraPrompts[domain.domainName.toLowerCase()] ?? null,
|
|
123
|
+
})),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
export async function generateCandidatesForDomains(options) {
|
|
127
|
+
const bestBlockHash = options.readContext.nodeStatus?.nodeBestHashHex;
|
|
128
|
+
if (bestBlockHash === null || bestBlockHash === undefined) {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
const targetBlockHeight = (options.readContext.nodeStatus?.nodeBestHeight ?? 0) + 1;
|
|
132
|
+
const referencedBlockHashInternal = Buffer.from(displayToInternalBlockhash(bestBlockHash), "hex");
|
|
133
|
+
const rootDomains = options.domains.map((domain) => ({
|
|
134
|
+
...domain,
|
|
135
|
+
requiredWords: getWords(domain.domainId, referencedBlockHashInternal),
|
|
136
|
+
}));
|
|
137
|
+
const clientConfig = await loadClientConfig({
|
|
138
|
+
path: options.paths.clientConfigPath,
|
|
139
|
+
provider: options.provider,
|
|
140
|
+
}).catch(() => null);
|
|
141
|
+
const abortController = new AbortController();
|
|
142
|
+
let stale = false;
|
|
143
|
+
let staleIndexerTruth = false;
|
|
144
|
+
let preempted = false;
|
|
145
|
+
const timer = setInterval(async () => {
|
|
146
|
+
try {
|
|
147
|
+
const [current, truthCurrent] = await Promise.all([
|
|
148
|
+
options.rpc.getBlockchainInfo(),
|
|
149
|
+
indexerTruthIsCurrent({
|
|
150
|
+
dataDir: options.readContext.dataDir,
|
|
151
|
+
truthKey: options.indexerTruthKey,
|
|
152
|
+
}),
|
|
153
|
+
]);
|
|
154
|
+
if (current.bestblockhash !== bestBlockHash) {
|
|
155
|
+
stale = true;
|
|
156
|
+
abortController.abort();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (!truthCurrent) {
|
|
160
|
+
staleIndexerTruth = true;
|
|
161
|
+
abortController.abort();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (await isMiningGenerationAbortRequested(options.paths)) {
|
|
165
|
+
preempted = true;
|
|
166
|
+
abortController.abort();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// Ignore transient polling failures and let the main cycle degrade on the next tick.
|
|
171
|
+
}
|
|
172
|
+
}, BEST_BLOCK_POLL_INTERVAL_MS);
|
|
173
|
+
try {
|
|
174
|
+
await markMiningGenerationActive({
|
|
175
|
+
paths: options.paths,
|
|
176
|
+
runId: options.runId ?? null,
|
|
177
|
+
pid: process.pid ?? null,
|
|
178
|
+
});
|
|
179
|
+
const generationRequest = buildMiningGenerationRequest({
|
|
180
|
+
targetBlockHeight,
|
|
181
|
+
referencedBlockHashDisplay: bestBlockHash,
|
|
182
|
+
domains: rootDomains,
|
|
183
|
+
domainExtraPrompts: clientConfig?.mining.domainExtraPrompts ?? {},
|
|
184
|
+
extraPrompt: clientConfig?.mining.builtIn?.extraPrompt ?? null,
|
|
185
|
+
});
|
|
186
|
+
let generated;
|
|
187
|
+
try {
|
|
188
|
+
generated = await generateMiningSentences(generationRequest, {
|
|
189
|
+
paths: options.paths,
|
|
190
|
+
provider: options.provider,
|
|
191
|
+
signal: abortController.signal,
|
|
192
|
+
fetchImpl: options.fetchImpl,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (stale) {
|
|
197
|
+
throw new Error("mining_generation_stale_tip");
|
|
198
|
+
}
|
|
199
|
+
if (staleIndexerTruth) {
|
|
200
|
+
throw new Error("mining_generation_stale_indexer_truth");
|
|
201
|
+
}
|
|
202
|
+
if (preempted) {
|
|
203
|
+
throw new Error("mining_generation_preempted");
|
|
204
|
+
}
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
if (stale) {
|
|
208
|
+
throw new Error("mining_generation_stale_tip");
|
|
209
|
+
}
|
|
210
|
+
if (staleIndexerTruth) {
|
|
211
|
+
throw new Error("mining_generation_stale_indexer_truth");
|
|
212
|
+
}
|
|
213
|
+
if (preempted) {
|
|
214
|
+
throw new Error("mining_generation_preempted");
|
|
215
|
+
}
|
|
216
|
+
await ensureIndexerTruthIsCurrent({
|
|
217
|
+
dataDir: options.readContext.dataDir,
|
|
218
|
+
truthKey: options.indexerTruthKey,
|
|
219
|
+
});
|
|
220
|
+
const sentencesByDomain = new Map();
|
|
221
|
+
for (const candidate of generated.candidates) {
|
|
222
|
+
const existing = sentencesByDomain.get(candidate.domainId) ?? [];
|
|
223
|
+
existing.push(candidate.sentence);
|
|
224
|
+
sentencesByDomain.set(candidate.domainId, existing);
|
|
225
|
+
}
|
|
226
|
+
const candidates = [];
|
|
227
|
+
for (const domain of rootDomains) {
|
|
228
|
+
const domainSentences = sentencesByDomain.get(domain.domainId) ?? [];
|
|
229
|
+
if (domainSentences.length === 0) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const assayed = await assaySentences(domain.domainId, referencedBlockHashInternal, domainSentences);
|
|
233
|
+
const best = assayed.find((entry) => entry.gatesPass && entry.encodedSentenceBytes !== null && entry.rank === 1);
|
|
234
|
+
if (best === undefined || best.encodedSentenceBytes === null || best.canonicalBlend === null) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
candidates.push({
|
|
238
|
+
domainId: domain.domainId,
|
|
239
|
+
domainName: domain.domainName,
|
|
240
|
+
localIndex: domain.localIndex,
|
|
241
|
+
sender: domain.sender,
|
|
242
|
+
sentence: best.sentence,
|
|
243
|
+
encodedSentenceBytes: best.encodedSentenceBytes,
|
|
244
|
+
bip39WordIndices: [...best.bip39WordIndices],
|
|
245
|
+
bip39Words: best.bip39Words,
|
|
246
|
+
canonicalBlend: best.canonicalBlend,
|
|
247
|
+
referencedBlockHashDisplay: bestBlockHash,
|
|
248
|
+
referencedBlockHashInternal,
|
|
249
|
+
targetBlockHeight,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return candidates;
|
|
253
|
+
}
|
|
254
|
+
finally {
|
|
255
|
+
clearInterval(timer);
|
|
256
|
+
await markMiningGenerationInactive({
|
|
257
|
+
paths: options.paths,
|
|
258
|
+
runId: options.runId ?? null,
|
|
259
|
+
pid: process.pid ?? null,
|
|
260
|
+
}).catch(() => undefined);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
export async function chooseBestLocalCandidate(candidates) {
|
|
264
|
+
if (candidates.length === 0) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
if (candidates.length === 1) {
|
|
268
|
+
return candidates[0];
|
|
269
|
+
}
|
|
270
|
+
const blendSeed = deriveBlendSeed(candidates[0].referencedBlockHashInternal);
|
|
271
|
+
const winners = await settleBlock({
|
|
272
|
+
blendSeed,
|
|
273
|
+
blockRewardCogtoshi: 100n,
|
|
274
|
+
submissions: candidates
|
|
275
|
+
.slice()
|
|
276
|
+
.sort((left, right) => left.domainId - right.domainId || left.domainName.localeCompare(right.domainName))
|
|
277
|
+
.map((candidate, index) => ({
|
|
278
|
+
miningDomainId: candidate.domainId,
|
|
279
|
+
rawSentenceBytes: candidate.encodedSentenceBytes,
|
|
280
|
+
recipientScriptPubKey: Buffer.from(candidate.sender.scriptPubKeyHex, "hex"),
|
|
281
|
+
bip39WordIndices: candidate.bip39WordIndices,
|
|
282
|
+
txIndex: index,
|
|
283
|
+
})),
|
|
284
|
+
});
|
|
285
|
+
const winner = winners[0];
|
|
286
|
+
if (winner === undefined) {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
return candidates.find((candidate) => candidate.domainId === winner.miningDomainId) ?? null;
|
|
290
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { assaySentences } from "@cogcoin/scoring";
|
|
2
|
+
import type { WalletReadContext } from "../read/index.js";
|
|
3
|
+
import type { CompetitivenessDecision, MiningCandidate, MiningCooperativeYield, MiningRpcClient } from "./engine-types.js";
|
|
4
|
+
export declare function clearMiningGateCache(walletRootId: string | null | undefined): void;
|
|
5
|
+
export declare function topologicallyOrderAncestorTxidsForTesting(options: {
|
|
6
|
+
txid: string;
|
|
7
|
+
txContexts: Map<string, {
|
|
8
|
+
txid: string;
|
|
9
|
+
rawTransaction: Awaited<ReturnType<MiningRpcClient["getRawTransaction"]>>;
|
|
10
|
+
}>;
|
|
11
|
+
}): string[] | null;
|
|
12
|
+
export declare function runCompetitivenessGate(options: {
|
|
13
|
+
rpc: MiningRpcClient;
|
|
14
|
+
readContext: WalletReadContext & {
|
|
15
|
+
snapshot: NonNullable<WalletReadContext["snapshot"]>;
|
|
16
|
+
};
|
|
17
|
+
candidate: MiningCandidate;
|
|
18
|
+
currentTxid: string | null;
|
|
19
|
+
assaySentencesImpl?: typeof assaySentences;
|
|
20
|
+
cooperativeYield?: MiningCooperativeYield;
|
|
21
|
+
cooperativeYieldEvery?: number;
|
|
22
|
+
}): Promise<CompetitivenessDecision>;
|