Source: daemonService/daemonServiceBlockchainRpcs.js

const serviceHelper = require('../serviceHelper');
const messageHelper = require('../messageHelper');
const daemonServiceUtils = require('./daemonServiceUtils');
const verificationHelper = require('../verificationHelper');

let response = messageHelper.createErrorMessage();

/**
 * To get best block hash.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getBestBlockHash(req, res) {
  const rpccall = 'getBestBlockHash';

  response = await daemonServiceUtils.executeCall(rpccall);

  return res ? res.json(response) : response;
}

/**
 * To get block. Hash height and verbosity required as parameters for RPC call. Verbosity defaults to an integer value of 2.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getBlock(req, res) {
  let { hashheight, verbosity } = req.params;
  hashheight = hashheight || req.query.hashheight;
  hashheight = serviceHelper.ensureString(hashheight);
  verbosity = verbosity || req.query.verbosity || 2; // defaults to json object. CORRECT DAEMON verbosity is number, error says its not boolean
  verbosity = serviceHelper.ensureNumber(verbosity);

  const rpccall = 'getBlock';
  const rpcparameters = [hashheight, verbosity];

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get blockchain info.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getBlockchainInfo(req, res) {
  const rpccall = 'getBlockchainInfo';

  response = await daemonServiceUtils.executeCall(rpccall);

  return res ? res.json(response) : response;
}

/**
 * To get block count.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getBlockCount(req, res) {
  const rpccall = 'getBlockCount';

  response = await daemonServiceUtils.executeCall(rpccall);

  return res ? res.json(response) : response;
}

/**
 * To get block hash. Index required as parameter for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getBlockHash(req, res) {
  let { index } = req.params;
  index = index || req.query.index; // no default value, show help

  const rpccall = 'getBlockHash';
  const rpcparameters = [];
  if (index) {
    index = serviceHelper.ensureNumber(index);
    rpcparameters.push(index);
  }

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get block deltas. Hash required as parameter for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getBlockDeltas(req, res) {
  let { hash } = req.params;
  hash = hash || req.query.hash;

  const rpccall = 'getblockdeltas';
  const rpcparameters = [];
  if (hash) {
    rpcparameters.push(hash);
  }

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get block hashes. High and low values and options object required as parameters for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getBlockHashes(req, res) {
  let {
    high, low, noOrphans, logicalTimes,
  } = req.params;
  high = high || req.query.high;
  low = low || req.query.low;
  noOrphans = noOrphans ?? req.query.noOrphans;
  logicalTimes = logicalTimes ?? req.query.logicalTimes;

  const rpccall = 'getblockhashes';
  const rpcparameters = [];
  if (high) {
    high = serviceHelper.ensureNumber(high);
    rpcparameters.push(high);
  }
  if (low) {
    low = serviceHelper.ensureNumber(low);
    rpcparameters.push(low);
  }
  const options = {};
  if (noOrphans !== undefined && noOrphans !== null) {
    options.noOrphans = serviceHelper.ensureBoolean(noOrphans);
  }
  if (logicalTimes !== undefined && logicalTimes !== null) {
    options.logicalTimes = serviceHelper.ensureBoolean(logicalTimes);
  }
  if (options.noOrphans !== undefined || options.logicalTimes !== undefined) {
    rpcparameters.push(options);
  }

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get block hashes after data is processed. High and low values required as parameters for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 */
async function getBlockHashesPost(req, res) {
  let body = '';
  req.on('data', (data) => {
    body += data;
  });
  req.on('end', async () => {
    const processedBody = serviceHelper.ensureObject(body);
    const { high, low, options } = processedBody;

    const rpccall = 'getblockhashes';
    const rpcparameters = [high, low];

    if (options) {
      rpcparameters.push(options);
    }
    response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

    return res.json(response);
  });
}

