UNPKG

@btc-vision/bitcoin-rpc

Version:

The one and only fully typed Bitcoin RPC client for Node.js

1,047 lines (825 loc) 32.1 kB
import { Logger } from '@btc-vision/bsi-common'; import { Blockhash, CreateWalletParams, EstimateSmartFeeParams, GetBlockFilterParams, GetBlockHeaderParams, GetBlockParams, GetBlockStatsParams, GetChainTxStatsParams, GetMemPoolParams, GetRawTransactionParams, GetTxOutParams, GetTxOutProofParams, Height, RPCClient, RPCIniOptions, SendRawTransactionParams, TxId, Verbose, } from './external/rpc.js'; import { AddressByLabel } from './types/AddressByLabel.js'; import { RPCConfig } from './interfaces/RPCConfig.js'; import { BasicBlockInfo } from './types/BasicBlockInfo.js'; import { BitcoinRawTransactionParams, RawTransaction } from './types/BitcoinRawTransaction.js'; import { BitcoinVerbosity } from './types/BitcoinVerbosity.js'; import { BlockchainInfo } from './types/BlockchainInfo.js'; import { BlockData, BlockDataWithTransactionData } from './types/BlockData.js'; import { BlockFilterInfo } from './types/BlockFilterInfo.js'; import { BlockHeaderInfo } from './types/BlockHeaderInfo.js'; import { BlockStats } from './types/BlockStats.js'; import { ChainTipInfo } from './types/ChainTipInfo.js'; import { ChainTxStats } from './types/ChainTxStats.js'; import { CreateWalletResponse } from './types/CreateWalletResponse.js'; import { FeeEstimation, SmartFeeEstimation } from './types/FeeEstimation.js'; import { MempoolInfo } from './types/MempoolInfo.js'; import { MemPoolTransactionInfo, RawMemPoolTransactionInfo, } from './types/MemPoolTransactionInfo.js'; import { TransactionOutputInfo } from './types/TransactionOutputInfo.js'; import { TransactionOutputSetInfo } from './types/TransactionOutputSetInfo.js'; import { WalletInfo } from './types/WalletInfo.js'; import { RawMempool } from './types/RawMempool.js'; export class BitcoinRPC extends Logger { public readonly logColor: string = '#fa9600'; private rpc: RPCClient | null = null; private blockchainInfo: BlockchainInfo | null = null; private currentBlockInfo: BasicBlockInfo | null = null; private purgeInterval: NodeJS.Timeout | null = null; constructor( private readonly cacheClearInterval: number = 1000, private readonly enableDebug: boolean = false, ) { super(); this.purgeCachedData(); } public destroy(): void { if (this.purgeInterval) { clearInterval(this.purgeInterval); } this.rpc = null; this.blockchainInfo = null; this.currentBlockInfo = null; } public getRpcConfigFromBlockchainConfig(rpcInfo: RPCConfig): RPCIniOptions { return { url: `http://${rpcInfo.BITCOIND_HOST}`, port: rpcInfo.BITCOIND_PORT, user: rpcInfo.BITCOIND_USERNAME, pass: rpcInfo.BITCOIND_PASSWORD, }; } public async getBestBlockHash(): Promise<string | null> { this.debugMessage('getBestBlockHash'); if (!this.rpc) { throw new Error('RPC not initialized'); } const bestBlockHash = (await this.rpc.getbestblockhash().catch((e: unknown) => { this.error(`Error getting best block hash: ${e}`); return; })) as string | null; return bestBlockHash || null; } public async getBlockBatch(blockHashes: string[]): Promise<BlockData[] | null> { this.debugMessage('getBlockBatch'); if (!this.rpc) { throw new Error('RPC not initialized'); } const blockData: BlockData[] | null = (await this.rpc .getblockBatch(blockHashes) .catch((e: unknown) => { this.error(`Error getting block batch: ${e}`); return null; })) as BlockData[] | null; return blockData || null; } public async getBlockAsHexString(blockHash: string): Promise<string | null> { this.debugMessage('getBlockAsHexString'); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetBlockParams = { blockhash: blockHash, verbosity: BitcoinVerbosity.NONE, }; const blockData: string | null = (await this.rpc.getblock(param).catch((e: unknown) => { this.error(`Error getting block data: ${e}`); return null; })) as string | null; return blockData == '' ? null : blockData; } public async estimateSmartFee( confTarget: number, estimateMode: FeeEstimation = FeeEstimation.CONSERVATIVE, ): Promise<SmartFeeEstimation> { this.debugMessage('estimateSmartFee'); if (!this.rpc) { throw new Error('RPC not initialized'); } const opts: EstimateSmartFeeParams = { conf_target: confTarget, estimate_mode: estimateMode, }; return (await this.rpc.estimatesmartfee(opts)) as SmartFeeEstimation; } public async joinPSBTs(psbts: string[]): Promise<string | null> { this.debugMessage('joinPSBTs'); if (!this.rpc) { throw new Error('RPC not initialized'); } const result: string | null = (await this.rpc .joinpsbts({ txs: psbts, }) .catch((e: unknown) => { this.error(`Error joining PSBTs: ${e}`); return ''; })) as string | null; return result || null; } public async getBlockInfoOnly(blockHash: string): Promise<BlockData | null> { this.debugMessage('getBlockInfoOnly'); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetBlockParams = { blockhash: blockHash, verbosity: BitcoinVerbosity.RAW, }; const blockData: BlockData | null = (await this.rpc.getblock(param).catch((e: unknown) => { this.error(`Error getting block data: ${e}`); return null; })) as BlockData | null; return blockData || null; } public async getBlockInfoWithTransactionData( blockHash: string, ): Promise<BlockDataWithTransactionData | null> { this.debugMessage(`getBlockInfoWithTransactionData ${blockHash}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetBlockParams = { blockhash: blockHash, verbosity: 2, }; const blockData: BlockDataWithTransactionData | null = (await this.rpc .getblock(param) .catch((e: unknown) => { this.error(`Error getting block data: ${e}`); return null; })) as BlockDataWithTransactionData | null; return blockData || null; } public async getBlockHashes(height: number, count: number): Promise<(string | null)[] | null> { this.debugMessage(`getBlockHashes ${height} ${count}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: Height = { height, }; const blockHashes: (string | null)[] | null = (await this.rpc .getblockhashes(param, count) .catch((e: unknown) => { this.error(`Error getting block hashes: ${e}`); return []; })) as (string | null)[] | null; return blockHashes || null; } public async getBlocksInfoWithTransactionData( blockHashes: string[], ): Promise<(BlockDataWithTransactionData | null)[] | null> { if (!this.rpc) { throw new Error('RPC not initialized'); } const blockData: (BlockDataWithTransactionData | null)[] | null = (await this.rpc .getblockBatch(blockHashes, 2) .catch((e: unknown) => { this.error(`Error getting block data: ${e}`); return null; })) as unknown as (BlockDataWithTransactionData | null)[]; return blockData || null; } public async getBlockCount(): Promise<number | null> { this.debugMessage('getBlockCount'); if (!this.rpc) { throw new Error('RPC not initialized'); } const blockCount: number | null = (await this.rpc.getblockcount().catch((e: unknown) => { this.error(`Error getting block count: ${e}`); return 0; })) as number | null; return blockCount ?? null; } public async getBlockFilter( blockHash: string, filterType?: string, ): Promise<BlockFilterInfo | null> { this.debugMessage(`getBlockFilter ${blockHash}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetBlockFilterParams = { blockhash: blockHash, filtertype: filterType, }; const result: BlockFilterInfo | null = (await this.rpc .getblockfilter(param) .catch((e: unknown) => { this.error(`Error getting block filter: ${e}`); return null; })) as BlockFilterInfo | null; return result || null; } public async getBlockHash(height: number): Promise<string | null> { this.debugMessage(`getBlockHash ${height}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: Height = { height: height, }; const result: string | null = (await this.rpc.getblockhash(param).catch((e: unknown) => { this.error(`Error getting block hash: ${e}`); return ''; })) as string | null; return result || null; } public async getChainInfo(): Promise<BlockchainInfo | null> { this.debugMessage('getChainInfo'); if (!this.rpc) { throw new Error('RPC not initialized'); } this.blockchainInfo = (await this.rpc.getblockchaininfo()) as BlockchainInfo | null; if (this.blockchainInfo) { this.currentBlockInfo = { blockHeight: this.blockchainInfo.blocks, blockHash: this.blockchainInfo.bestblockhash, }; } return this.blockchainInfo; } public async getWalletInfo(walletName: string): Promise<WalletInfo | null> { this.debugMessage(`getWalletInfo ${walletName}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const walletInfo: WalletInfo | null = (await this.rpc .getwalletinfo(walletName) .catch((e: unknown) => { this.error(`Error getting wallet info: ${e}`); return null; })) as WalletInfo | null; return walletInfo || null; } public async createWallet(params: CreateWalletParams): Promise<CreateWalletResponse | null> { this.debugMessage('createWallet'); if (!this.rpc) { throw new Error('RPC not initialized'); } const wallet: CreateWalletResponse | null = (await this.rpc .createwallet(params) .catch((e: unknown) => { this.error(`Error creating wallet: ${e}`); return ''; })) as CreateWalletResponse | null; return wallet || null; } public async loadWallet(filename: string): Promise<CreateWalletResponse | null> { this.debugMessage(`loadWallet ${filename}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const params: { filename: string } = { filename, }; const wallet: CreateWalletResponse | null = (await this.rpc .loadwallet(params) .catch((e: unknown) => { this.error(`Error loading wallet: ${e}`); return ''; })) as CreateWalletResponse | null; return wallet || null; } public async listWallets(): Promise<string[] | null> { this.debugMessage('listWallets'); if (!this.rpc) { throw new Error('RPC not initialized'); } const wallets: string[] | null = (await this.rpc.listwallets().catch((e: unknown) => { this.error(`Error listing wallets: ${e}`); return []; })) as string[] | null; return wallets || null; } public async getNewAddress(label: string, wallet?: string): Promise<string | null> { this.debugMessage(`getNewAddress ${label}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const params: { label: string } = { label, }; const address: string | null = (await this.rpc .getnewaddress(params, wallet) .catch((e: unknown) => { this.error(`Error getting new address: ${e}`); return ''; })) as string | null; return address || null; } public async generateToAddress( nBlock: number, address: string, wallet?: string, ): Promise<string[] | null> { this.debugMessage(`generateToAddress ${nBlock} ${address}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const params: { nblocks: number; address: string } = { nblocks: nBlock, address, }; const blockHashes: string[] | null = (await this.rpc .generatetoaddress(params, wallet) .catch((e: unknown) => { this.error(`Error generating to address: ${e}`); return []; })) as string[] | null; return blockHashes || null; } public async importPrivateKey( privateKey: string, label: string, rescan?: boolean, wallet?: string, ): Promise<void> { this.debugMessage(`importPrivateKey ${label}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const params: { privkey: string; label: string; rescan?: boolean } = { privkey: privateKey, label, rescan, }; await this.rpc.importprivkey(params, wallet).catch((e: unknown) => { this.error(`Error importing private key: ${e}`); }); } public async getAddressByLabel(label: string, wallet?: string): Promise<AddressByLabel | null> { this.debugMessage(`getAddressByLabel ${label}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const params: { label: string } = { label, }; const address: AddressByLabel | null = (await this.rpc .getaddressesbylabel(params, wallet) .catch((e: unknown) => { this.error(`Error getting address by label: ${e}`); throw e; })) as AddressByLabel | null; return address || null; } public async sendRawTransaction(params: SendRawTransactionParams): Promise<string | null> { this.debugMessage('sendRawTransaction'); if (!this.rpc) { throw new Error('RPC not initialized'); } const txId: string | null = (await this.rpc .sendrawtransaction(params) .catch((e: unknown) => { throw e; })) as string | null; return txId || null; } public async dumpPrivateKey(address: string, wallet?: string): Promise<string | null> { this.debugMessage(`dumpPrivateKey ${address}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const privateKey: string | null = (await this.rpc .dumpprivkey( { address, }, wallet, ) .catch((e: unknown) => { this.error(`Error dumping private key: ${e}`); return ''; })) as string | null; return privateKey || null; } public async getRawTransaction<V extends BitcoinVerbosity>( parameters: BitcoinRawTransactionParams, ): Promise<RawTransaction<V> | null> { this.debugMessage(`getRawTransaction ${parameters.txId}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const params: GetRawTransactionParams = { txid: parameters.txId, verbose: parameters.verbose !== BitcoinVerbosity.RAW, }; if (parameters.blockHash) { params.blockhash = parameters.blockHash; } const rawTx: RawTransaction<V> | null = (await this.rpc .getrawtransaction(params) .catch((e: unknown) => { this.error(`Error getting raw transaction: ${e}`); return null; })) as RawTransaction<V> | null; return rawTx || null; } public async getRawTransactions<V extends BitcoinVerbosity>( txs: string[], verbose?: V, ): Promise<(RawTransaction<V> | null)[] | null> { this.debugMessage(`getRawTransactions ${txs}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const txsInfo: (RawTransaction<V> | null)[] | null = (await this.rpc .getrawtransactionBatch(txs, verbose !== BitcoinVerbosity.RAW) .catch((e: unknown) => { this.error(`Error getting raw transactions: ${e}`); return null; })) as (RawTransaction<V> | null)[]; return txsInfo || null; } public async getBlockHeight(): Promise<BasicBlockInfo | null> { this.debugMessage('getBlockHeight'); if (!this.rpc) { throw new Error('RPC not initialized'); } if (!this.currentBlockInfo) { await this.getChainInfo(); } return this.currentBlockInfo; } public async getBlockHeader( blockHash: string, verbose?: boolean, ): Promise<BlockHeaderInfo | null> { this.debugMessage(`getBlockHeader ${blockHash} ${verbose}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetBlockHeaderParams = { blockhash: blockHash, verbose: verbose, }; const header: BlockHeaderInfo | null = (await this.rpc .getblockheader(param) .catch((e: unknown) => { this.error(`Error getting block header: ${e}`); return ''; })) as BlockHeaderInfo | null; return header || null; } public async getBlockStatsByHeight( height: number, stats?: string[], ): Promise<BlockStats | null> { this.debugMessage(`getBlockStatsByHeight ${height} ${stats}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetBlockStatsParams = { hash_or_height: height, stats: stats, }; const blockStats: BlockStats | null = (await this.rpc .getblockstats(param) .catch((e: unknown) => { this.error(`Error getting block stats: ${e}`); return null; })) as BlockStats | null; return blockStats || null; } public async getBlockStatsByHash( blockHash: string, stats?: string[], ): Promise<BlockStats | null> { this.debugMessage(`getBlockStatsByHash ${blockHash} ${stats}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetBlockStatsParams = { hash_or_height: blockHash, stats: stats, }; const blockStats: BlockStats | null = (await this.rpc .getblockstats(param) .catch((e: unknown) => { this.error(`Error getting block stats: ${e}`); return null; })) as BlockStats | null; return blockStats || null; } public async getChainTips(): Promise<ChainTipInfo[] | null> { this.debugMessage('getChainTips'); if (!this.rpc) { throw new Error('RPC not initialized'); } const tips: ChainTipInfo[] | null = (await this.rpc.getchaintips().catch((e: unknown) => { this.error(`Error getting chain tips: ${e}`); return null; })) as ChainTipInfo[] | null; return tips || null; } public async getChainTxStats(param: GetChainTxStatsParams): Promise<ChainTxStats | null> { this.debugMessage('getChainTxStats'); if (!this.rpc) { throw new Error('RPC not initialized'); } const chainTxStats: ChainTxStats | null = (await this.rpc .getchaintxstats(param) .catch((e: unknown) => { this.error(`Error getting chain tx stats: ${e}`); return null; })) as ChainTxStats | null; return chainTxStats || null; } public async getDifficulty(): Promise<number | null> { this.debugMessage('getDifficulty'); if (!this.rpc) { throw new Error('RPC not initialized'); } const difficulty: number | null = (await this.rpc.getdifficulty().catch((e: unknown) => { this.error(`Error getting difficulty: ${e}`); return 0; })) as number | null; return difficulty ?? null; } public async getMempoolAncestors<V extends BitcoinVerbosity>( txId: string, verbose?: V, ): Promise<MemPoolTransactionInfo<V> | null> { this.debugMessage(`getMempoolAncestors ${txId}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetMemPoolParams = { txid: txId, verbose: verbose !== BitcoinVerbosity.RAW, }; const transactionInfo: MemPoolTransactionInfo<V> | null = (await this.rpc .getmempoolancestors(param) .catch((e: unknown) => { this.error(`Error getting mempool ancestors: ${e}`); return null; })) as MemPoolTransactionInfo<V> | null; return transactionInfo || null; } public async getMempoolDescendants<V extends BitcoinVerbosity>( txid: string, verbose?: V, ): Promise<MemPoolTransactionInfo<V> | null> { this.debugMessage(`getMempoolDescendants ${txid}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetMemPoolParams = { txid: txid, verbose: verbose !== BitcoinVerbosity.RAW, }; const transactionInfo: MemPoolTransactionInfo<V> | null = (await this.rpc .getmempooldescendants(param) .catch((e: unknown) => { this.error(`Error getting mempool descendants: ${e}`); return null; })) as MemPoolTransactionInfo<V> | null; return transactionInfo || null; } public async getMempoolEntry(txid: string): Promise<RawMemPoolTransactionInfo | null> { this.debugMessage(`getMempoolEntry ${txid}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: TxId = { txid: txid, }; const transactionInfo: RawMemPoolTransactionInfo | null = (await this.rpc .getmempoolentry(param) .catch((e: unknown) => { this.error(`Error getting mempool entry: ${e}`); return null; })) as RawMemPoolTransactionInfo | null; return transactionInfo || null; } public async getMempoolInfo(): Promise<MempoolInfo<BitcoinVerbosity.NONE> | null> { this.debugMessage('getMempoolInfo'); if (!this.rpc) { throw new Error('RPC not initialized'); } const mempoolInfo: MempoolInfo<BitcoinVerbosity.NONE> | null = (await this.rpc .getmempoolinfo() .catch((e: unknown) => { this.error(`Error getting mempool info: ${e}`); return null; })) as MempoolInfo<BitcoinVerbosity.NONE> | null; return mempoolInfo || null; } public async getRawMempool<V extends BitcoinVerbosity>( verbose?: V, ): Promise<RawMempool<V> | null> { this.debugMessage('getRawMempool'); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: Verbose = { verbose: verbose !== BitcoinVerbosity.RAW, }; const mempoolInfo: RawMempool<V> | null = (await this.rpc .getrawmempool(param) .catch((e: unknown) => { this.error(`Error getting raw mempool: ${e}`); return null; })) as RawMempool<V> | null; return mempoolInfo || null; } public async getTxOut( txid: string, voutNumber: number, includeMempool?: boolean, ): Promise<TransactionOutputInfo | null> { this.debugMessage(`getTxOut ${txid} ${voutNumber}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetTxOutParams = { n: voutNumber, txid: txid, include_mempool: includeMempool, }; const txOuputInfo: TransactionOutputInfo | null = (await this.rpc .gettxout(param) .catch((e: unknown) => { this.error(`Error getting tx out: ${e}`); return null; })) as TransactionOutputInfo | null; return txOuputInfo || null; } public async getTxOutProof(txids: string[], blockHash?: string): Promise<string | null> { this.debugMessage(`getTxOutProof ${txids} ${blockHash}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: GetTxOutProofParams = { txids: txids, blockhash: blockHash, }; const txOuputProof: string | null = (await this.rpc .gettxoutproof(param) .catch((e: unknown) => { this.error(`Error getting tx out proof: ${e}`); return ''; })) as string | null; return txOuputProof || null; } public async getTxOutSetInfo(): Promise<TransactionOutputSetInfo | null> { this.debugMessage('getTxOutSetInfo'); if (!this.rpc) { throw new Error('RPC not initialized'); } const txOuputSetInfo: TransactionOutputSetInfo | null = (await this.rpc .gettxoutsetinfo() .catch((e: unknown) => { this.error(`Error getting tx out set info: ${e}`); return null; })) as TransactionOutputSetInfo | null; return txOuputSetInfo || null; } public async preciousBlock(blockHash: string): Promise<void> { this.debugMessage(`preciousBlock ${blockHash}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: Blockhash = { blockhash: blockHash, }; await this.rpc.preciousblock(param).catch((e: unknown) => { this.error(`Error precious block: ${e}`); }); } public async pruneBlockChain(height: number): Promise<number | null> { this.debugMessage(`pruneBlockChain ${height}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: Height = { height: height, }; const prunedHeight: number | null = (await this.rpc .pruneblockchain(param) .catch((e: unknown) => { this.error(`Error pruning blockchain: ${e}`); return 0; })) as number | null; return prunedHeight ?? null; } public async saveMempool(): Promise<void> { this.debugMessage('saveMempool'); if (!this.rpc) { throw new Error('RPC not initialized'); } await this.rpc.savemempool().catch((e: unknown) => { this.error(`Error saving mempool: ${e}`); }); } public async verifyChain(checkLevel?: number, nblocks?: number): Promise<boolean | null> { this.debugMessage(`verifyChain ${checkLevel} ${nblocks}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: { checklevel?: number; nblocks?: number } = { checklevel: checkLevel, nblocks: nblocks, }; const checked: boolean | null = (await this.rpc.verifychain(param).catch((e: unknown) => { this.error(`Error verifying chain: ${e}`); return false; })) as boolean | null; return checked ?? null; } public async verifyTxOutProof(proof: string): Promise<string[] | null> { this.debugMessage(`verifyTxOutProof ${proof}`); if (!this.rpc) { throw new Error('RPC not initialized'); } const param: { proof: string } = { proof: proof, }; const proofs: string[] | null = (await this.rpc .verifytxoutproof(param) .catch((e: unknown) => { this.error(`Error verifying tx out proof: ${e}`); return []; })) as string[] | null; return proofs || null; } public async init(rpcInfo: RPCConfig): Promise<void> { if (this.rpc) { throw new Error('RPC already initialized'); } const rpcConfig = this.getRpcConfigFromBlockchainConfig(rpcInfo); this.rpc = new RPCClient(rpcConfig); await this.testRPC(); } public override error(...args: string[]): void { if (this.enableDebug) { super.error(...args); } } private debugMessage(message: string): void { if (this.enableDebug) { this.log(message); } } private purgeCachedData(): void { this.purgeInterval = setInterval(() => { this.blockchainInfo = null; this.currentBlockInfo = null; }, this.cacheClearInterval); } private async testRPC(): Promise<void> { try { const chainInfo = await this.getChainInfo(); if (!chainInfo) { this.error('RPC errored. Please check your configuration.'); process.exit(1); } /*const chain = chainInfo.chain; if (BitcoinChains.MAINNET !== chain && rpcInfo.BITCOIND_NETWORK === 'mainnet') { this.error('Chain is not mainnet. Please check your configuration.'); process.exit(1); } else if (BitcoinChains.TESTNET !== chain && rpcInfo.BITCOIND_NETWORK === 'testnet') { this.error( `Chain is not testnet (currently: ${chain} !== ${BitcoinChains.TESTNET}). Please check your configuration.`, ); process.exit(1); } else if (BitcoinChains.REGTEST !== chain && rpcInfo.BITCOIND_NETWORK === 'regtest') { this.error( `Chain is not testnet (currently: ${chain} !== ${BitcoinChains.TESTNET}). Please check your configuration.`, ); process.exit(1); } else { this.success( `RPC initialized. {Chain: ${rpcInfo.BITCOIND_NETWORK}. Block height: ${chainInfo.blocks}}`, ); }*/ } catch (e: unknown) { const error = e as Error; this.error(`RPC errored. Please check your configuration. ${error.message}`); } } }