From e83aaad1e309928ac3407569020ee2586e69531a Mon Sep 17 00:00:00 2001 From: danielhumgon Date: Sat, 8 Feb 2020 22:31:56 -0400 Subject: [PATCH] refactor(blockchain.js): refactoring blockchain.js library [WIP] --- src/routes/v3/full-node/blockchain2.js | 748 +++++++++++++++++++++++++ 1 file changed, 748 insertions(+) diff --git a/src/routes/v3/full-node/blockchain2.js b/src/routes/v3/full-node/blockchain2.js index a7c103f..a84c70e 100644 --- a/src/routes/v3/full-node/blockchain2.js +++ b/src/routes/v3/full-node/blockchain2.js @@ -34,6 +34,21 @@ class Blockchain { this.router.get("/", this.root) this.router.get("/getBestBlockHash", this.getBestBlockHash) this.router.get("/getBlockchainInfo", this.getBlockchainInfo) + this.router.get("/getBlockCount", this.getBlockCount) + this.router.get("/getBlockHeader/:hash", this.getBlockHeaderSingle) + this.router.post("/getBlockHeader", getBlockHeaderBulk) + this.router.get("/getChainTips", getChainTips) + this.router.get("/getDifficulty", getDifficulty) + this.router.get("/getMempoolEntry/:txid", getMempoolEntrySingle) + this.router.post("/getMempoolEntry", getMempoolEntryBulk) + this.router.get("/getMempoolAncestors/:txid", getMempoolAncestorsSingle) + this.router.get("/getMempoolInfo", getMempoolInfo) + this.router.get("/getRawMempool", getRawMempool) + this.router.get("/getTxOut/:txid/:n", getTxOut) + this.router.get("/getTxOutProof/:txid", getTxOutProofSingle) + this.router.post("/getTxOutProof", getTxOutProofBulk) + this.router.get("/verifyTxOutProof/:proof", verifyTxOutProofSingle) + this.router.post("/verifyTxOutProof", verifyTxOutProofBulk) } root(req, res, next) { @@ -128,6 +143,739 @@ class Blockchain { return this.errorHandler(err, res) } } + + /** + * @api {get} /blockchain/getBlockCount Get Block Count + * @apiName GetBlockCount + * @apiGroup Blockchain + * @apiDescription Returns the number of blocks in the longest blockchain. + * + * @apiExample Example usage: + * curl -X GET "https://mainnet.bchjs.cash/v3/blockchain/getBlockCount" -H "accept: application/json" + * + * @apiSuccess {Number} bestBlockCount 587665 + */ + async getBlockCount(req, res, next) { + try { + // Axios options + const options = this.routeUtils.getAxiosOptions() + options.data.id = "getblockcount" + options.data.method = "getblockcount" + options.data.params = [] + + const response = await this.axios.request(options) + + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getBlockCount().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {get} /blockchain/getBlockHeader/:hash Get single block header + * @apiName GetSingleBlockHeader + * @apiGroup Blockchain + * @apiDescription If verbose is false (default), returns a string that is + * serialized, hex-encoded data for blockheader 'hash'. If verbose is true, + * returns an Object with information about blockheader hash. + * + * @apiExample Example usage: + * curl -X GET "https://mainnet.bchjs.cash/v3/blockchain/getBlockHeader/000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201?verbose=true" -H "accept: application/json" + * + * @apiParam {String} hash block hash + * @apiParam {Boolean} verbose Return verbose data + * + * @apiSuccess {Object} object Object containing data + * @apiSuccess {String} object.hash "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" + * @apiSuccess {Number} object.confirmations 61839 + * @apiSuccess {Number} object.height 500000 + * @apiSuccess {Number} object.version 536870912 + * @apiSuccess {String} object.versionHex "20000000" + * @apiSuccess {String} object.merkleroot "4af279645e1b337e655ae3286fc2ca09f58eb01efa6ab27adedd1e9e6ec19091" + * @apiSuccess {Number} object.time 1509343584 + * @apiSuccess {Number} object.mediantime 1509336533 + * @apiSuccess {Number} object.nonce 3604508752 + * @apiSuccess {String} object.bits "1809b91a" + * @apiSuccess {Number} object.difficulty 113081236211.4533 + * @apiSuccess {String} object.chainwork "0000000000000000000000000000000000000000007ae48aca46e3b449ad9714" + * @apiSuccess {String} object.previousblockhash "0000000000000000043831d6ebb013716f0580287ee5e5687e27d0ed72e6e523" + * @apiSuccess {String} object.nextblockhash "00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3" + */ + async getBlockHeaderSingle(req, res, next) { + try { + let verbose = false + if (req.query.verbose && req.query.verbose.toString() === "true") + verbose = true + + const hash = req.params.hash + if (!hash || hash === "") { + res.status(400) + return res.json({ error: "hash can not be empty" }) + } + + // Axios options + const options = this.routeUtils.getAxiosOptions() + options.data.id = "getblockheader" + options.data.method = "getblockheader" + options.data.params = [hash, verbose] + + const response = await this.axios.request(options) + + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getBlockHeaderSingle().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {post} /blockchain/getBlockHeader Get multiple block headers + * @apiName GetBulkBlockHeader + * @apiGroup Blockchain + * @apiDescription If verbose is false (default), returns a string that is + * serialized, hex-encoded data for blockheader 'hash'. If verbose is true, + * returns an Object with information about blockheader hash. + * + * @apiExample Example usage: + * curl -X POST "https://rest.bitcoin.com/v3/blockchain/getBlockHeader" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"hashes\":[\"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201\",\"00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3\"],\"verbose\":true}" + * + * @apiParam {String} hash block hash + * @apiParam {Boolean} verbose Return verbose data + * + * @apiSuccess {Array} array array containing objects + * @apiSuccess {String} object.hash "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" + * @apiSuccess {Number} object.confirmations 61839 + * @apiSuccess {Number} object.height 500000 + * @apiSuccess {Number} object.version 536870912 + * @apiSuccess {String} object.versionHex "20000000" + * @apiSuccess {String} object.merkleroot "4af279645e1b337e655ae3286fc2ca09f58eb01efa6ab27adedd1e9e6ec19091" + * @apiSuccess {Number} object.time 1509343584 + * @apiSuccess {Number} object.mediantime 1509336533 + * @apiSuccess {Number} object.nonce 3604508752 + * @apiSuccess {String} object.bits "1809b91a" + * @apiSuccess {Number} object.difficulty 113081236211.4533 + * @apiSuccess {String} object.chainwork "0000000000000000000000000000000000000000007ae48aca46e3b449ad9714" + * @apiSuccess {String} object.previousblockhash "0000000000000000043831d6ebb013716f0580287ee5e5687e27d0ed72e6e523" + * @apiSuccess {String} object.nextblockhash "00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3" + */ + async getBlockHeaderBulk(req, res, next) { + try { + const hashes = req.body.hashes + const verbose = req.body.verbose ? req.body.verbose : false + + if (!Array.isArray(hashes)) { + res.status(400) + return res.json({ + error: "hashes needs to be an array. Use GET for single hash." + }) + } + + // Enforce array size rate limits + if (!routeUtils.validateArraySize(req, hashes)) { + res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330 + return res.json({ + error: `Array too large.` + }) + } + + wlogger.debug( + `Executing blockchain/getBlockHeaderBulk with these hashes: `, + hashes + ) + + // Validate each hash in the array. + for (let i = 0; i < hashes.length; i++) { + const hash = hashes[i] + + if (hash.length !== 64) { + res.status(400) + return res.json({ error: `This is not a hash: ${hash}` }) + } + } + + // Axios options + const options = this.routeUtils.getAxiosOptions() + + // Loop through each hash and creates an array of requests to call in parallel + const promises = hashes.map(async hash => { + options.data.id = "getblockheader" + options.data.method = "getblockheader" + options.data.params = [hash, verbose] + + return await this.axios.request(options) + }) + + const axiosResult = await this.axios.all(promises) + + // Extract the data component from the axios response. + const result = axiosResult.map(x => x.data.result) + + res.status(200) + return res.json(result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getBlockHeaderBulk().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {get} /blockchain/getChainTips Get Chain Tips + * @apiName getChainTips + * @apiGroup Blockchain + * @apiDescription Return information about all known tips in the block tree, + * including the main chain as well as orphaned branches. + * + * @apiExample Example usage: + * curl -X GET "https://mainnet.bchjs.cash/v3/blockchain/getChainTips" -H "accept: application/json" + * + */ + async getChainTips(req, res, next) { + try { + // Axios options + const options = this.routeUtils.getAxiosOptions() + + options.data.id = "getchaintips" + options.data.method = "getchaintips" + options.data.params = [] + + const response = await this.axios.request(options) + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getChainTips().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {get} /blockchain/getDifficulty Get difficulty + * @apiName getDifficulty + * @apiGroup Blockchain + * @apiDescription Get the current difficulty value, used to regulate mining + * power on the network. + * + * @apiExample Example usage: + * curl -X GET "https://mainnet.bchjs.cash/v3/blockchain/getDifficulty" -H "accept: application/json" + * + */ + async getDifficulty(req, res, next) { + try { + // Axios options + const options = this.routeUtils.getAxiosOptions() + + options.data.id = "getdifficulty" + options.data.method = "getdifficulty" + options.data.params = [] + + const response = await this.axios.request(options) + + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getDifficulty().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {get} /blockchain/getMempoolEntry/:txid Get single mempool entry + * @apiName getMempoolEntry + * @apiGroup Blockchain + * @apiDescription Returns mempool data for given transaction. TXID must be in + * mempool (unconfirmed) + * + * @apiExample Example usage: + * curl -X GET "https://mainnet.bchjs.cash/v3/blockchain/getMempoolEntry/fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" -H "accept: application/json" + * + */ + async getMempoolEntrySingle(req, res, next) { + try { + // Validate input parameter + const txid = req.params.txid + if (!txid || txid === "") { + res.status(400) + return res.json({ error: "txid can not be empty" }) + } + + // Axios options + const options = this.routeUtils.getAxiosOptions() + + options.data.id = "getmempoolentry" + options.data.method = "getmempoolentry" + options.data.params = [txid] + + const response = await this.axios.request(options) + + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getMempoolEntrySingle().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {post} /blockchain/getMempoolEntry Get bulk mempool entry + * @apiName getMempoolEntryBulk + * @apiGroup Blockchain + * @apiDescription Returns mempool data for multiple transactions + * + * @apiExample Example usage: + * curl -X POST https://mainnet.bchjs.cash/v3/blockchain/getMempoolEntry -H "Content-Type: application/json" -d "{\"txids\":[\"a5f972572ee1753e2fd2457dd61ce5f40fa2f8a30173d417e49feef7542c96a1\",\"5165dc531aad05d1149bb0f0d9b7bda99c73e2f05e314bcfb5b4bb9ca5e1af5e\"]}" + */ + async getMempoolEntryBulk(req, res, next) { + try { + const txids = req.body.txids + + if (!Array.isArray(txids)) { + res.status(400) + return res.json({ + error: "txids needs to be an array. Use GET for single txid." + }) + } + + // Enforce array size rate limits + if (!routeUtils.validateArraySize(req, txids)) { + res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330 + return res.json({ + error: `Array too large.` + }) + } + + wlogger.debug( + `Executing blockchain/getMempoolEntry with these txids: `, + txids + ) + + // Validate each element in the array + for (let i = 0; i < txids.length; i++) { + const txid = txids[i] + + if (txid.length !== 64) { + res.status(400) + return res.json({ error: "This is not a txid" }) + } + } + + // Axios options + const options = this.routeUtils.getAxiosOptions() + + // Loop through each txid and creates an array of requests to call in parallel + const promises = txids.map(async txid => { + options.data.id = "getmempoolentry" + options.data.method = "getmempoolentry" + options.data.params = [txid] + + return await this.axios.request(options) + }) + + const axiosResult = await this.axios.all(promises) + + // Extract the data component from the axios response. + const result = axiosResult.map(x => x.data.result) + + res.status(200) + return res.json(result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getMempoolEntryBulk().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {get} /blockchain/getMempoolAncestors/:txid Get Mempool Ancestors + * @apiName getMempoolAncestors + * @apiGroup Blockchain + * @apiDescription Returns mempool ancestors data for given TXID. It must be in + * mempool (unconfirmed). This call is handy to tell if a UTXO is bumping up + * against the 25 ancestor chain-limit. + * + * @apiExample Example usage: + * curl -X GET "https://mainnet.bchjs.cash/v3/blockchain/getMempoolAncestors/fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" -H "accept: application/json" + * + */ + async getMempoolAncestorsSingle(req, res, next) { + try { + // Validate input parameter + const txid = req.params.txid + if (!txid || txid === "") { + res.status(400) + return res.json({ error: "txid can not be empty" }) + } + + let verbose = req.params.verbose + if (verbose === undefined) verbose = false + + // Axios options + const options = this.routeUtils.getAxiosOptions() + + options.data.id = "getmempoolancestors" + options.data.method = "getmempoolancestors" + options.data.params = [txid, verbose] + + const response = await this.axios.request(requestConfig) + // console.log(`response: ${util.inspect(response)}`) + + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getMempoolAncestorsSingle().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {get} /blockchain/getMempoolInfo Get mempool info + * @apiName getMempoolInfo + * @apiGroup Blockchain + * @apiDescription Returns details on the active state of the TX memory pool. + * + * @apiExample Example usage: + * curl -X GET https://mainnet.bchjs.cash/v3/getMempoolInfo -H "accept: application/json" + * + */ + async getMempoolInfo(req, res, next) { + try { + // Axios options + const options = this.routeUtils.getAxiosOptions() + + options.data.id = "getmempoolinfo" + options.data.method = "getmempoolinfo" + options.data.params = [] + + const response = await this.axios.request(options) + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getMempoolInfo().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {get} /blockchain/getRawMempool Get mempool info + * @apiName getMempoolInfo + * @apiGroup Blockchain + * @apiDescription Returns details on the active state of the TX memory pool. + * + * @apiExample Example usage: + * curl -X GET https://mainnet.bchjs.cash/v3/getMempoolInfo -H "accept: application/json" + * + */ + /** + * @api {get} /blockchain/getRawMempool/?verbose= Get raw mempool + * @apiName getRawMempool + * @apiGroup Blockchain + * @apiDescription Returns all transaction ids in memory pool as a json array + * of string transaction ids. + * + * @apiExample Example usage: + * curl -X GET "https://mainnet.bchjs.cash/v3/getRawMempool/?verbose=true" -H "accept: application/json" + * + * @apiParam {Boolean} verbose Return verbose data + * + */ + async getRawMempool(req, res, next) { + try { + // Axios options + const options = this.routeUtils.getAxiosOptions() + + let verbose = false + if (req.query.verbose && req.query.verbose === "true") verbose = true + + options.data.id = "getrawmempool" + options.data.method = "getrawmempool" + options.data.params = [verbose] + + const response = await this.axios.request(options) + + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getRawMempool().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {get} /blockchain/getTxOut/:txid/:n?mempool= Get Tx Out + * @apiName getTxOut + * @apiGroup Blockchain + * @apiDescription Returns details about an unspent transaction output. + * + * @apiExample Example usage: + * curl -X GET "https://mainnet.bchjs.cash/v3/blockchain/getTxOut/fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33/0?mempool=false" -H "accept: application/json" + * + * @apiParam {String} txid Transaction id (required) + * @apiParam {Number} n Output number (required) + * @apiParam {Boolean} mempool Check mempool or not (optional) + * + */ + // Returns details about an unspent transaction output. + async getTxOut(req, res, next) { + try { + // Validate input parameter + const txid = req.params.txid + if (!txid || txid === "") { + res.status(400) + return res.json({ error: "txid can not be empty" }) + } + + let n = req.params.n + if (n === undefined || n === "") { + res.status(400) + return res.json({ error: "n can not be empty" }) + } + n = parseInt(n) + + let include_mempool = false + if (req.query.include_mempool && req.query.include_mempool === "true") + include_mempool = true + + // Axios options + const options = this.routeUtils.getAxiosOptions() + + options.data.id = "gettxout" + options.data.method = "gettxout" + options.data.params = [txid, n, include_mempool] + + // console.log(`requestConfig: ${JSON.stringify(requestConfig, null, 2)}`) + + const response = await this.axios.request(options) + + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getTxOut().`, err) + + return this.errorHandler(err, res) + } + } + + /** + * @api {get} /blockchain/getTxOutProofSingle/:txid Get Tx Out Proof + * @apiName getTxOutProofSingle + * @apiGroup Blockchain + * @apiDescription Returns a hex-encoded proof that 'txid' was included in a block. + * + * @apiExample Example usage: + * curl -X GET "https://mainnet.bchjs.cash/v3/blockchain/getTxOutProofSingle/fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" -H "accept: application/json" + * + * @apiParam {String} txid Transaction id (required) + * + */ + async getTxOutProofSingle(req, res, next) { + try { + // Validate input parameter + const txid = req.params.txid + if (!txid || txid === "") { + res.status(400) + return res.json({ error: "txid can not be empty" }) + } + + // Axios options + const options = this.routeUtils.getAxiosOptions() + + options.data.id = "gettxoutproof" + options.data.method = "gettxoutproof" + options.data.params = [[txid]] + + const response = await this.axios.request(options) + + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getTxOutProofSingle().`, err) + + return this.errorHandler(err, res) + } + } + + // Returns a hex-encoded proof that 'txid' was included in a block. + async getTxOutProofBulk(req, res, next) { + try { + const txids = req.body.txids + + // Reject if txids is not an array. + if (!Array.isArray(txids)) { + res.status(400) + return res.json({ + error: "txids needs to be an array. Use GET for single txid." + }) + } + + // Enforce array size rate limits + if (!routeUtils.validateArraySize(req, txids)) { + res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330 + return res.json({ + error: `Array too large.` + }) + } + + // Axios options + const options = this.routeUtils.getAxiosOptions() + + // Validate each element in the array. + for (let i = 0; i < txids.length; i++) { + const txid = txids[i] + + if (txid.length !== 64) { + res.status(400) + return res.json({ + error: `Invalid txid. Double check your txid is valid: ${txid}` + }) + } + } + + wlogger.debug( + `Executing blockchain/getTxOutProof with these txids: `, + txids + ) + + // Loop through each txid and creates an array of requests to call in parallel + const promises = txids.map(async txid => { + options.data.id = "gettxoutproof" + options.data.method = "gettxoutproof" + options.data.params = [[txid]] + + return await this.axios.request(options) + }) + + // Wait for all parallel promisses to resolve. + const axiosResult = await this.axios.all(promises) + + // Extract the data component from the axios response. + const result = axiosResult.map(x => x.data.result) + + res.status(200) + return res.json(result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/getTxOutProofBulk().`, err) + + return this.errorHandler(err, res) + } + } + + async verifyTxOutProofSingle(req, res, next) { + try { + // Validate input parameter + const proof = req.params.proof + if (!proof || proof === "") { + res.status(400) + return res.json({ error: "proof can not be empty" }) + } + + // Axios options + const options = this.routeUtils.getAxiosOptions() + + options.data.id = "verifytxoutproof" + options.data.method = "verifytxoutproof" + options.data.params = [req.params.proof] + + const response = await this.axios.request(options) + + return res.json(response.data.result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/verifyTxOutProofSingle().`, err) + + return this.errorHandler(err, res) + } + } + + async verifyTxOutProofBulk(req, res, next) { + try { + const proofs = req.body.proofs + + // Reject if proofs is not an array. + if (!Array.isArray(proofs)) { + res.status(400) + return res.json({ + error: "proofs needs to be an array. Use GET for single proof." + }) + } + + // Enforce array size rate limits + if (!routeUtils.validateArraySize(req, proofs)) { + res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330 + return res.json({ + error: `Array too large.` + }) + } + + // Axios options + const options = this.routeUtils.getAxiosOptions() + + // Validate each element in the array. + for (let i = 0; i < proofs.length; i++) { + const proof = proofs[i] + + if (!proof || proof === "") { + res.status(400) + return res.json({ error: `proof can not be empty: ${proof}` }) + } + } + + wlogger.debug( + `Executing blockchain/verifyTxOutProof with these proofs: `, + proofs + ) + + // Loop through each proof and creates an array of requests to call in parallel + const promises = proofs.map(async proof => { + options.data.id = "verifytxoutproof" + options.data.method = "verifytxoutproof" + options.data.params = [proof] + + return await this.axios.request(options) + }) + + // Wait for all parallel promisses to resolve. + const axiosResult = await this.axios.all(promises) + + // Extract the data component from the axios response. + const result = axiosResult.map(x => x.data.result[0]) + + res.status(200) + return res.json(result) + } catch (err) { + // Write out error to error log. + //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err) + wlogger.error(`Error in blockchain.ts/verifyTxOutProofBulk().`, err) + + return this.errorHandler(err, res) + } + } } module.exports = Blockchain