ArQmA RPC JS

rpcDaemon.js

'use strict'

const http = require('./httpClient')
const { default: PQueue } = require('p-queue')
const rpcHelpers = require('./rpcHelpers')

function parseDaemonResponse (res) {
  if (res.status === 200) {
    var json
    if ('result' in res.data) {
      json = res.data.result
    } else {
      json = res.data
    }
    if (json.status === 'OK') {
      return json
    } else {
      const error = new Error('RPC Error!')
      error.code = json.error.code
      error.message = json.error.message
      throw error
    }
  } else {
    const error = new Error('HTTP Error!')
    error.code = res.status
    error.message = res.data
    throw error
  }
}

/**
 * @module RPCDaemon
 */
/** @typedef {{ RPCDaemon}} */
var rpcDaemon = {}

/**
* Factory that creates a RPCDaemon client object.
* @function module:RPCDaemon.createDaemonClient
* @param {Object} opts
* @param {string} opts.url - complete url with port 'http://127.0.0.1:20000' or 'https://127.0.0.1:20000'.
* @param {string} [opts.username='Mufasa'] - username.
* @param {string} [opts.password='Circle of Life'] - password.
* @return {RPCDaemon} returns a new instance of RPCDaemon.
*/
rpcDaemon.createDaemonClient = function (config) {
  /**
 * @async
 * @param {Object} opts
 * @param {string} opts.url - complete url with port 'http://127.0.0.1:19994' or 'https://127.0.0.1:19994'.
 * @param {string} [opts.username='Mufasa'] - username.
 * @param {string} [opts.password='Circle of Life'] - password.
 * @return {RPCDaemon} returns a new instance of RPCDaemon.
 */
  const queue = new PQueue({ concurrency: 1 })
  const httpClient = http.createHttpClient(config)
  const jsonAddress = config.url + '/json_rpc'
  httpClient.defaults.headers.post['Content-Type'] = 'application/json'
  return {
    /**
    *  Convenience Digest function to reset nc to '00000001' and generate a new cnonce
    */
    resetNonces: function () {
      return httpClient.resetNonces()
    },
    /**
    *  If not false, the server certificate is verified against the list of supplied CAs.
    */
    sslRejectUnauthorized: function (value) {
      httpClient.defaults.httpAgent.options.rejectUnauthorized = value
      httpClient.defaults.httpsAgent.options.rejectUnauthorized = value
      return value
    },
    /**
   * Flush tx ids from transaction pool.
   * @async
   * @param {Object} [opts]
   * @param {string[]} [opts.txids] - list of transactions IDs to flush from pool (all tx ids flushed if empty).
   * @returns {Promise<object>} Promise object.
   * @example <caption><b>Output</b></caption>
   * { status: 'OK' }
   */
    flushTxPool: async function (opts) {
      rpcHelpers.checkOptionalParametersType({ txids: 'ArrayOfHashes' }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'flush_txpool', opts)
    },
    /**
    * Display alternative chains seen by the node.
    * @async
    * @example <caption><b>Output</b></caption>
    * { status: 'OK' }
    */
    getAlternateChains: async function () {
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_alternate_chains')
    },
    /**
    * Get list of banned IPs.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  bans:
    *  [
    *   { host: '192.168.1.50', ip: 838969536, seconds: 30 },
    *   { host: '192.168.1.51', ip: 855746752, seconds: 30 }
    *  ],
    *  status: 'OK'
    * }
    */
    getBans: async function () {
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_bans')
    },
    /**
    * Full block information can be retrieved by either block height or hash.
    * @async
    * @param {Object} opts
    * @param {number} [opts.height] -  The block's height.
    * @param {string} [opts.hash] -  The block's hash.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  blob: '0a0ab294a0e305be9bcd157ff60f9b174217608a5b419c451afa1d9d76c49edf54ac829bf24e
    *         743b62008002a6fc0601ff94fc0601a5a7a3bf4702f0f7be480164ced3d5d28c49dd9baeb5ab2bd3
    *         29910838afd3e26cd85ad49b3e6101311398a1783551ba88c64c00135d0439d982fc4d70f48e1dff
    *         cca8146454e84303210091abcad5e3b8bc208e5361ffeebbb68a35e102a5225f4865e3503cf7e76a
    *         ff92021b000000000000000000000000005602009e000000000000000000000000',
    *  block_header:
    *  {
    *   block_size: 147,
    *   cumulative_difficulty: 16146009479722,
    *   depth: 31535,
    *   difficulty: 109000131,
    *   hash: '5859dbfca776cc006f6bfd00a41363f8ffcc20e6f217c484df0b47ae8cc2458a',
    *   height: 114196,
    *   major_version: 10,
    *   minor_version: 10,
    *   nonce: 2147508795,
    *   num_txes: 0,
    *   orphan_status: false,
    *   pow_hash: '',
    *   prev_hash: 'be9bcd157ff60f9b174217608a5b419c451afa1d9d76c49edf54ac829bf24e74',
    *   reward: 19191616421,
    *   timestamp: 1550322226
    *  },
    *  json: '{\n  "major_version": 10, \n  "minor_version": 10, \n  "timestamp": 15503222
    *  26, \n  "prev_id": "be9bcd157ff60f9b174217608a5b419c451afa1d9d76c49edf54ac829bf2
    *  4e74", \n  "nonce": 2147508795, \n  "miner_tx": {\n    "version": 2, \n    "unlo
    *  ck_time": 114214, \n    "vin": [ {\n        "gen": {\n          "height": 114196
    *  \n        }\n      }\n    ], \n    "vout": [ {\n        "amount": 19191616421, \
    *  n        "target": {\n          "key": "f0f7be480164ced3d5d28c49dd9baeb5ab2bd329
    *  910838afd3e26cd85ad49b3e"\n        }\n      }\n    ], \n    "extra": [ 1, 49, 19
    *  , 152, 161, 120, 53, 81, 186, 136, 198, 76, 0, 19, 93, 4, 57, 217, 130, 252, 77,
    *  112, 244, 142, 29, 255, 204, 168, 20, 100, 84, 232, 67, 3, 33, 0, 145, 171, 202
    *  , 213, 227, 184, 188, 32, 142, 83, 97, 255, 238, 187, 182, 138, 53, 225, 2, 165,
    *  34, 95, 72, 101, 227, 80, 60, 247, 231, 106, 255, 146, 2, 27, 0, 0, 0, 0, 0, 0,
    *  0, 0, 0, 0, 0, 0, 0, 86, 2, 0, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n    ], \n
    *  "rct_signatures": {\n      "type": 0\n    }\n  }, \n  "tx_hashes": [ ]\n}',
    *  miner_tx_hash: '691e09ce198a2953c391a292ed79d7a239ec929740503400a0ab3e3ee8cfad84',
    *  status: 'OK',
    *  untrusted: false
    * }
    */
    getBlock: async function (opts) {
      if ((typeof opts.height === 'undefined') && (typeof opts.hash === 'undefined')) {
        throw new Error('must specify height or hash')
      } else {
        rpcHelpers.checkOptionalParametersType({
          height: 'Integer',
          hash: 'Hash'
        }, opts)
      }
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_block', opts)
    },
    /**
    * Look up how many blocks are in the longest chain known to the node.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  count: 144188,
    *  status: 'OK'
    * }
    */
    getBlockCount: async function () {
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'getblockcount')
    },
    /**
    * Look up a block's hash by its height.
    * @async
    * @param {Object} opts
    * @param {number} opts.height - block height.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * 6115a8e9902af15d31d14c698621d54e9bb594b0da053591ec5d1ceb537960ea
    */
    getBlockHash: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ height: 'Integer' }, opts)
      const res = await httpClient.post(jsonAddress, `{"jsonrpc":"2.0","id":"0","method":"on_get_block_hash","params":${JSON.stringify([opts.height])}}`)
      if (res.status === 200) {
        if ('result' in res.data) {
          return res.data.result
        } else {
          const error = new Error('RPC Error!')
          error.code = res.data.error.code
          error.message = res.data.error.message
          throw error
        }
      } else {
        const error = new Error('HTTP Error!')
        error.code = res.status
        error.message = res.data
        throw error
      }
    },
    /**
    * Block header information can be retrieved using hash.
    * @async
    * @param {Object} opts
    * @param {string} opts.hash - The block's sha256 hash.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  block_header:
    *  {
    *   block_size: 147,
    *   cumulative_difficulty: 16146009479722,
    *   depth: 30823,
    *   difficulty: 109000131,
    *   hash: '5859dbfca776cc006f6bfd00a41363f8ffcc20e6f217c484df0b47ae8cc2458a',
    *   height: 114196,
    *   major_version: 10,
    *   minor_version: 10,
    *   nonce: 2147508795,
    *   num_txes: 0,
    *   orphan_status: false,
    *   pow_hash: '',
    *   prev_hash: 'be9bcd157ff60f9b174217608a5b419c451afa1d9d76c49edf54ac829bf24e74',
    *   reward: 19191616421,
    *   timestamp: 1550322226
    *  },
    *  status: 'OK',
    *  untrusted: false
    * }
    */
    getBlockHeaderByHash: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ hash: 'Hash' }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_block_header_by_hash', opts)
    },
    /**
    * Block header information can be retrieved using height.
    * @async
    * @param {Object} opts
    * @param {number} opts.height - The block's height.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  block_header:
    *  {
    *   block_size: 147,
    *   cumulative_difficulty: 16146009479722,
    *   depth: 30823,
    *   difficulty: 109000131,
    *   hash: '5859dbfca776cc006f6bfd00a41363f8ffcc20e6f217c484df0b47ae8cc2458a',
    *   height: 114196,
    *   major_version: 10,
    *   minor_version: 10,
    *   nonce: 2147508795,
    *   num_txes: 0,
    *   orphan_status: false,
    *   pow_hash: '',
    *   prev_hash: 'be9bcd157ff60f9b174217608a5b419c451afa1d9d76c49edf54ac829bf24e74',
    *   reward: 19191616421,
    *   timestamp: 1550322226
    *  },
    *  status: 'OK',
    *  untrusted: false
    * }
    */
    getBlockHeaderByHeight: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ height: 'Integer' }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_block_header_by_height', opts)
    },
    /**
    * Similar to get_block_header_by_height above, but for a range of blocks.
    * This method includes a starting block height and an ending block height as parameters.
    * @async
    * @param {Object} opts
    * @param {number} opts.start_height - The starting block's height.
    * @param {number} opts.end_height - The ending block's height.
    * @returns {Promise<object>} Promise object
    * @example <caption><b>Output</b></caption>
    * {
    *  headers:
    *  [
    *   {
    *    block_size: 147,
    *    cumulative_difficulty: 16146009479722,
    *    depth: 30831,
    *    difficulty: 109000131,
    *    hash: '5859dbfca776cc006f6bfd00a41363f8ffcc20e6f217c484df0b47ae8cc2458a',
    *    height: 114196,
    *    major_version: 10,
    *    minor_version: 10,
    *    nonce: 2147508795,
    *    num_txes: 0,
    *    orphan_status: false,
    *    pow_hash: '',
    *    prev_hash: 'be9bcd157ff60f9b174217608a5b419c451afa1d9d76c49edf54ac829bf24e74',
    *    reward: 19191616421,
    *    timestamp: 1550322226
    *   },
    *   {
    *    block_size: 147,
    *    cumulative_difficulty: 16146120479856,
    *    depth: 30830,
    *    difficulty: 111000134,
    *    hash: 'c27c128325bb3f47d76816789995d376268ee25f3cdcfb714580e34fe5cc8e08',
    *    height: 114197,
    *    major_version: 10,
    *    minor_version: 10,
    *    nonce: 541065496,
    *    num_txes: 0,
    *    orphan_status: false,
    *    pow_hash: '',
    *    prev_hash: '5859dbfca776cc006f6bfd00a41363f8ffcc20e6f217c484df0b47ae8cc2458a',
    *    reward: 19191607270,
    *    timestamp: 1550322551
    *   }
    *  ],
    *  status: 'OK',
    *  untrusted: false
    * }
    */
    getBlockHeadersRange: async function (opts) {
      rpcHelpers.checkMandatoryParameters({
        start_height: 'Integer',
        end_height: 'Integer'
      }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_block_headers_range', opts)
    },
    /**
    * Return a range of blocks containing the block header and its attached transactions.
    * The first transaction in block is the coinbase transaction.
    * This method includes a starting block height and an ending block height as parameters.
    * @async
    * @param {Object} opts
    * @param {number} opts.start_height - The starting block's height.
    * @param {number} opts.end_height - The ending block's height.
    * @returns {Promise<object>} Promise object
    * @example <caption><b>Output</b></caption>
    * { blocks:
    *  [
    *   { block_header: [Object], txs: [Array] },
    *   { block_header: [Object], txs: [Array] }
    *  ],
    *  status: 'OK',
    *  untrusted: false
    * }
    */
    getBlocksRange: async function (opts) {
      rpcHelpers.checkMandatoryParameters({
        start_height: 'Integer',
        end_height: 'Integer'
      }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_blocks_range', opts)
    },
    /**
    * Get a block template on which mining a new block.
    * @async
    * @param {Object} opts
    * @param {string} opts.wallet_address - Address of wallet to receive coinbase transactions if block is successfully mined.
    * @param {number} opts.reserve_size - Reserve size.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  blockhashing_blob: '0b0bdc83ffe405686cd8e06fea333582a7d521c6899a00266f107e9212ebe7b7626258893c9a
    *                     9000000000cc172232b1465580877b898f8f6021ad264705fb44d4ce4116576c951865dc6e02',
    *  blocktemplate_blob: '0b0bdc83ffe405686cd8e06fea333582a7d521c6899a00266f107e9212ebe7b7626258893c9a
    *                      900000000002b3e70801ffa1e70801919ef5bc46027fecb474827691e150863765eeb11c7fda
    *                      e88e9cf413468b3f46a6fd1416174f2101958d80e5dd64b962d539a18e2fab89cd6abf1ddd2d
    *                      f4b6c2b890c1fad31acd310001eae8de4b74bf117c059ba9b68c9e81a2465997319dd5805a90
    *                      dfae8290b33ab9',
    *  difficulty: 58700182,
    *  expected_reward: 18918231825,
    *  height: 144289,
    *  prev_hash: '686cd8e06fea333582a7d521c6899a00266f107e9212ebe7b7626258893c9a90',
    *  reserved_offset: 127,
    *  status: 'OK',
    *  untrusted: false
    * }
    */
    getBlockTemplate: async function (opts) {
      rpcHelpers.checkMandatoryParameters({
        wallet_address: 'Address',
        reserve_size: 'Integer'
      }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'getblocktemplate', opts)
    },
    /**
    * Get the coinbase amount and the fees ammount for n last blocks starting at particular height.
    * @async
    * @param {Object} opts
    * @param {number} opts.height -  unsigned int; Block height from which getting the amounts.
    * @param {number} opts.count -  unsigned int; number of blocks to include in the sum
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  emission_amount: 7502006245466748,
    *  fee_amount: 0,
    *  status: 'OK'
    * }
    */
    getCoinbaseTxSum: async function (opts) {
      rpcHelpers.checkMandatoryParameters({
        height: 'Integer',
        count: 'Integer'
      }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_coinbase_tx_sum', opts)
    },
    /**
    * Retrieve information about incoming and outgoing connections to your node.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  connections:
    *  [
    *   {
    *    address: '192.154.226.212:19993',
    *    avg_download: 1,
    *    avg_upload: 0,
    *    connection_id: 'cb8f0270c5b740fa9eb7aa1aedddb5cb',
    *    current_download: 2,
    *    current_upload: 0,
    *    height: 145745,
    *    host: '192.154.226.212',
    *    incoming: false,
    *    ip: '192.154.226.212',
    *    live_time: 20,
    *    local_ip: false,
    *    localhost: false,
    *    peer_id: 'c7f323892fb18784',
    *    port: '19993',
    *    pruning_seed: 0,
    *    recv_count: 22852,
    *    recv_idle_time: 13,
    *    send_count: 568,
    *    send_idle_time: 13,
    *    state: 'normal',
    *    support_flags: 1
    *   }, ...
    *  ]
    * }
    */
    getConnections: async function () {
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_connections')
    },
    /**
    * Gives an estimation on fees per kB.
    * @async
    * @param {Object} [opts]
    * @param {number} [opts.grace_blocks] - unsigned int.
    * @example <caption><b>Output</b></caption>
    * { fee: 7560, status: 'OK', untrusted: false }
    */
    getFeeEstimate: async function (opts) {
      rpcHelpers.checkOptionalParametersType({ grace_blocks: 'Integer' }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_fee_estimate', opts)
    },
    /**
    * Look up information regarding hard fork voting and readiness.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  earliest_height: 131650,
    *  enabled: true,
    *  state: 2,
    *  status: 'OK',
    *  threshold: 0,
    *  untrusted: false,
    *  version: 11,
    *  votes: 10080,
    *  voting: 11,
    *  window: 10080
    * }
    */
    getHardForkInfo: async function () {
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'hard_fork_info')
    },
    /**
    * Retrieve general information about the state of your node and the network.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  alt_blocks_count: 0,
    *  block_size_limit: 600000,
    *  block_size_median: 147,
    *  bootstrap_daemon_address: '',
    *  cumulative_difficulty: 20431347989483,
    *  database_size: 0,
    *  difficulty: 75600102,
    *  free_space: 243485646848,
    *  grey_peerlist_size: 62,
    *  height: 145746,
    *  height_without_bootstrap: 145746,
    *  incoming_connections_count: 7,
    *  mainnet: true,
    *  nettype: 'mainnet',
    *  offline: false,
    *  outgoing_connections_count: 8,
    *  rpc_connections_count: 2,
    *  stagenet: false,
    *  start_time: 1554144733,
    *  status: 'OK',
    *  target: 120,
    *  target_height: 145732,
    *  testnet: false,
    *  top_block_hash: '9df96b39bb2ca8953cbf8f2fffc8f9896a74f430cbe29dc0ad356986ef93024c',
    *  tx_count: 179362,
    *  tx_pool_size: 10,
    *  untrusted: false,
    *  was_bootstrap_ever_used: false,
    *  white_peerlist_size: 38
    * }
    */
    getInfo: async function () {
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_info')
    },
    /**
    * Block header information for the most recent block is easily retrieved with this method.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  block_header:
    *  {
    *    block_size: 147,
    *    cumulative_difficulty: 20379479802883,
    *    depth: 0,
    *    difficulty: 61400097,
    *    hash: 'c99c2f9a53e4bab5d08f9820ee555d62059e0e9bf799fbe07a6137aac607f4e8',
    *    height: 145009,
    *    major_version: 11,
    *    minor_version: 11,
    *    nonce: 3441194797,
    *    num_txes: 0,
    *    orphan_status: false,
    *    pow_hash: '',
    *    prev_hash: '53d6437ac32fc49e0ee8b24f63046c6e1e6e0491f6d1b6797b025b66ad1b4a40',
    *    reward: 18911700042,
    *    timestamp: 1554058920 },
    *    status: 'OK',
    *    untrusted: false
    *  }
    *  count: 144188,
    *  status: 'OK'
    * }
    */
    getLastBlockHeader: async function () {
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_last_block_header')
    },
    /**
    * Get Ouput Distribution.
    * @async
    * @param {Object} opts
    * @param {number[]} opts.amounts -  list of amounts to look for.
    * @param {boolean} [opts.cumulative] - (default is false) States if the result should be cumulative (true or false).
    * @param {number} [opts.from_height] - (default is 0) - unsigned int.
    * @param {number} [opts.to_height] - (default is 0) - unsigned int.
    * @example <caption><b>Output</b></caption>
    * { status: 'OK', untrusted: false }
    */
    getOutputDistribution: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ amounts: 'ArrayOfIntegers' }, opts)

      rpcHelpers.checkOptionalParametersType({
        cumulative: 'Boolean',
        from_height: 'Integer',
        to_height: 'Integer'
      }, opts)

      opts.binary = false

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_output_distribution', opts)
    },
    /**
    * Get a histogram of output amounts.
    * @async
    * @param {Object} [opts]
    * @param {number[]} [opts.amounts] -  list of unsigned int.
    * @param {number} [opts.min_count] -  unsigned int.
    * @param {number} [opts.max_count] -  unsigned int.
    * @param {boolean} [unlocked] -  boolean.
    * @param {number} [recent_cutoff] -  unsigned int.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  histogram:
    *  [
    *   {
    *    amount: 10000000,
    *    recent_instances: 0,
    *    total_instances: 1481,
    *    unlocked_instances: 0
    *   }
    *  ],
    *  status: 'OK',
    *  untrusted: false
    * }
    */
    getOutputHistogram: async function (opts) {
      rpcHelpers.checkOptionalParametersType({
        amounts: 'ArrayOfIntegers',
        min_count: 'Integer',
        max_count: 'Integer',
        unlocked: 'Boolean',
        recent_cutoff: 'Integer'
      }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_output_histogram', opts)
    },
    /**
    * Give the node current version.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { status: 'OK', untrusted: false, version: 131077 }
    */
    getVersion: async function () {
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'get_version')
    },
    /**
    * Get the known blocks hashes which are not on the main chain.
    * @async
    * @returns {Promise<object>} Promise object.
    */
    otherGetAltBlocksHashes: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'get_alt_blocks_hashes')
    },
    /**
    * Get the node's current height.
    * @async
    * @example <caption><b>Output</b></caption>
    * { height: 149045, status: 'OK', untrusted: false }
    */
    otherGetHeight: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'get_height')
    },
    /**
    * Get daemon bandwidth limits.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  "limit_down": 8192,
    *  "limit_up": 128,
    *  "status": "OK",
    *  "untrusted": false
    * }
    */
    otherGetLimit: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'get_limit')
    },
    /**
    * Get the known peers list.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  gray_list:
    *  [
    *   { host: '135790251',
    *     id: 17703185689409910000,
    *     ip: 135790251,
    *     last_seen: 1551473999,
    *     port: 19993,
    *     pruning_seed: 0 }, ...
    *  ]
    *  status: 'OK',
    *  white_list:
    *  [
    *   { host: '35263064',
    *     id: 3764929947382960000,
    *     ip: 35263064,
    *     last_seen: 1554553579,
    *     port: 19993,
    *     pruning_seed: 0 }, ...
    *  ]
    * }
    */
    otherGetPeerList: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'get_peer_list')
    },
    /**
    * Show information about valid transactions seen by the node but not yet mined into a block, as well as spent key image information for the txpool in the node's memory.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  spent_key_images:
    *  [
    *   { id_hash: '12f6051aea57b598e7aefe436545ab55f449b11d392fffd76e33eef53ad9b962',
    *     txs_hashes: [Array] },
     *    ...
     * ],
     * status: 'OK',
     * transactions:
     * [
     *  { blob_size: 4384,
     *    do_not_relay: false,
     *    double_spend_seen: false,
     *    fee: 37750,
     *    id_hash:
     *    '3fa2745621696d4e87d997e32409469cc3d734fda186f37878b8db2972a99a41',
     *    kept_by_block: false,
     *    last_failed_height: 0,
     *    last_failed_id_hash:
     *    '0000000000000000000000000000000000000000000000000000000000000000',
     *    last_relayed_time: 1554589504,
     *    max_used_block_height: 149373,
     *    max_used_block_id_hash:
     *    '3ed0b7d1c294def73dda48c6b3f43d724525fcbc08672782ec3a1e4c5a1b2f01',
     *    receive_time: 1554589504,
     *    relayed: true,
     *    tx_blob: ... ,
     *    tx_json: ... ,
     *   }
     * ],
     * untrusted: false
     * }
    */
    otherGetTransactionPool: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'get_transaction_pool')
    },
    /**
    * Get the transaction pool statistics.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  pool_stats:
    *  {
    *   bytes_max: 2785,
    *   bytes_med: 2785,
    *   bytes_min: 2785,
    *   bytes_total: 2785,
    *   fee_total: 22650,
    *   histo_98pc: 0,
    *   num_10m: 0,
    *   num_double_spends: 0,
    *   num_failing: 0,
    *   num_not_relayed: 0,
    *   oldest: 1554589922,
    *   txs_total: 1
    *  },
    *  status: 'OK',
    *  untrusted: false
    * }
    */
    otherGetTransactionPoolStats: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'get_transaction_pool_stats')
    },
    /**
    * Full block information can be retrieved by either block height or hash.
    * @async
    * @param {Object} opts
    * @param {string[]} opts.tx_hashes -  List of transaction hashes to look up.
    * @param {boolean} [opts.decode_as_json] - (false by default). If set true, the returned transaction information will be decoded rather than binary.
    * @param {boolean} [opts.prune] - (false by default).
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  status: 'OK',
    *  txs:
    *  [
    *   {
    *    as_hex: '02000202 ... 0f',
    *    as_json: '',
    *    block_height: 140732,
    *    block_timestamp: 1553537372,
    *    double_spend_seen: false,
    *    in_pool: false,
    *    output_indices: [Array],
    *    prunable_as_hex: '',
    *    prunable_hash:
    *    '79f87397ef265f27b32a659e0f3f73496527e2cb97228ee4a82f31ec972bd65b',
    *    pruned_as_hex: '',
    *    tx_hash: 'a43c51e3a216bb702e6be2746c02a366c8e3a05b08b50da5ada8e9481418e350'
    *   }
    *  ],
    *  txs_as_hex: [ '02000202 ... 0f' ],
    *  untrusted: false
    * }
    */
    otherGetTransactions: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ txs_hashes: 'ArrayOfHashes' }, opts)

      rpcHelpers.checkOptionalParametersType({
        decode_as_json: 'Boolean',
        prune: 'Boolean'
      }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'get_transactions', opts)
    },
    /**
    * Check if outputs have been spent using the key image associated with the output.
    * @async
    * @param {Object} opts
    * @param {string[]} opts.key_images -  list of block blobs which have been mined.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { spent_status: [ 1 ], status: 'OK', untrusted: false }
    */
    otherIsKeyImageSpent: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ key_images: 'ArrayOfHashes' }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'is_key_image_spent', opts)
    },
    /**
    * Limit number of incoming peers.
    * @async
    * @param {Object} opts
    * @param {number} opts.in_peers - Max number of incoming peers.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { status: 'OK' }
    */
    otherInPeers: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ in_peers: 'Integer' }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'in_peers', opts)
    },
    /**
    * Limit number of outgoing peers.
    * @async
    * @param {Object} opts
    * @param {number} opts.out_peers - Max number of outgoing peers.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { status: 'OK' }
    */
    otherOutPeers: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ out_peers: 'Integer' }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'out_peers', opts)
    },
    /**
    * Get the mining status of the daemon.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  active: true,
    *  address: 'ar4bfzwH4726kamvTg2wRNLkw16MR6DbbZMyuShYgKs58SknoAF8q7PBQ1XXAsGgH9feTWKKmYZNjaWphc7Wce1u33iKe2cL9',
    *  is_background_mining_enabled: true,
    *  speed: 2,
    *  status: 'OK',
    *  threads_count: 1
    * }
    */
    otherMiningStatus: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'mining_status')
    },
    /**
    * Save the blockchain. The blockchain does not need saving and is always saved when modified, however it does a sync to flush the filesystem cache onto the disk for safety purposes against Operating System or Hardware crashes.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { status: 'OK' }
    */
    otherSaveBc: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'save_bc')
    },
    /**
    * Broadcast a raw transaction to the network.
    * @async
    * @param {Object} opts
    * @param {string} opts.tx_as_hex -  Full transaction information as hexidecimal string.
    * @param {boolean} [opts.do_not_relay] - (false by default). Stop relaying transaction to other nodes.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  double_spend: false,
    *  fee_too_low: false,
    *  invalid_input: false,
    *  invalid_output: false,
    *  low_mixin: false,
    *  not_rct: false,
    *  not_relayed: true,
    *  overspend: false,
    *  reason: 'Not relayed',
    *  status: 'OK',
    *  too_big: false,
    *  untrusted: false
    * }
    */
    otherSendRawTransaction: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ tx_as_hex: 'String' }, opts)

      rpcHelpers.checkOptionalParametersType({ do_not_relay: 'Boolean' }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'send_raw_transaction', opts)
    },
    /**
    * Set daemon bandwidth limits.
    * @async
    * @param {Object} opts
    * @param {number} [opts.limit_down] - Download limit in kBytes per second (-1 reset to default, 0 don't change the current limit).
    * @param {number} [opts.limit_up] - Upload limit in kBytes per second (-1 reset to default, 0 don't change the current limit).
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  limit_down: 16384,
    *  limit_up: 4096,
    *  status: 'OK'
    * }
    */
    otherSetLimit: async function (opts) {
      rpcHelpers.checkOptionalParametersType({
        limit_down: 'Integer',
        limit_up: 'Integer'
      }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'set_limit', opts)
    },
    /**
    * Set the daemon log categories.<br>
    * Categories are represented as a comma separated list of <Category\>:<level\> (similarly to syslog standard <Facility\>:<Severity-level\>), where:
    * <p><ul>
    * Category is one of the following:
    *   <li>\* - All facilities</li>
    *   <li>default</li>
    *   <li>net</li>
    *   <li>net.http</li>
    *   <li>net.p2p</li>
    *   <li>logging</li>
    *   <li>net.throttle</li>
    *   <li>blockchain.db</li>
    *   <li>blockchain.db.lmdb</li>
    *   <li>bcutil</li>
    *   <li>checkpoints</li>
    *   <li>net.dns</li>
    *   <li>net.dl</li>
    *   <li>i18n</li>
    *   <li>perf</li>
    *   <li>stacktrace</li>
    *   <li>updates</li>
    *   <li>account</li>
    *   <li>cn</li>
    *   <li>difficulty</li>
    *   <li>hardfork</li>
    *   <li>miner</li>
    *   <li>blockchain</li>
    *   <li>txpool</li>
    *   <li>cn.block_queue</li>
    *   <li>net.cn</li>
    *   <li>daemon</li>
    *   <li>debugtools.deserialize</li>
    *   <li>debugtools.objectsizes</li>
    *   <li>device.ledger</li>
    *   <li>wallet.gen_multisig</li>
    *   <li>multisig</li>
    *   <li>bulletproofs</li>
    *   <li>ringct</li>
    *   <li>daemon.rpc</li>
    *   <li>wallet.simplewallet</li>
    *   <li>WalletAPI</li>
    *   <li>wallet.ringdb</li>
    *   <li>wallet.wallet2</li>
    *   <li>wallet.rpc</li>
    *   <li>tests.core
    *   </ul>
    * <ul>
    * Level is one of the following:
    *   <li>FATAL - higher level</li>
    *   <li>ERROR</li>
    *   <li>WARNING</li>
    *   <li>INFO</li>
    *   <li>DEBUG</li>
    *   <li>TRACE - lower level A level automatically includes higher level.</li>
    *   </ul></p>
    *   By default, categories are set to *:WARNING,net:FATAL,net.p2p:FATAL,net.cn:FATAL,global:INFO,verify:FATAL,stacktrace:INFO,logging:INFO,msgwriter:INFO.<br>
    *   Setting the categories to "" prevent any logs to be outputed.
    * @async
    * @param {Object} opts
    * @param {string} [opts.categories] - Daemon log categories to enable.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  "categories": "*:INFO",
    *  "status": "OK"
    * }
    */
    otherSetLogCategories: async function (opts) {
      rpcHelpers.checkOptionalParametersType({ categories: 'String' }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'set_log_categories', opts)
    },
    /**
    * Set the log hash rate display mode.
    * @async
    * @param {Object} opts
    * @param {boolean} opts.visible - States if hash rate logs should be visible (true) or hidden (false)
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output while mining</b></caption>
    * { "status": "OK" }
    * @example <caption><b>Output while NOT mining. You need to catch it with promise.</b></caption>
    * Error: NOT MINING
    * at _request.then (C:\myDev\arqma-rpc-js\src\rpcDaemon.js:1418:27)
    * at process._tickCallback (internal/process/next_tick.js:68:7)
    */
    otherSetLogHashrate: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ visible: 'Boolean' }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'set_log_hash_rate', opts)
    },
    /**
    * Set the daemon log level. By default, log level is set to 0.
    * @async
    * @param {Object} opts
    * @param {number} opts.level - Daemon log level to set from 0 (less verbose) to 4 (most verbose).
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { "status": "OK" }
    */
    otherSetLogLevel: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ level: 'Integer' }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'set_log_level', opts)
    },
    /**
    * Start mining on the daemon.
    * @async
    * @param {Object} opts
    * @param {boolean} opts.do_background_mining - States if the mining should run in background (true) or foreground (false).
    * @param {boolean} opts.ignore_battery - States if batery state (on laptop) should be ignored (true) or not (false).
    * @param {string} opts.miner_address - Account address to mine to.
    * @param {number} opts.threads_count - Number of mining thread to run.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { status: 'OK' }
    */
    otherStartMining: async function (opts) {
      rpcHelpers.checkMandatoryParameters({
        do_background_mining: 'Boolean',
        ignore_battery: 'Boolean',
        miner_address: 'Address',
        threads_count: 'Integer'
      }, opts)

      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'start_mining', opts)
    },
    /**
    * Send a command to the daemon to safely disconnect and shut down.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { "status": "OK" }
    */
    otherStopDaemon: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'stop_daemon')
    },
    /**
    * Stop mining on the daemon.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { status: 'OK' }
    */
    otherStopMining: async function () {
      return rpcHelpers.makeOtherQuery(httpClient, config.url, queue, parseDaemonResponse, 'stop_mining')
    },
    /**
    * Relay a list of transaction IDs.
    * @async
    * @param {Object} opts
    * @param {string[]} opts.txids - list of transaction IDs to relay.
    * @returns {Promise} Promise object.
    * @example <caption><b>Output</b></caption>
    * { status: 'OK' }
    */
    relayTx: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ txids: 'ArrayOfHashes' }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'relay_tx', opts)
    },
    /**
    * Ban another node by IP.
    * @async
    * @param {Object} opts
    * @param {Array} opts.bans
    * @param {string} [opts.bans[].host] - Host to ban.
    * @param {number} [opts.bans[].ip] - IP address to ban, in Int format.
    * @param {boolean} opts.bans[].ban - Set true to ban.
    * @param {number} opts.bans[].seconds - Number of seconds to ban node.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * { status: 'OK' }
    */
    setBans: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ bans: 'ArrayOfBans' }, opts)
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'set_bans', opts)
    },
    /**
    * Look up a block's hash by its height.
    * @async
    * @param {Object} opts
    * @param {string[]} opts.blobs -  list of block blobs which have been mined.
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output with error message when the block is not accepted. You need to catch it with promise.</b></caption>
    * { Error: Block not accepted
    *   at _request.then (C:\myDev\arqma-rpc-js\src\rpcDaemon.js:761:25)
    *   at process._tickCallback (internal/process/next_tick.js:68:7) code: -7 }
    */
    submitBlock: async function (opts) {
      rpcHelpers.checkMandatoryParameters({ blobs: 'ArrayOfStrings' }, opts)

      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'submit_block', opts.blobs)
    },
    /**
    * Get synchronisation informations.
    * @async
    * @returns {Promise<object>} Promise object.
    * @example <caption><b>Output</b></caption>
    * {
    *  height: 149027,
    *  next_needed_pruning_seed: 0,
    *  overview: '[]',
    *  peers:
    *  [
    *   { info: [Object] },
    *   { info: [Object] },
    *   ... ,
    *   { info: [Object] }
    *  ],
    *  status: 'OK',
    *  target_height: 149009
    * }
    */
    syncInfo: async function () {
      return rpcHelpers.makeJsonQuery(httpClient, jsonAddress, queue, parseDaemonResponse, 'sync_info')
    }
  }
}

exports = module.exports = rpcDaemon