@did-btcr2/cli 0.25.1 → 0.25.2
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/dist/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +34 -34
- package/dist/esm/src/commands/config.js +1 -1
- package/dist/esm/src/commands/config.js.map +1 -1
- package/dist/esm/src/commands/quickstart.js +2 -2
- package/dist/esm/src/commands/quickstart.js.map +1 -1
- package/dist/esm/src/config.js +50 -46
- package/dist/esm/src/config.js.map +1 -1
- package/dist/types/src/config.d.ts +10 -7
- package/dist/types/src/config.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/commands/config.ts +1 -1
- package/src/commands/quickstart.ts +2 -2
- package/src/config.ts +52 -51
package/src/config.ts
CHANGED
|
@@ -958,7 +958,7 @@ export function resolveEffectiveConfig(network: NetworkOption, overrides?: Conne
|
|
|
958
958
|
};
|
|
959
959
|
}
|
|
960
960
|
|
|
961
|
-
/** One endpoint
|
|
961
|
+
/** One endpoint check produced by `config doctor`. */
|
|
962
962
|
export interface DoctorCheck {
|
|
963
963
|
endpoint : 'btc-rest' | 'btc-rpc' | 'cas';
|
|
964
964
|
target : string;
|
|
@@ -966,81 +966,82 @@ export interface DoctorCheck {
|
|
|
966
966
|
detail? : string;
|
|
967
967
|
}
|
|
968
968
|
|
|
969
|
-
/** Result of `config doctor`: per
|
|
969
|
+
/** Result of `config doctor`: one check per endpoint, and any coherence warning. */
|
|
970
970
|
export interface DoctorReport {
|
|
971
971
|
checks : DoctorCheck[];
|
|
972
972
|
coherence? : { profile: string; declared: NetworkOption; encoding: NetworkOption };
|
|
973
973
|
}
|
|
974
974
|
|
|
975
|
-
/**
|
|
975
|
+
/** The timeout (ms) of each `config doctor` check. */
|
|
976
976
|
const DOCTOR_PROBE_TIMEOUT_MS = 5000;
|
|
977
977
|
|
|
978
|
-
/**
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
978
|
+
/**
|
|
979
|
+
* A block that only the chain of each network has: the genesis block, or block 1 on
|
|
980
|
+
* signet and mutinynet, because all signets share one genesis block. A `config doctor`
|
|
981
|
+
* check reads the hash at this height, to prove that an endpoint serves the chain of
|
|
982
|
+
* the network.
|
|
983
|
+
*/
|
|
984
|
+
const CHAIN_MARKER: Record<NetworkOption, { height: number; hash: string }> = {
|
|
985
|
+
bitcoin : { height: 0, hash: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f' },
|
|
986
|
+
testnet3 : { height: 0, hash: '000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943' },
|
|
987
|
+
testnet4 : { height: 0, hash: '00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043' },
|
|
988
|
+
signet : { height: 1, hash: '00000086d6b2636cb2a392d45edc4ec544a10024d30141c9adf4bfd9de533b53' },
|
|
989
|
+
mutinynet : { height: 1, hash: '000002855893a0a9b24eaffc5efc770558a326fee4fc10c9da22fc19cd2954f9' },
|
|
990
|
+
regtest : { height: 0, hash: '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206' },
|
|
991
|
+
};
|
|
992
|
+
|
|
993
|
+
/** Runs one check. A rejection gives a failed check with the error message as the detail. */
|
|
994
|
+
async function runCheck(endpoint: DoctorCheck['endpoint'], target: string, check: () => Promise<void>): Promise<DoctorCheck> {
|
|
985
995
|
try {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
headers : opts?.headers,
|
|
989
|
-
signal : AbortSignal.timeout(DOCTOR_PROBE_TIMEOUT_MS),
|
|
990
|
-
});
|
|
991
|
-
return res.ok
|
|
992
|
-
? { endpoint, target, ok: true }
|
|
993
|
-
: { endpoint, target, ok: false, detail: `HTTP ${res.status}` };
|
|
996
|
+
await check();
|
|
997
|
+
return { endpoint, target, ok: true };
|
|
994
998
|
} catch (error) {
|
|
995
999
|
return { endpoint, target, ok: false, detail: (error as Error).message };
|
|
996
1000
|
}
|
|
997
1001
|
}
|
|
998
1002
|
|
|
999
|
-
/**
|
|
1000
|
-
function
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
});
|
|
1005
|
-
return Promise.race([ promise, timeout ]).finally(() => clearTimeout(timer));
|
|
1003
|
+
/** Throws if a block hash is not the hash of the chain marker of the network. */
|
|
1004
|
+
function assertChainMarker(network: NetworkOption, hash: unknown): void {
|
|
1005
|
+
const marker = CHAIN_MARKER[network];
|
|
1006
|
+
if (hash === marker.hash) return;
|
|
1007
|
+
const got = (typeof hash === 'string' ? hash : JSON.stringify(hash) ?? String(hash)).slice(0, 80);
|
|
1008
|
+
throw new Error(`block ${marker.height} is ${got}, not the ${network} block ${marker.hash}: the endpoint serves another chain`);
|
|
1006
1009
|
}
|
|
1007
1010
|
|
|
1008
1011
|
/**
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
1012
|
+
* Checks the resolved endpoints of one network for `config doctor`. Each check uses
|
|
1013
|
+
* the api client of the commands (with a 5-second abort), so it tests the request
|
|
1014
|
+
* path of the commands, not only a connection:
|
|
1015
|
+
* - `btc-rest` and `btc-rpc`: read the hash of the {@link CHAIN_MARKER} block. A pass
|
|
1016
|
+
* proves an Esplora or a Bitcoin Core endpoint for the chain of the network.
|
|
1017
|
+
* - `cas`: `CasApi.probe` reads a fixed identity block through the resolved backend
|
|
1018
|
+
* (the RPC endpoint if one is set, else the gateway) and compares the bytes.
|
|
1019
|
+
* Also surfaces the profile/network coherence warning. Reads the network; never writes.
|
|
1014
1020
|
*/
|
|
1015
1021
|
export async function runDoctor(network: NetworkOption, overrides?: ConnectionOverrides): Promise<DoctorReport> {
|
|
1016
|
-
const
|
|
1022
|
+
const conn = resolveConnectionConfig(network, overrides);
|
|
1023
|
+
const api = createApi({
|
|
1024
|
+
btc : { ...conn.btc, network, timeoutMs: DOCTOR_PROBE_TIMEOUT_MS },
|
|
1025
|
+
cas : { ...(conn.cas ?? { gateway: DEFAULT_CAS_GATEWAY }), timeoutMs: DOCTOR_PROBE_TIMEOUT_MS },
|
|
1026
|
+
});
|
|
1027
|
+
const height = CHAIN_MARKER[network].height;
|
|
1017
1028
|
const checks: DoctorCheck[] = [];
|
|
1018
1029
|
|
|
1019
|
-
const
|
|
1020
|
-
checks.push(await
|
|
1030
|
+
const rest = api.btc.connection.rest;
|
|
1031
|
+
checks.push(await runCheck('btc-rest', rest.config.host.replace(/\/+$/, ''), async () => {
|
|
1032
|
+
assertChainMarker(network, await rest.block.getHash(height));
|
|
1033
|
+
}));
|
|
1021
1034
|
|
|
1022
1035
|
const rpc = api.btc.connection.rpc;
|
|
1023
1036
|
if (rpc) {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
checks.push({ endpoint: 'btc-rpc', target, ok: true });
|
|
1028
|
-
} catch (error) {
|
|
1029
|
-
checks.push({ endpoint: 'btc-rpc', target, ok: false, detail: (error as Error).message });
|
|
1030
|
-
}
|
|
1037
|
+
checks.push(await runCheck('btc-rpc', rpc.config.host ?? '(default rpc)', async () => {
|
|
1038
|
+
assertChainMarker(network, await rpc.getBlockHash(height));
|
|
1039
|
+
}));
|
|
1031
1040
|
}
|
|
1032
1041
|
|
|
1033
|
-
//
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
const conn = resolveConnectionConfig(network, overrides);
|
|
1037
|
-
if (conn.cas?.rpcUrl) {
|
|
1038
|
-
const base = conn.cas.rpcUrl.replace(/\/+$/, '');
|
|
1039
|
-
checks.push(await probeEndpoint('cas', conn.cas.rpcUrl, `${base}/api/v0/version`, { method: 'POST' }));
|
|
1040
|
-
} else {
|
|
1041
|
-
const gateway = (conn.cas?.gateway ?? DEFAULT_CAS_GATEWAY).replace(/\/+$/, '');
|
|
1042
|
-
checks.push(await probeEndpoint('cas', gateway, gateway));
|
|
1043
|
-
}
|
|
1042
|
+
// The api selects the RPC endpoint over the gateway, so the check names that target.
|
|
1043
|
+
const casTarget = (conn.cas?.rpcUrl ?? conn.cas?.gateway ?? DEFAULT_CAS_GATEWAY).replace(/\/+$/, '');
|
|
1044
|
+
checks.push(await runCheck('cas', casTarget, () => api.cas.probe()));
|
|
1044
1045
|
|
|
1045
1046
|
const mismatch = profileNetworkMismatch(network, overrides);
|
|
1046
1047
|
return {
|