@cogcoin/client 0.5.5 → 0.5.7
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 +11 -2
- package/dist/bitcoind/bootstrap/chainstate.d.ts +2 -1
- package/dist/bitcoind/bootstrap/chainstate.js +4 -1
- package/dist/bitcoind/bootstrap/controller.d.ts +4 -1
- package/dist/bitcoind/bootstrap/controller.js +42 -5
- package/dist/bitcoind/bootstrap/getblock-archive.d.ts +39 -0
- package/dist/bitcoind/bootstrap/getblock-archive.js +548 -0
- package/dist/bitcoind/bootstrap/headers.d.ts +12 -0
- package/dist/bitcoind/bootstrap/headers.js +95 -10
- package/dist/bitcoind/bootstrap.d.ts +1 -0
- package/dist/bitcoind/bootstrap.js +1 -0
- package/dist/bitcoind/client/factory.js +91 -28
- package/dist/bitcoind/client/managed-client.d.ts +1 -1
- package/dist/bitcoind/client/managed-client.js +4 -3
- package/dist/bitcoind/client/sync-engine.js +55 -13
- package/dist/bitcoind/errors.js +18 -0
- package/dist/bitcoind/indexer-daemon-main.js +78 -0
- package/dist/bitcoind/indexer-daemon.d.ts +10 -1
- package/dist/bitcoind/indexer-daemon.js +44 -28
- package/dist/bitcoind/node.js +2 -0
- package/dist/bitcoind/processing-start-height.d.ts +7 -0
- package/dist/bitcoind/processing-start-height.js +9 -0
- package/dist/bitcoind/progress/constants.d.ts +1 -0
- package/dist/bitcoind/progress/constants.js +1 -0
- package/dist/bitcoind/progress/controller.d.ts +22 -0
- package/dist/bitcoind/progress/controller.js +49 -23
- package/dist/bitcoind/progress/formatting.js +29 -1
- package/dist/bitcoind/progress/render-policy.d.ts +35 -0
- package/dist/bitcoind/progress/render-policy.js +81 -0
- package/dist/bitcoind/retryable-rpc.d.ts +11 -0
- package/dist/bitcoind/retryable-rpc.js +30 -0
- package/dist/bitcoind/service-paths.js +2 -6
- package/dist/bitcoind/service.d.ts +21 -2
- package/dist/bitcoind/service.js +274 -122
- package/dist/bitcoind/testing.d.ts +2 -2
- package/dist/bitcoind/testing.js +2 -2
- package/dist/bitcoind/types.d.ts +36 -1
- package/dist/cli/commands/follow.js +11 -0
- package/dist/cli/commands/getblock-archive-restart.d.ts +5 -0
- package/dist/cli/commands/getblock-archive-restart.js +15 -0
- package/dist/cli/commands/mining-admin.js +4 -0
- package/dist/cli/commands/mining-read.js +8 -5
- package/dist/cli/commands/mining-runtime.js +4 -0
- package/dist/cli/commands/service-runtime.js +150 -134
- package/dist/cli/commands/status.js +2 -0
- package/dist/cli/commands/sync.js +11 -0
- package/dist/cli/commands/wallet-admin.js +106 -24
- package/dist/cli/commands/wallet-mutation.js +57 -4
- package/dist/cli/commands/wallet-read.js +2 -0
- package/dist/cli/context.js +8 -4
- package/dist/cli/mutation-command-groups.d.ts +2 -1
- package/dist/cli/mutation-command-groups.js +5 -0
- package/dist/cli/mutation-json.d.ts +18 -2
- package/dist/cli/mutation-json.js +49 -0
- package/dist/cli/mutation-success.d.ts +1 -0
- package/dist/cli/mutation-success.js +2 -2
- package/dist/cli/output.js +86 -1
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +133 -3
- package/dist/cli/preview-json.d.ts +10 -1
- package/dist/cli/preview-json.js +32 -0
- package/dist/cli/prompt.js +1 -1
- package/dist/cli/runner.js +4 -0
- package/dist/cli/types.d.ts +15 -5
- package/dist/cli/types.js +1 -1
- package/dist/cli/wallet-format.js +140 -14
- package/dist/wallet/lifecycle.d.ts +21 -1
- package/dist/wallet/lifecycle.js +252 -116
- package/dist/wallet/mining/visualizer.d.ts +11 -6
- package/dist/wallet/mining/visualizer.js +32 -15
- package/dist/wallet/read/context.js +10 -4
- package/dist/wallet/reset.d.ts +61 -2
- package/dist/wallet/reset.js +246 -89
- package/dist/wallet/root-resolution.d.ts +20 -0
- package/dist/wallet/root-resolution.js +37 -0
- package/dist/wallet/runtime.d.ts +13 -1
- package/dist/wallet/runtime.js +54 -11
- package/dist/wallet/state/crypto.d.ts +3 -0
- package/dist/wallet/state/crypto.js +3 -0
- package/dist/wallet/state/provider.d.ts +1 -0
- package/dist/wallet/state/provider.js +119 -3
- package/dist/wallet/state/seed-index.d.ts +43 -0
- package/dist/wallet/state/seed-index.js +151 -0
- package/dist/wallet/state/storage.d.ts +7 -1
- package/dist/wallet/state/storage.js +39 -0
- package/dist/wallet/tx/anchor.d.ts +22 -0
- package/dist/wallet/tx/anchor.js +215 -8
- package/dist/wallet/tx/index.d.ts +1 -1
- package/dist/wallet/tx/index.js +1 -1
- package/dist/wallet/types.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@cogcoin/client`
|
|
2
2
|
|
|
3
|
-
`@cogcoin/client@0.5.
|
|
3
|
+
`@cogcoin/client@0.5.7` is the store-backed 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
|
|
|
@@ -107,6 +107,7 @@ The built-in managed-node integration:
|
|
|
107
107
|
- uses RPC for durable reads and ZMQ `hashblock` notifications for tip following
|
|
108
108
|
- launches a local full node with cookie auth
|
|
109
109
|
- defaults to an assumeutxo-first mainnet bootstrap using `https://snapshots.cogcoin.org/utxo-910000.dat`
|
|
110
|
+
- opportunistically loads the public getblock archive family from `https://snapshots.cogcoin.org/getblock-910000-latest.{json,dat}` to accelerate post-`910000` Bitcoin Core catch-up
|
|
110
111
|
- composes the existing SQLite-backed client rather than replacing it
|
|
111
112
|
|
|
112
113
|
If `dataDir` is omitted, the managed node defaults to:
|
|
@@ -120,7 +121,15 @@ On a fresh mainnet managed sync, `syncToTip()` or `startFollowingTip()`:
|
|
|
120
121
|
1. downloads the pinned Cogcoin UTXO snapshot with resume support
|
|
121
122
|
2. validates its known size and SHA-256
|
|
122
123
|
3. loads it with Bitcoin Core assumeutxo
|
|
123
|
-
4.
|
|
124
|
+
4. opportunistically downloads and validates the public getblock archive for raw post-snapshot Bitcoin blocks
|
|
125
|
+
5. loads that archive into managed Bitcoin Core when available
|
|
126
|
+
6. continues Bitcoin sync and Cogcoin replay from the managed node until the live tip is caught up
|
|
127
|
+
|
|
128
|
+
The public getblock archive provenance is tracked in the companion scraper repository:
|
|
129
|
+
|
|
130
|
+
- [`github.com/cogcoin/bitcoin-scrape`](https://github.com/cogcoin/bitcoin-scrape)
|
|
131
|
+
|
|
132
|
+
That repo documents how the `getblock-910000-latest.dat` and `getblock-910000-latest.json` artifacts are assembled from `bitcoin-cli getblockhash` plus `bitcoin-cli getblock <hash> 0`, including the blk-style file layout, manifest format, durability guarantees, and height-based cache-busting rules.
|
|
124
133
|
|
|
125
134
|
The managed `bitcoind` client also exposes:
|
|
126
135
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BitcoinRpcClient } from "../rpc.js";
|
|
2
|
-
import type { SnapshotMetadata } from "../types.js";
|
|
2
|
+
import type { RpcChainState, SnapshotMetadata } from "../types.js";
|
|
3
3
|
import type { BootstrapPersistentState } from "./types.js";
|
|
4
4
|
export declare function isSnapshotAlreadyLoaded(rpc: Pick<BitcoinRpcClient, "getChainStates">, snapshot: SnapshotMetadata, state: BootstrapPersistentState): Promise<boolean>;
|
|
5
|
+
export declare function findLoadedSnapshotChainState(rpc: Pick<BitcoinRpcClient, "getChainStates">, snapshot: SnapshotMetadata, state: BootstrapPersistentState): Promise<RpcChainState | null>;
|
|
@@ -8,6 +8,9 @@ function chainStateMatches(chainState, snapshot, baseHeight, tipHashHex) {
|
|
|
8
8
|
return chainState.blocks === snapshot.height && chainState.validated === false;
|
|
9
9
|
}
|
|
10
10
|
export async function isSnapshotAlreadyLoaded(rpc, snapshot, state) {
|
|
11
|
+
return (await findLoadedSnapshotChainState(rpc, snapshot, state)) !== null;
|
|
12
|
+
}
|
|
13
|
+
export async function findLoadedSnapshotChainState(rpc, snapshot, state) {
|
|
11
14
|
const chainStates = await rpc.getChainStates();
|
|
12
|
-
return chainStates.chainstates.
|
|
15
|
+
return chainStates.chainstates.find((chainState) => chainStateMatches(chainState, snapshot, state.baseHeight, state.tipHashHex)) ?? null;
|
|
13
16
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ClientTip } from "../../types.js";
|
|
2
2
|
import { ManagedProgressController } from "../progress.js";
|
|
3
3
|
import { BitcoinRpcClient } from "../rpc.js";
|
|
4
|
-
import
|
|
4
|
+
import { type ManagedRpcRetryState } from "../retryable-rpc.js";
|
|
5
|
+
import type { BootstrapPhase, SnapshotMetadata, SnapshotChunkManifest } from "../types.js";
|
|
5
6
|
export declare class AssumeUtxoBootstrapController {
|
|
6
7
|
#private;
|
|
7
8
|
constructor(options: {
|
|
@@ -9,12 +10,14 @@ export declare class AssumeUtxoBootstrapController {
|
|
|
9
10
|
dataDir: string;
|
|
10
11
|
progress: ManagedProgressController;
|
|
11
12
|
snapshot?: SnapshotMetadata;
|
|
13
|
+
manifest?: SnapshotChunkManifest;
|
|
12
14
|
fetchImpl?: typeof fetch;
|
|
13
15
|
});
|
|
14
16
|
get quoteStatePath(): string;
|
|
15
17
|
get snapshot(): SnapshotMetadata;
|
|
16
18
|
ensureReady(indexedTip: ClientTip | null, expectedChain: "main" | "regtest", options?: {
|
|
17
19
|
signal?: AbortSignal;
|
|
20
|
+
retryState?: ManagedRpcRetryState;
|
|
18
21
|
}): Promise<void>;
|
|
19
22
|
getStateForTesting(): Promise<{
|
|
20
23
|
metadataVersion: number;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
1
2
|
import { createBootstrapProgressForTesting, ManagedProgressController } from "../progress.js";
|
|
2
3
|
import { BitcoinRpcClient } from "../rpc.js";
|
|
3
4
|
import { DEFAULT_SNAPSHOT_METADATA } from "./constants.js";
|
|
@@ -5,7 +6,8 @@ import { downloadSnapshotFileForTesting } from "./download.js";
|
|
|
5
6
|
import { waitForHeaders } from "./headers.js";
|
|
6
7
|
import { resolveBootstrapPaths } from "./paths.js";
|
|
7
8
|
import { loadBootstrapStateRecord, saveBootstrapState } from "./state.js";
|
|
8
|
-
import { isSnapshotAlreadyLoaded } from "./chainstate.js";
|
|
9
|
+
import { findLoadedSnapshotChainState, isSnapshotAlreadyLoaded } from "./chainstate.js";
|
|
10
|
+
import { describeManagedRpcRetryError, isRetryableManagedRpcError, } from "../retryable-rpc.js";
|
|
9
11
|
async function loadSnapshotIntoNode(rpc, snapshotPath) {
|
|
10
12
|
return rpc.loadTxOutSet(snapshotPath);
|
|
11
13
|
}
|
|
@@ -14,13 +16,17 @@ export class AssumeUtxoBootstrapController {
|
|
|
14
16
|
#paths;
|
|
15
17
|
#progress;
|
|
16
18
|
#snapshot;
|
|
19
|
+
#debugLogPath;
|
|
20
|
+
#manifest;
|
|
17
21
|
#fetchImpl;
|
|
18
22
|
#stateRecordPromise = null;
|
|
19
23
|
constructor(options) {
|
|
20
24
|
this.#rpc = options.rpc;
|
|
21
25
|
this.#progress = options.progress;
|
|
22
26
|
this.#snapshot = options.snapshot ?? DEFAULT_SNAPSHOT_METADATA;
|
|
27
|
+
this.#manifest = options.manifest;
|
|
23
28
|
this.#paths = resolveBootstrapPaths(options.dataDir, this.#snapshot);
|
|
29
|
+
this.#debugLogPath = join(options.dataDir, "debug.log");
|
|
24
30
|
this.#fetchImpl = options.fetchImpl;
|
|
25
31
|
}
|
|
26
32
|
get quoteStatePath() {
|
|
@@ -47,18 +53,23 @@ export class AssumeUtxoBootstrapController {
|
|
|
47
53
|
}
|
|
48
54
|
const { state, snapshotIdentity } = await this.#loadStateRecord();
|
|
49
55
|
if (state.loadTxOutSetComplete && await isSnapshotAlreadyLoaded(this.#rpc, this.#snapshot, state)) {
|
|
56
|
+
if (state.lastError !== null) {
|
|
57
|
+
state.lastError = null;
|
|
58
|
+
await saveBootstrapState(this.#paths, state);
|
|
59
|
+
}
|
|
50
60
|
await this.#progress.setPhase("bitcoin_sync", {
|
|
51
61
|
blocks: state.baseHeight,
|
|
52
62
|
targetHeight: state.baseHeight ?? this.#snapshot.height,
|
|
53
63
|
baseHeight: state.baseHeight,
|
|
54
64
|
tipHashHex: state.tipHashHex,
|
|
55
65
|
message: "Using the previously loaded assumeutxo chainstate.",
|
|
56
|
-
lastError:
|
|
66
|
+
lastError: null,
|
|
57
67
|
});
|
|
58
68
|
return;
|
|
59
69
|
}
|
|
60
70
|
await downloadSnapshotFileForTesting({
|
|
61
71
|
fetchImpl: this.#fetchImpl,
|
|
72
|
+
manifest: this.#manifest,
|
|
62
73
|
metadata: this.#snapshot,
|
|
63
74
|
paths: this.#paths,
|
|
64
75
|
progress: this.#progress,
|
|
@@ -69,22 +80,48 @@ export class AssumeUtxoBootstrapController {
|
|
|
69
80
|
if (!await isSnapshotAlreadyLoaded(this.#rpc, this.#snapshot, state)) {
|
|
70
81
|
await waitForHeaders(this.#rpc, this.#snapshot, this.#progress, {
|
|
71
82
|
signal: options.signal,
|
|
83
|
+
retryState: options.retryState,
|
|
84
|
+
debugLogPath: this.#debugLogPath,
|
|
72
85
|
});
|
|
73
86
|
await this.#progress.setPhase("load_snapshot", {
|
|
74
87
|
downloadedBytes: this.#snapshot.sizeBytes,
|
|
75
88
|
totalBytes: this.#snapshot.sizeBytes,
|
|
76
89
|
percent: 100,
|
|
77
90
|
message: "Loading the UTXO snapshot into bitcoind.",
|
|
91
|
+
lastError: null,
|
|
78
92
|
});
|
|
79
|
-
|
|
93
|
+
let loadResult;
|
|
94
|
+
try {
|
|
95
|
+
loadResult = await loadSnapshotIntoNode(this.#rpc, this.#paths.snapshotPath);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (!isRetryableManagedRpcError(error)) {
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
state.lastError = describeManagedRpcRetryError(error);
|
|
102
|
+
await saveBootstrapState(this.#paths, state);
|
|
103
|
+
const loadedChainState = await findLoadedSnapshotChainState(this.#rpc, this.#snapshot, state);
|
|
104
|
+
if (loadedChainState === null) {
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
loadResult = {
|
|
108
|
+
base_height: loadedChainState.blocks ?? this.#snapshot.height,
|
|
109
|
+
coins_loaded: 0,
|
|
110
|
+
tip_hash: loadedChainState.snapshot_blockhash ?? state.tipHashHex ?? "",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
80
113
|
state.loadTxOutSetComplete = true;
|
|
81
114
|
state.baseHeight = loadResult.base_height;
|
|
82
|
-
state.tipHashHex = loadResult.tip_hash;
|
|
115
|
+
state.tipHashHex = loadResult.tip_hash === "" ? state.tipHashHex : loadResult.tip_hash;
|
|
83
116
|
state.phase = "bitcoin_sync";
|
|
84
117
|
state.lastError = null;
|
|
85
118
|
await saveBootstrapState(this.#paths, state);
|
|
86
119
|
}
|
|
87
120
|
const info = await this.#rpc.getBlockchainInfo();
|
|
121
|
+
if (state.lastError !== null) {
|
|
122
|
+
state.lastError = null;
|
|
123
|
+
await saveBootstrapState(this.#paths, state);
|
|
124
|
+
}
|
|
88
125
|
await this.#progress.setPhase("bitcoin_sync", {
|
|
89
126
|
blocks: info.blocks,
|
|
90
127
|
headers: info.headers,
|
|
@@ -92,7 +129,7 @@ export class AssumeUtxoBootstrapController {
|
|
|
92
129
|
baseHeight: state.baseHeight,
|
|
93
130
|
tipHashHex: state.tipHashHex,
|
|
94
131
|
message: "Bitcoin Core is syncing blocks after assumeutxo bootstrap.",
|
|
95
|
-
lastError:
|
|
132
|
+
lastError: null,
|
|
96
133
|
});
|
|
97
134
|
}
|
|
98
135
|
async getStateForTesting() {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ManagedProgressController } from "../progress.js";
|
|
2
|
+
import type { GetblockArchiveManifest } from "../types.js";
|
|
3
|
+
interface GetblockArchivePaths {
|
|
4
|
+
directory: string;
|
|
5
|
+
artifactPath: string;
|
|
6
|
+
partialArtifactPath: string;
|
|
7
|
+
manifestPath: string;
|
|
8
|
+
partialManifestPath: string;
|
|
9
|
+
statePath: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ReadyGetblockArchive {
|
|
12
|
+
manifest: GetblockArchiveManifest;
|
|
13
|
+
artifactPath: string;
|
|
14
|
+
manifestPath: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function resolveGetblockArchivePathsForTesting(dataDir: string): GetblockArchivePaths;
|
|
17
|
+
export declare function resolveReadyGetblockArchiveForTesting(dataDir: string): Promise<ReadyGetblockArchive | null>;
|
|
18
|
+
export declare function prepareLatestGetblockArchive(options: {
|
|
19
|
+
dataDir: string;
|
|
20
|
+
progress: Pick<ManagedProgressController, "setPhase">;
|
|
21
|
+
fetchImpl?: typeof fetch;
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
}): Promise<ReadyGetblockArchive | null>;
|
|
24
|
+
export declare const prepareLatestGetblockArchiveForTesting: typeof prepareLatestGetblockArchive;
|
|
25
|
+
export declare function waitForGetblockArchiveImportForTesting(rpc: Pick<{
|
|
26
|
+
getBlockchainInfo(): Promise<{
|
|
27
|
+
blocks: number;
|
|
28
|
+
headers: number;
|
|
29
|
+
bestblockhash: string;
|
|
30
|
+
}>;
|
|
31
|
+
}, "getBlockchainInfo">, progress: Pick<ManagedProgressController, "setPhase">, targetEndHeight: number, signal?: AbortSignal): Promise<void>;
|
|
32
|
+
export declare function waitForGetblockArchiveImport(rpc: Pick<{
|
|
33
|
+
getBlockchainInfo(): Promise<{
|
|
34
|
+
blocks: number;
|
|
35
|
+
headers: number;
|
|
36
|
+
bestblockhash: string;
|
|
37
|
+
}>;
|
|
38
|
+
}, "getBlockchainInfo">, progress: Pick<ManagedProgressController, "setPhase">, targetEndHeight: number, signal?: AbortSignal): Promise<void>;
|
|
39
|
+
export {};
|