/**
 * To get block header. Hash and verbose (defaults to true) required as parameters for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getBlockHeader(req, res) {
  let { hash, verbose } = req.params;
  hash = hash || req.query.hash;
  verbose = verbose ?? req.query.verbose ?? true;

  const rpccall = 'getBlockHeader';
  const rpcparameters = [];
  if (hash) {
    verbose = serviceHelper.ensureBoolean(verbose);
    rpcparameters.push(hash);
    rpcparameters.push(verbose);
  }

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get chain tips.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getChainTips(req, res) {
  const rpccall = 'getChainTips';

  response = await daemonServiceUtils.executeCall(rpccall);

  return res ? res.json(response) : response;
}

/**
 * To get block hash algorithm difficulty.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getDifficulty(req, res) {
  const rpccall = 'getDifficulty';

  response = await daemonServiceUtils.executeCall(rpccall);

  return res ? res.json(response) : response;
}

/**
 * To get mempool (memory pool) info.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getMempoolInfo(req, res) {
  const rpccall = 'getMempoolInfo';

  response = await daemonServiceUtils.executeCall(rpccall);

  return res ? res.json(response) : response;
}

/**
 * To get raw mempool (memory pool) info. Verbose (defaults to true) required as parameter for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getRawMemPool(req, res) {
  let { verbose } = req.params;
  verbose = verbose ?? req.query.verbose ?? false;

  verbose = serviceHelper.ensureBoolean(verbose);

  const rpccall = 'getRawMemPool';
  const rpcparameters = [verbose];

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get transaction output. Transaction ID, number and whether to include mempool (defaults to true) required as parameters for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getTxOut(req, res) {
  let { txid, n, includemempool } = req.params;
  txid = txid || req.query.txid;
  n = n || req.query.n;
  includemempool = includemempool ?? req.query.includemempool ?? true;

  const rpccall = 'getTxOut';
  const rpcparameters = [];
  if (txid && n) {
    includemempool = serviceHelper.ensureBoolean(includemempool);
    n = serviceHelper.ensureNumber(n);
    rpcparameters.push(txid);
    rpcparameters.push(n);
    rpcparameters.push(includemempool);
  }

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get transaction output proof. Array of transaction IDs required as parameter for RPC call. Block hash can also be included as parameter for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getTxOutProof(req, res) {
  let { txids, blockhash } = req.params;
  txids = txids || req.query.txids;
  blockhash = blockhash || req.query.blockhash;
  const txidsarray = txids ? txids.split(',') : undefined;

  const rpccall = 'getTxOutProof';
  const rpcparameters = [];
  if (txids && blockhash) {
    rpcparameters.push(txidsarray);
    rpcparameters.push(blockhash);
  } else if (txids) {
    rpcparameters.push(txidsarray);
  }

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get transaction output set info.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getTxOutSetInfo(req, res) {
  const rpccall = 'getTxOutSetInfo';

  response = await daemonServiceUtils.executeCall(rpccall);

  return res ? res.json(response) : response;
}

/**
 * To verify chain. Check level and number of blocks required as parameters for RPC call. Only accessible by admins.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function verifyChain(req, res) {
  let { checklevel, numblocks } = req.params;
  checklevel = checklevel || req.query.checklevel || 3;
  numblocks = numblocks || req.query.numblocks || 288;
  const authorized = await verificationHelper.verifyPrivilege('admin', req);
  if (authorized !== true) {
    response = messageHelper.errUnauthorizedMessage();
    return res ? res.json(response) : response;
  }
  checklevel = serviceHelper.ensureNumber(checklevel);
  numblocks = serviceHelper.ensureNumber(numblocks);
  const rpccall = 'verifyChain';
  const rpcparameters = [checklevel, numblocks];

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To verify transaction output proof. Proof required as parameter for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function verifyTxOutProof(req, res) {
  let { proof } = req.params;
  proof = proof || req.query.proof;

  const rpccall = 'verifyTxOutProof';
  const rpcparameters = [];
  if (proof) {
    rpcparameters.push(proof);
  }

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get spent info. Transaction ID and index required as parameters for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getSpentInfo(req, res) {
  let { txid, index } = req.params;
  txid = txid || req.query.txid;
  index = index || req.query.index;

  const rpccall = 'getspentinfo';
  const options = {
    txid: serviceHelper.ensureString(txid),
    index: serviceHelper.ensureNumber(index),
  };
  const rpcparameters = [options];

  response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

  return res ? res.json(response) : response;
}

/**
 * To get spent info after data is processed. Transaction ID and index required as parameters for RPC call.
 * @param {object} req Request.
 * @param {object} res Response.
 * @returns {object} Message.
 */
async function getSpentInfoPost(req, res) {
  let body = '';
  req.on('data', (data) => {
    body += data;
  });
  req.on('end', async () => {
    const processedBody = serviceHelper.ensureObject(body);
    const { txid, index } = processedBody;
    const options = {
      txid: serviceHelper.ensureString(txid),
      index: serviceHelper.ensureNumber(index),
    };

    const rpccall = 'getspentinfo';
    const rpcparameters = [options];

    response = await daemonServiceUtils.executeCall(rpccall, rpcparameters);

    return res.json(response);
  });
}

module.exports = {
  getBestBlockHash,
  getBlock,
  getBlockchainInfo,
  getBlockCount,
  getBlockDeltas, // experimental feataure, insight explorer
  getBlockHashes, // experimental feataure, insight explorer
  getBlockHashesPost, // experimental feataure, insight explorer
  getBlockHash,
  getBlockHeader,
  getChainTips,
  getDifficulty,
  getMempoolInfo,
  getRawMemPool,
  getTxOut,
  getTxOutProof,
  getTxOutSetInfo,
  verifyChain,
  verifyTxOutProof,
  getSpentInfo, // experimental feature, insight explorer
  getSpentInfoPost, // experimental feature, insight explorer
};