mirror of
https://github.com/fullstack-cash/bch-api.git
synced 2026-09-22 09:12:05 -07:00
refactor(blockchain.js): refactoring blockchain.js library [WIP]
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user