import { EventEmitter } from "events" ; import * as zmq from "zeromq" ; import { IBitcoindOptions } from "./BitcoindOptions" ; import { jsonrpcRequest } from "./JsonRpcRequest" ; import { ConstantBackoff } from "./policies/ConstantBackoff" ; import { RetryPolicy } from "./policies/RetryPolicy" ; import { BlockChainInfo } from "./types/BlockChainInfo" ; import { Block } from "./types/Block" ; import { BlockHeader } from "./types/BlockHeader" ; import { BlockSummary } from "./types/BlockSummary" ; import { Transaction } from "./types/Transaction" ; import { Utxo } from "./types/Transaction" ; export declare interface IBitcoindClient { on ( event , listener ) : this ; on ( event , listener ) : this ; } /**
 * Bitcoind RPC and Zeromq client
 */ export class BitcoindClient extends EventEmitter { public opts : IBitcoindOptions ; public id : number ; public rawTxSock : zmq . socket ; public rawBlockSock : zmq . socket ; constructor ( opts ) { super ( ) ; this . opts = opts ; this . id = 0 ; } emits public subscribeRawTx ( ) { const sock = ( this . rawTxSock = zmq . socket ( "sub" ) ) ; sock . connect ( this . opts . zmqpubrawtx ) ; sock . subscribe ( "rawtx" ) ; sock . on ( "message" , ( topic , message ) => this . emit ( "rawtx" , message ) ) ; } emits public subscribeRawBlock ( ) { const sock = ( this . rawBlockSock = zmq . socket ( "sub" ) ) ; sock . connect ( this . opts . zmqpubrawblock ) ; sock . subscribe ( "rawblock" ) ; sock . on ( "message" , ( topic , message ) => this . emit ( "rawblock" , message ) ) ; } /**
     * Gets the BlockChaininfo using the `getblockchaininfo` RPC method
     */ public async getBlockchainInfo ( ) { return this . _jsonrpc < BlockChainInfo > ( "getblockchaininfo" ) ; } /**
     * Returns the hash of the best block.
     */ public async getBestBlockHash ( ) { return this . _jsonrpc < string > ( "getbestblockhash" ) ; } param height public async getBlockHash ( height ) { return this . _jsonrpc < string > ( "getblockhash" , [ height ] ) ; } param hash public async getBlockSummary ( hash ) { return this . _jsonrpc < BlockSummary > ( "getblock" , [ hash , 1 ] ) ; } public async getBlock ( hash ) { return this . _jsonrpc < Block > ( "getblock" , [ hash , 2 ] ) ; } param hash public async getRawBlock ( hash ) { const result = await this . _jsonrpc < string > ( "getblock" , [ hash , 0 ] ) ; return Buffer . from ( result , "hex" ) ; } param hash public async getHeader ( hash ) { return await this . _jsonrpc < BlockHeader > ( "getblockheader" , [ hash ] ) ; } param txid public async getTransaction ( txid ) { return this . _jsonrpc < Transaction > ( "getrawtransaction" , [ txid , true ] ) ; } param txid public async getRawTransaction ( txid ) { const result = await this . _jsonrpc < string > ( "getrawtransaction" , [ txid , false ] ) ; return Buffer . from ( result , "hex" ) ; } param txid param n public async getUtxo ( txid , n ) { return await this . _jsonrpc < Utxo > ( "gettxout" , [ txid , n ] ) ; } param blocks param address public async generateToAddress ( blocks , address ) { return await this . _jsonrpc < string [ ] > ( "generatetoaddress" , [ blocks , address ] ) ; } /**
     * This API will block until the bitcoind has been synced.  If the bitcoind
     * has already been synced then it will immediately return.
     *
     * This method works by using the `getblockchaininfo` RPC call and analyzing
     * the mediantime, blocks, and headers values.  The mediantime must be within
     * several hours of the current system time and then we verify that the
     * blocks and headers counts match. If either of this conditions fail we use a
     * backoff strategy and try again.
     */ public async waitForSync ( ) { const constant = new ConstantBackoff ( 15000 ) ; const retry = new RetryPolicy < boolean > ( Number . MAX_SAFE_INTEGER , constant ) ; const now = Math . floor ( Date . now ( ) / 1000 ) ; const threeHours = 180 * 60 ; const mediantimeTarget = now - threeHours ; return await retry . execute ( async ( ) => { const info = await this . getBlockchainInfo ( ) ; if ( info . mediantime >= mediantimeTarget && info . blocks >= info . headers ) { return true ; } else { throw new Error ( "Sync in progress" ) ; } } ) ; } param method param args private _jsonrpc < T > ( method , args ? ) { const fn = ( ) => jsonrpcRequest < T > ( method , args , ++ this . id , this . opts ) ; if ( this . opts . policyMaker ) { return this . opts . policyMaker < T > ( ) . execute ( fn ) ; } else { return fn ( ) ; } } }