- View the original rest.bitcoin.com API documentation
- on developer.bitcoin.com.
-
-
+
+ bch-api is a
+ REST API, allowing modern applications to interact with the Bitcoin Cash (BCH)
+ blockchain. New to the BCH blockchain? Start by reading more about
+ building full stack applications on BCH.
+
+
+ A REST API can work with any programming language, but bch-api is intended
+ to be paired with the
+ npm bch-js
+ JavaScript library.
+ Here is example code
+ for common BCH use cases.
+
+ slp-cli-wallet
+ is another npm library that provides common wallet functionality, to get
+ your apps up and running as quickly as possible.
+
+
+ While you'll be able to run through the examples without one, you should
+ sign-up for a free API key
+ in order to unlock higher rate limits.
+
+ This web server is based on
+ rest.bitcoin.com. Most endpoints
+ are common between the two projects. You may want to plan with their
+ interactive UI to explore the API endpoints.
+
+
+
+ View the original rest.bitcoin.com API documentation on
+ developer.bitcoin.com.
+
+
+
+
+
diff --git a/src/routes/v2/address.js b/src/routes/v2/address.js
deleted file mode 100644
index 0ae8d9e..0000000
--- a/src/routes/v2/address.js
+++ /dev/null
@@ -1,805 +0,0 @@
-/*
- Address route
-*/
-
-"use strict"
-
-const express = require("express")
-const requestUtils = require("./services/requestUtils")
-const axios = require("axios")
-const logger = require("./logging.js")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
-
-//const router = express.Router()
-const router = express.Router()
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BITBOXJS = require("@chris.troutner/bch-js")
-const BITBOX = new BITBOXJS()
-
-// Use the default (and max) page size of 1000
-// https://github.com/bitpay/insight-api#notes-on-upgrading-from-v03
-const PAGE_SIZE = 1000
-
-// Connect the route endpoints to their handler functions.
-router.get("/", root)
-router.get("/details/:address", detailsSingle)
-router.post("/details", detailsBulk)
-router.post("/utxo", utxoBulk)
-router.get("/utxo/:address", utxoSingle)
-router.post("/unconfirmed", unconfirmedBulk)
-router.get("/unconfirmed/:address", unconfirmedSingle)
-router.get("/transactions/:address", transactionsSingle)
-router.post("/transactions", transactionsBulk)
-router.get("/fromXPub/:xpub", fromXPubSingle)
-
-// Root API endpoint. Simply acknowledges that it exists.
-function root(req, res, next) {
- return res.json({ status: "address" })
-}
-
-// Query the Insight API for details on a single BCH address.
-// Returns a Promise.
-async function detailsFromInsight(thisAddress, currentPage = 0) {
- try {
- let addr
- if (
- process.env.BITCOINCOM_BASEURL === "https://bch-insight.bitpay.com/api/"
- )
- addr = BITBOX.Address.toCashAddress(thisAddress)
- else addr = BITBOX.Address.toLegacyAddress(thisAddress)
-
- let path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}`
-
- // Set from and to params based on currentPage and pageSize
- // https://github.com/bitpay/insight-api/blob/master/README.md#notes-on-upgrading-from-v02
- const from = currentPage * PAGE_SIZE
- const to = from + PAGE_SIZE
- path = `${path}?from=${from}&to=${to}`
-
- // Query the Insight server.
- const axiosResponse = await axios.get(path)
- const retData = axiosResponse.data
- //console.log(`retData: ${util.inspect(retData)}`)
-
- // Calculate pagesTotal from response
- const pagesTotal = Math.ceil(retData.txApperances / PAGE_SIZE)
-
- // Append different address formats to the return data.
- retData.legacyAddress = BITBOX.Address.toLegacyAddress(retData.addrStr)
- retData.cashAddress = BITBOX.Address.toCashAddress(retData.addrStr)
- delete retData.addrStr
-
- // Append pagination information to the return data.
- retData.currentPage = currentPage
- retData.pagesTotal = pagesTotal
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// POST handler for bulk queries on address details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"]}' -H "Content-Type: application/json" http://localhost:3000/v2/address/details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"], "from": 1, "to": 5}' -H "Content-Type: application/json" http://localhost:3000/v2/address/details
-async function detailsBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- logger.debug(`Executing address/details with these addresses: `, addresses)
- wlogger.debug(`Executing address/details with these addresses: `, addresses)
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- BITBOX.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- detailsFromInsight(address, currentPage)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- //logger.error(`Error in detailsBulk(): `, err)
- wlogger.error(`Error in address.ts/detailsBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler for single address details
-async function detailsSingle(req, res, next) {
- try {
- const address = req.params.address
- const currentPage = req.query.page ? parseInt(req.query.page, 10) : 0
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(`Executing address/detailsSingle with this address: `, address)
- wlogger.debug(
- `Executing address/detailsSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await detailsFromInsight(address, currentPage)
-
- // Return the retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in address.ts/detailsSingle: `, err)
- wlogger.error(`Error in address.ts/detailsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve UTXO data from the Insight API
-async function utxoFromInsight(thisAddress) {
- try {
- let addr
- if (
- process.env.BITCOINCOM_BASEURL === "https://bch-insight.bitpay.com/api/"
- )
- addr = BITBOX.Address.toCashAddress(thisAddress)
- else addr = BITBOX.Address.toLegacyAddress(thisAddress)
-
- const path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}/utxo`
-
- // Query the Insight server.
- const response = await axios.get(path)
-
- // Append different address formats to the return data.
- const retData = {
- utxos: Array,
- legacyAddress: String,
- cashAddress: String,
- scriptPubKey: String
- }
- if (response.data.length && response.data[0].scriptPubKey) {
- const spk = response.data[0].scriptPubKey
- retData.scriptPubKey = spk
- }
- retData.legacyAddress = BITBOX.Address.toLegacyAddress(thisAddress)
- retData.cashAddress = BITBOX.Address.toCashAddress(thisAddress)
- retData.utxos = response.data.map(utxo => {
- delete utxo.address
- delete utxo.scriptPubKey
- return utxo
- })
- //console.log(`utxoFromInsight retData: ${util.inspect(retData)}`)
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// Retrieve UTXO information for an address.
-async function utxoBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- BITBOX.Address.toLegacyAddress(thisAddress)
- } catch (er) {
- //if (er.message.includes("Unsupported address format"))
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- logger.debug(`Executing address/utxoBulk with these addresses: `, addresses)
- wlogger.debug(
- `Executing address/utxoBulk with these addresses: `,
- addresses
- )
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- utxoFromInsight(address)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/utxoBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler for single address details
-async function utxoSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(`Executing address/utxoSingle with this address: `, address)
- wlogger.debug(`Executing address/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await utxoFromInsight(address)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/utxoSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve any unconfirmed TX information for a given address.
-async function unconfirmedBulk(req, res, next) {
- try {
- const addresses = req.body.addresses
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- logger.debug(`Executing address/utxo with these addresses: `, addresses)
- wlogger.debug(`Executing address/utxo with these addresses: `, addresses)
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- BITBOX.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Collect an array of promises.
- const promises = addresses.map(address => utxoFromInsight(address))
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(promises)
-
- // Loop through each result
- const finalResult = result.map(elem => {
- //console.log(`elem: ${util.inspect(elem)}`)
-
- // Filter out confirmed transactions.
- const unconfirmedUtxos = elem.utxos.filter(
- utxo => utxo.confirmations === 0
- )
-
- elem.utxos = unconfirmedUtxos
-
- return elem
- })
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(finalResult)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/unconfirmedBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function unconfirmedSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(`Executing address/utxoSingle with this address: `, address)
- wlogger.debug(`Executing address/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await utxoFromInsight(address)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Loop through each returned UTXO.
- const unconfirmedUTXOs = []
- for (let j = 0; j < retData.utxos.length; j++) {
- const thisUtxo = retData.utxos[j]
-
- // Only interested in UTXOs with no confirmations.
- if (thisUtxo.confirmations === 0) unconfirmedUTXOs.push(thisUtxo)
- }
-
- retData.utxos = unconfirmedUTXOs
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/unconfirmedSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve transaction data from the Insight API
-async function transactionsFromInsight(thisAddress, currentPage = 0) {
- try {
- const path = `${process.env.BITCOINCOM_BASEURL}txs/?address=${thisAddress}&pageNum=${currentPage}`
-
- // Query the Insight server.
- const response = await axios.get(path)
-
- // Append different address formats to the return data.
- const retData = response.data
- retData.legacyAddress = BITBOX.Address.toLegacyAddress(thisAddress)
- retData.cashAddress = BITBOX.Address.toCashAddress(thisAddress)
- retData.currentPage = currentPage
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// Get an array of TX information for a given address.
-async function transactionsBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- logger.debug(`Executing address/utxo with these addresses: `, addresses)
- wlogger.debug(`Executing address/utxo with these addresses: `, addresses)
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- BITBOX.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loop through each address and collect an array of promises.
- addresses = addresses.map(async (address, index) =>
- transactionsFromInsight(address, currentPage)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/transactionsBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function transactionsSingle(req, res, next) {
- try {
- const address = req.params.address
- const currentPage = req.query.page ? parseInt(req.query.page, 10) : 0
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(
- `Executing address/transactionsSingle with this address: `,
- address
- )
- wlogger.debug(
- `Executing address/transactionsSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await transactionsFromInsight(address, currentPage)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/transactionsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function fromXPubSingle(req, res, next) {
- try {
- const xpub = req.params.xpub
- const hdPath = req.query.hdPath ? req.query.hdPath : "0"
-
- if (!xpub || xpub === "") {
- res.status(400)
- return res.json({ error: "xpub can not be empty" })
- }
-
- // Reject if xpub is an array.
- if (Array.isArray(xpub)) {
- res.status(400)
- return res.json({
- error: "xpub can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(`Executing address/fromXPub with this xpub: `, xpub)
- wlogger.debug(`Executing address/fromXPub with this xpub: `, xpub)
-
- const cashAddr = BITBOX.Address.fromXPub(xpub, hdPath)
- const legacyAddr = BITBOX.Address.toLegacyAddress(cashAddr)
- res.status(200)
- return res.json({
- cashAddress: cashAddr,
- legacyAddress: legacyAddr
- })
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/fromXPubSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- detailsBulk,
- detailsSingle,
- utxoBulk,
- utxoSingle,
- unconfirmedBulk,
- unconfirmedSingle,
- transactionsBulk,
- transactionsSingle,
- fromXPubSingle
- }
-}
diff --git a/src/routes/v2/block.js b/src/routes/v2/block.js
deleted file mode 100644
index 500687f..0000000
--- a/src/routes/v2/block.js
+++ /dev/null
@@ -1,280 +0,0 @@
-"use strict"
-
-const express = require("express")
-const requestUtils = require("./services/requestUtils")
-const axios = require("axios")
-const bitbox = require("./services/bitbox")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-const routeUtils = require("./route-utils")
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 3 }
-
-const router = express.Router()
-//const BitboxHTTP = bitbox.getInstance()
-
-router.get("/", root)
-router.get("/detailsByHash/:hash", detailsByHashSingle)
-router.post("/detailsByHash", detailsByHashBulk)
-router.get("/detailsByHeight/:height", detailsByHeightSingle)
-router.post("/detailsByHeight", detailsByHeightBulk)
-
-function root(req, res, next) {
- return res.json({ status: "block" })
-}
-
-// Call the insight server to get block details based on the hash.
-async function detailsByHashSingle(req, res, next) {
- try {
- const hash = req.params.hash
-
- // Reject if hash is empty
- if (!hash || hash === "") {
- res.status(400)
- return res.json({ error: "hash must not be empty" })
- }
-
- const response = await axios.get(
- `${process.env.BITCOINCOM_BASEURL}block/${hash}`
- )
- //console.log(`response.data: ${JSON.stringify(response.data,null,2)}`)
-
- const parsed = response.data
- return res.json(parsed)
- } catch (error) {
- //console.log(`error object: ${util.inspect(error)}`)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHashSingle().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-
-async function detailsByHashBulk(req, res, next) {
- try {
- const hashes = req.body.hashes
-
- // Reject if hashes is not an array.
- if (!Array.isArray(hashes)) {
- res.status(400)
- return res.json({
- error: "hashes needs to be an array. Use GET for single address."
- })
- }
-
- // 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.`
- })
- }
-
- // Validate each hash in the array.
- for (let i = 0; i < hashes.length; i++) {
- const thisHash = hashes[i]
-
- if (thisHash.length !== 64) {
- res.status(400)
- return res.json({
- error: `Invalid hash. Double check your hash is valid: ${thisHash}`
- })
- }
- }
-
- // Loop through each hash and creates an array of promises
- const axiosPromises = hashes.map(async hash =>
- axios.get(`${process.env.BITCOINCOM_BASEURL}block/${hash}`)
- )
-
- // Wait for all parallel promises to return.
- const axiosResult = await axios.all(axiosPromises)
-
- // Extract the data component from the axios response.
- const result = axiosResult.map(x => x.data)
- //console.log(`result: ${util.inspect(result)}`)
-
- res.status(200)
- return res.json(result)
- } catch (error) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHashBulk().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-
-// Call the Full Node to get block hash based on height, then call the Insight
-// server to get details from that hash.
-async function detailsByHeightSingle(req, res, next) {
- try {
- const height = req.params.height
-
- // Reject if id is empty
- if (!height || height === "") {
- res.status(400)
- return res.json({ error: "height must not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockhash"
- requestConfig.data.method = "getblockhash"
- requestConfig.data.params = [parseInt(height)]
-
- const response = await BitboxHTTP(requestConfig)
-
- const hash = response.data.result
- //console.log(`response.data: ${util.inspect(response.data)}`)
-
- // Call detailsByHashSingle now that the hash has been retrieved.
- req.params.hash = hash
- return detailsByHashSingle(req, res, next)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in control/getInfo: `, error)
- wlogger.error(`Error in block.ts/detailsByHeightSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function detailsByHeightBulk(req, res, next) {
- try {
- const heights = req.body.heights
-
- // Reject if heights is not an array.
- if (!Array.isArray(heights)) {
- res.status(400)
- return res.json({
- error: "heights needs to be an array. Use GET for single height."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, heights)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- logger.debug(`Executing detailsByHeight with these heights: `, heights)
-
- // Validate each element in the address array.
- for (let i = 0; i < heights.length; i++) {
- const thisHeight = heights[i]
-
- // Reject if id is empty
- if (!thisHeight || thisHeight === "") {
- res.status(400)
- return res.json({ error: "height must not be empty" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each height and creates an array of requests to call in parallel
- const promises = heights.map(async height => {
- requestConfig.data.id = "getblockhash"
- requestConfig.data.method = "getblockhash"
- requestConfig.data.params = [parseInt(height)]
-
- const response = await BitboxHTTP(requestConfig)
-
- const hash = response.data.result
-
- const axiosResult = await axios.get(
- `${process.env.BITCOINCOM_BASEURL}block/${hash}`
- )
-
- return axiosResult.data
- })
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(promises)
-
- res.status(200)
- return res.json(result)
- } catch (error) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHeightBulk().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- detailsByHashSingle,
- detailsByHashBulk,
- detailsByHeightSingle,
- detailsByHeightBulk
- }
-}
diff --git a/src/routes/v2/blockchain.js b/src/routes/v2/blockchain.js
deleted file mode 100644
index 65d772d..0000000
--- a/src/routes/v2/blockchain.js
+++ /dev/null
@@ -1,890 +0,0 @@
-/*
- TODO
- - Add blockhash functionality back into getTxOutProof
-*/
-
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-// Define routes.
-router.get("/", root)
-router.get("/getBestBlockHash", getBestBlockHash)
-// Dev Note: getBlock/:hash ommited because its the same as block/detailsByHash
-//router.get("/getBlock/:hash", getBlock)
-router.get("/getBlockchainInfo", getBlockchainInfo)
-router.get("/getBlockCount", getBlockCount)
-router.get("/getBlockHeader/:hash", getBlockHeaderSingle)
-router.post("/getBlockHeader", getBlockHeaderBulk)
-
-router.get("/getChainTips", getChainTips)
-router.get("/getDifficulty", getDifficulty)
-router.get("/getMempoolEntry/:txid", getMempoolEntrySingle)
-router.post("/getMempoolEntry", getMempoolEntryBulk)
-router.get("/getMempoolInfo", getMempoolInfo)
-router.get("/getRawMempool", getRawMempool)
-router.get("/getTxOut/:txid/:n", getTxOut)
-router.get("/getTxOutProof/:txid", getTxOutProofSingle)
-router.post("/getTxOutProof", getTxOutProofBulk)
-router.get("/verifyTxOutProof/:proof", verifyTxOutProofSingle)
-router.post("/verifyTxOutProof", verifyTxOutProofBulk)
-
-function root(req, res, next) {
- return res.json({ status: "blockchain" })
-}
-
-// Returns the hash of the best (tip) block in the longest block chain.
-async function getBestBlockHash(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getbestblockhash"
- requestConfig.data.method = "getbestblockhash"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBestBlockHash().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getBlockchainInfo(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockchaininfo"
- requestConfig.data.method = "getblockchaininfo"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBlockchainInfo().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getBlockCount(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockcount"
- requestConfig.data.method = "getblockcount"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBlockCount().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function 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" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockheader"
- requestConfig.data.method = "getblockheader"
- requestConfig.data.params = [hash, verbose]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBlockHeaderSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function 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.`
- })
- }
-
- logger.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}` })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each hash and creates an array of requests to call in parallel
- const promises = hashes.map(async hash => {
- requestConfig.data.id = "getblockheader"
- requestConfig.data.method = "getblockheader"
- requestConfig.data.params = [hash, verbose]
-
- return await BitboxHTTP(requestConfig)
- })
-
- const axiosResult = await 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) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getBlockHeaderBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getChainTips(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getchaintips"
- requestConfig.data.method = "getchaintips"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getChainTips().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Get the current difficulty value, used to regulate mining power on the network.
-async function getDifficulty(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getdifficulty"
- requestConfig.data.method = "getdifficulty"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getDifficulty().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns mempool data for given transaction. TXID must be in mempool (unconfirmed)
-async function 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" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getmempoolentry"
- requestConfig.data.method = "getmempoolentry"
- requestConfig.data.params = [txid]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getMempoolEntrySingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function 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.`
- })
- }
-
- logger.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" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each txid and creates an array of requests to call in parallel
- const promises = txids.map(async txid => {
- requestConfig.data.id = "getmempoolentry"
- requestConfig.data.method = "getmempoolentry"
- requestConfig.data.params = [txid]
-
- return await BitboxHTTP(requestConfig)
- })
-
- const axiosResult = await 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) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getMempoolEntryBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getMempoolInfo(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getmempoolinfo"
- requestConfig.data.method = "getmempoolinfo"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getMempoolInfo().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getRawMempool(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- let verbose = false
- if (req.query.verbose && req.query.verbose === "true") verbose = true
-
- requestConfig.data.id = "getrawmempool"
- requestConfig.data.method = "getrawmempool"
- requestConfig.data.params = [verbose]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getRawMempool().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns details about an unspent transaction output.
-async function 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
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "gettxout"
- requestConfig.data.method = "gettxout"
- requestConfig.data.params = [txid, n, include_mempool]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getTxOut().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns a hex-encoded proof that 'txid' was included in a block.
-async function 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" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "gettxoutproof"
- requestConfig.data.method = "gettxoutproof"
- requestConfig.data.params = [[txid]]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getTxOutProofSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns a hex-encoded proof that 'txid' was included in a block.
-async function 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.`
- })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // 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}`
- })
- }
- }
-
- logger.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 => {
- requestConfig.data.id = "gettxoutproof"
- requestConfig.data.method = "gettxoutproof"
- requestConfig.data.params = [[txid]]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel promisses to resolve.
- const axiosResult = await 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) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/getTxOutProofBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-/*
-//
-// router.get('/preciousBlock/:hash', async (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"preciousblock",
-// method: "preciousblock",
-// params: [
-// req.params.hash
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(JSON.stringify(response.data.result));
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.post('/pruneBlockchain/:height', async (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"pruneblockchain",
-// method: "pruneblockchain",
-// params: [
-// req.params.height
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/verifyChain', async (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"verifychain",
-// method: "verifychain"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-*/
-
-async function 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" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "verifytxoutproof"
- requestConfig.data.method = "verifytxoutproof"
- requestConfig.data.params = [req.params.proof]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/verifyTxOutProofSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function 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.`
- })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // 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}` })
- }
- }
-
- logger.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 => {
- requestConfig.data.id = "verifytxoutproof"
- requestConfig.data.method = "verifytxoutproof"
- requestConfig.data.params = [proof]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel promisses to resolve.
- const axiosResult = await 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) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in blockchain.ts/verifyTxOutProofBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- getBestBlockHash,
- //getBlock,
- getBlockchainInfo,
- getBlockCount,
- getBlockHeaderSingle,
- getBlockHeaderBulk,
- getChainTips,
- getDifficulty,
- getMempoolInfo,
- getRawMempool,
- getMempoolEntrySingle,
- getMempoolEntryBulk,
- getTxOut,
- getTxOutProofSingle,
- getTxOutProofBulk,
- verifyTxOutProofSingle,
- verifyTxOutProofBulk
- }
-}
diff --git a/src/routes/v2/generating.js b/src/routes/v2/generating.js
deleted file mode 100644
index ec0c601..0000000
--- a/src/routes/v2/generating.js
+++ /dev/null
@@ -1,51 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-//const axios = require("axios");
-
-//const BITBOXCli = require("bitbox-sdk/lib/bitbox-sdk").default;
-//const BITBOX = new BITBOXCli();
-
-//const BitboxHTTP = axios.create({
-// baseURL: process.env.RPC_BASEURL,
-//});
-//const username = process.env.RPC_USERNAME;
-//const password = process.env.RPC_PASSWORD;
-
-router.get("/", (req, res, next) => {
- res.json({ status: "generating" })
-})
-//
-// router.post('/generateToAddress/:nblocks/:address', (req, res, next) => {
-// let maxtries = 1000000;
-// if(req.query.maxtries) {
-// maxtries = parseInt(req.query.maxtries);
-// }
-//
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"generatetoaddress",
-// method: "generatetoaddress",
-// params: [
-// req.params.nblocks,
-// req.params.address,
-// maxtries
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-
-module.exports = router
diff --git a/src/routes/v2/health-check.js b/src/routes/v2/health-check.js
deleted file mode 100644
index 8c05030..0000000
--- a/src/routes/v2/health-check.js
+++ /dev/null
@@ -1,11 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-
-/* GET home page. */
-router.get("/", (req, res, next) => {
- res.json({ status: "winning v2" })
-})
-
-module.exports = router
diff --git a/src/routes/v2/index.js b/src/routes/v2/index.js
deleted file mode 100644
index 33c175f..0000000
--- a/src/routes/v2/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-
-/* GET home page. */
-router.get("/", (req, res, next) => {
- res.render("swagger-v2")
-})
-
-router.get("/v2", (req, res, next) => {
- res.render("swagger-v2")
-})
-
-module.exports = router
diff --git a/src/routes/v2/logging.js b/src/routes/v2/logging.js
deleted file mode 100644
index 07fd9be..0000000
--- a/src/routes/v2/logging.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- A utility library for setting up greylog2 logging.
-*/
-
-"use strict"
-
-// This will be uncommented and correct once we have our logging server functioning.
-/*
-var graylog2 = require("graylog2");
-var logger = new graylog2.graylog({
- servers: [
- { 'host': '127.0.0.1', port: 12201 },
- { 'host': '127.0.0.2', port: 12201 }
- ],
- hostname: 'server.name', // the name of this host
- // (optional, default: os.hostname())
- facility: 'Node.js', // the facility for these log messages
- // (optional, default: "Node.js")
- bufferSize: 1350 // max UDP packet size, should never exceed the
- // MTU of your system (optional, default: 1400)
-});
-
-logger.on('error', function (error) {
- console.error('Error while trying to write to graylog2:', error);
-});
-*/
-
-// This is just a placeholder function that will be replaced once we get the
-// greylog server working.
-function log(msg, obj) {
- //console.log(msg, obj)
-}
-
-// This is just a placeholder function that will be replaced once we get the
-// greylog server working.
-function error(msg, obj) {
- if (!obj) console.error(msg)
- else console.error(msg, obj)
-}
-
-// This is just a placeholder function that will be replaced once we get the
-// greylog server working.
-function debug(msg, obj) {
- //console.log(msg, obj)
-}
-
-module.exports = {
- log,
- error,
- debug
-}
diff --git a/src/routes/v2/mining.js b/src/routes/v2/mining.js
deleted file mode 100644
index 243b75a..0000000
--- a/src/routes/v2/mining.js
+++ /dev/null
@@ -1,170 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
-}
-
-router.get("/", root)
-router.get("/getMiningInfo", getMiningInfo)
-router.get("/getNetworkHashps", getNetworkHashPS)
-
-function root(req, res, next) {
- return res.json({ status: "mining" })
-}
-
-//
-// router.get('/getBlockTemplate/:templateRequest', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getblocktemplate",
-// method: "getblocktemplate",
-// params: [
-// req.params.templateRequest
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-
-async function getMiningInfo(req, res, next) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getmininginfo"
- requestConfig.data.method = "getmininginfo"
- requestConfig.data.params = []
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in mining.ts/getMiningInfo().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function getNetworkHashPS(req, res, next) {
- try {
- let nblocks = 120 // Default
- let height = -1 // Default
- if (req.query.nblocks) nblocks = parseInt(req.query.nblocks)
- if (req.query.height) height = parseInt(req.query.height)
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getnetworkhashps"
- requestConfig.data.method = "getnetworkhashps"
- requestConfig.data.params = [nblocks, height]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in mining.ts/getNetworkHashPS().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-//
-// router.post('/submitBlock/:hex', (req, res, next) => {
-// let parameters = '';
-// if(req.query.parameters && req.query.parameters !== '') {
-// parameters = true;
-// }
-//
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"submitblock",
-// method: "submitblock",
-// params: [
-// req.params.hex,
-// parameters
-// ]
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-
-module.exports = {
- router,
- testableComponents: {
- root,
- getMiningInfo,
- getNetworkHashPS
- }
-}
diff --git a/src/routes/v2/rawtransactions.js b/src/routes/v2/rawtransactions.js
deleted file mode 100644
index 99104c7..0000000
--- a/src/routes/v2/rawtransactions.js
+++ /dev/null
@@ -1,609 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
-}
-
-router.get("/", root)
-router.get("/decodeRawTransaction/:hex", decodeRawTransactionSingle)
-router.post("/decodeRawTransaction", decodeRawTransactionBulk)
-router.get("/decodeScript/:hex", decodeScriptSingle)
-router.post("/decodeScript", decodeScriptBulk)
-router.post("/getRawTransaction", getRawTransactionBulk)
-router.get("/getRawTransaction/:txid", getRawTransactionSingle)
-router.post("/sendRawTransaction", sendRawTransactionBulk)
-router.get("/sendRawTransaction/:hex", sendRawTransactionSingle)
-
-function root(req, res, next) {
- return res.json({ status: "rawtransactions" })
-}
-
-// Decode transaction hex into a JSON object.
-// GET
-async function decodeRawTransactionSingle(req, res, next) {
- try {
- const hex = req.params.hex
-
- // Throw an error if hex is empty.
- if (!hex || hex === "") {
- res.status(400)
- return res.json({ error: "hex can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "decoderawtransaction"
- requestConfig.data.method = "decoderawtransaction"
- requestConfig.data.params = [hex]
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(
- `Error in rawtransactions.ts/decodeRawTransactionSingle().`,
- err
- )
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function decodeRawTransactionBulk(req, res, next) {
- try {
- const hexes = req.body.hexes
-
- if (!Array.isArray(hexes)) {
- res.status(400)
- return res.json({ error: "hexes must be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, hexes)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- const results = []
-
- // Validate each element in the address array.
- for (let i = 0; i < hexes.length; i++) {
- const thisHex = hexes[i]
-
- // Reject if id is empty
- if (!thisHex || thisHex === "") {
- res.status(400)
- return res.json({ error: "Encountered empty hex" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each height and creates an array of requests to call in parallel
- const promises = hexes.map(async hex => {
- requestConfig.data.id = "decoderawtransaction"
- requestConfig.data.method = "decoderawtransaction"
- requestConfig.data.params = [hex]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel Insight requests to return.
- const axiosResult = await axios.all(promises)
-
- // Retrieve the data part of the result.
- const result = axiosResult.map(x => x.data.result)
-
- res.status(200)
- return res.json(result)
-
- /*
- // Loop through each hex and creates an array of requests to call in parallel
- hexes = hexes.map(async (hex: any) => {
- if (!hex || hex === "") {
- res.status(400)
- return res.json({ error: "Encountered empty hex" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "decoderawtransaction"
- requestConfig.data.method = "decoderawtransaction"
- requestConfig.data.params = [hex]
-
- return await BitboxHTTP(requestConfig)
- })
-
- const result: Array = []
- return axios.all(hexes).then(
- axios.spread((...args) => {
- args.forEach((arg: any) => {
- if (arg) {
- result.push(arg.data.result)
- }
- })
- res.status(200)
- return res.json(result)
- })
- )
-*/
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/getRawTransaction: `, err)
- wlogger.error(
- `Error in rawtransactions.ts/decodeRawTransactionBulk().`,
- err
- )
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Decode a raw transaction from hex to assembly.
-// GET single
-async function decodeScriptSingle(req, res, next) {
- try {
- const hex = req.params.hex
-
- // Throw an error if hex is empty.
- if (!hex || hex === "") {
- res.status(400)
- return res.json({ error: "hex can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "decodescript"
- requestConfig.data.method = "decodescript"
- requestConfig.data.params = [hex]
-
- const response = await BitboxHTTP(requestConfig)
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeScript: `, err)
- wlogger.error(`Error in rawtransactions.ts/decodeScriptSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Decode a raw transaction from hex to assembly.
-// POST bulk
-async function decodeScriptBulk(req, res, next) {
- try {
- const hexes = req.body.hexes
-
- // Validation
- if (!Array.isArray(hexes)) {
- res.status(400)
- return res.json({ error: "hexes must be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, hexes)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each hex in the array
- for (let i = 0; i < hexes.length; i++) {
- const hex = hexes[i]
-
- // Throw an error if hex is empty.
- if (!hex || hex === "") {
- res.status(400)
- return res.json({ error: "Encountered empty hex" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each hex and create an array of promises
- const promises = hexes.map(async hex => {
- requestConfig.data.id = "decodescript"
- requestConfig.data.method = "decodescript"
- requestConfig.data.params = [hex]
-
- const response = await BitboxHTTP(requestConfig)
- return response
- })
-
- // Wait for all parallel promises to return.
- const resolved = await Promise.all(promises)
-
- // Retrieve the data from each resolved promise.
- const result = resolved.map(x => x.data.result)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeScript: `, err)
- wlogger.error(`Error in rawtransactions.ts/decodeScriptBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve raw transactions details from the full node.
-async function getRawTransactionsFromNode(txid, verbose) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getrawtransaction"
- requestConfig.data.method = "getrawtransaction"
- requestConfig.data.params = [txid, verbose]
-
- const response = await BitboxHTTP(requestConfig)
-
- return response.data.result
- } catch (err) {
- wlogger.error(`Error in rawtransactions.ts/getRawTransactionsFromNode().`)
- throw err
- }
-}
-
-// Get a JSON object breakdown of transaction details.
-// POST
-async function getRawTransactionBulk(req, res, next) {
- try {
- let verbose = 0
- if (req.body.verbose) verbose = 1
-
- const txids = req.body.txids
- if (!Array.isArray(txids)) {
- res.status(400)
- return res.json({ error: "txids must be an array" })
- }
-
- // 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.`
- })
- }
-
- // stub response object
- const returnResponse = {
- status: 100,
- json: {
- error: ""
- }
- }
-
- // Validate each txid in the array.
- for (let i = 0; i < txids.length; i++) {
- const txid = txids[i]
-
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: `Encountered empty TXID` })
- }
-
- if (txid.length !== 64) {
- res.status(400)
- return res.json({
- error: `parameter 1 must be of length 64 (not ${txid.length})`
- })
- }
- }
-
- // Loop through each txid and create an array of promises
- const promises = txids.map(async txid =>
- getRawTransactionsFromNode(txid, verbose)
- )
-
- // Wait for all parallel promises to return.
- const axiosResult = await axios.all(promises)
-
- res.status(200)
- return res.json(axiosResult)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/getRawTransaction: `, err)
- wlogger.error(`Error in rawtransactions.ts/getRawTransactionBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Get a JSON object breakdown of transaction details.
-// GET
-async function getRawTransactionSingle(req, res, next) {
- try {
- let verbose = 0
- if (req.query.verbose === "true") verbose = 1
-
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- const data = await getRawTransactionsFromNode(txid, verbose)
-
- return res.json(data)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/getRawTransaction: `, err)
- wlogger.error(`Error in rawtransactions.ts/getRawTransactionSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Transmit a raw transaction to the BCH network.
-async function sendRawTransactionBulk(req, res, next) {
- try {
- // Validation
- const hexes = req.body.hexes
-
- // Reject if input is not an array
- if (!Array.isArray(hexes)) {
- res.status(400)
- return res.json({ error: "hex must be an array" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, hexes)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element
- for (let i = 0; i < hexes.length; i++) {
- const hex = hexes[i]
-
- if (hex === "") {
- res.status(400)
- return res.json({
- error: `Encountered empty hex`
- })
- }
- }
-
- // Dev Note CT 1/31/2019:
- // Sending the 'sendrawtrnasaction' RPC call to a full node in parallel will
- // not work. Testing showed that the full node will return the same TXID for
- // different TX hexes. I believe this is by design, to prevent double spends.
- // In parallel, we are essentially asking the node to broadcast a new TX before
- // it's finished broadcast the previous one. Serial execution is required.
-
- // How to send TX hexes in parallel the WRONG WAY:
- /*
- // Collect an array of promises.
- const promises = hexes.map(async (hex: any) => {
- requestConfig.data.id = "sendrawtransaction"
- requestConfig.data.method = "sendrawtransaction"
- requestConfig.data.params = [hex]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel Insight requests to return.
- const axiosResult: Array = await axios.all(promises)
-
- // Retrieve the data part of the result.
- const result = axiosResult.map(x => x.data.result)
- */
-
- // Sending them serially.
- const result = []
- for (let i = 0; i < hexes.length; i++) {
- const hex = hexes[i]
-
- requestConfig.data.id = "sendrawtransaction"
- requestConfig.data.method = "sendrawtransaction"
- requestConfig.data.params = [hex]
-
- const rpcResult = await BitboxHTTP(requestConfig)
-
- result.push(rpcResult.data.result)
- }
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in rawtransactions.ts/sendRawTransactionBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Transmit a raw transaction to the BCH network.
-async function sendRawTransactionSingle(req, res, next) {
- try {
- const hex = req.params.hex // URL parameter
-
- // Reject if input is not an array or a string
- if (typeof hex !== "string") {
- res.status(400)
- return res.json({ error: "hex must be a string" })
- }
-
- // Validation
- if (hex === "") {
- res.status(400)
- return res.json({
- error: `Encountered empty hex`
- })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // RPC call
- requestConfig.data.id = "sendrawtransaction"
- requestConfig.data.method = "sendrawtransaction"
- requestConfig.data.params = [hex]
-
- const rpcResult = await BitboxHTTP(requestConfig)
-
- const result = rpcResult.data.result
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(
- `Error in rawtransactions.ts/sendRawTransactionSingle().`,
- err
- )
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- getRawTransactionsFromNode,
- testableComponents: {
- root,
- decodeRawTransactionSingle,
- decodeRawTransactionBulk,
- decodeScriptSingle,
- decodeScriptBulk,
- getRawTransactionBulk,
- getRawTransactionSingle,
- sendRawTransactionBulk,
- sendRawTransactionSingle
- }
-}
diff --git a/src/routes/v2/route-utils.js b/src/routes/v2/route-utils.js
deleted file mode 100644
index 4b462c6..0000000
--- a/src/routes/v2/route-utils.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- A private library of utility functions used by several different routes.
-*/
-
-"use strict"
-
-const axios = require("axios")
-const wlogger = require("../../util/winston-logging")
-
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BITBOXJS = require("@chris.troutner/bch-js")
-const BITBOX = new BITBOXJS()
-
-module.exports = {
- validateNetwork, // Prevents a common user error
- setEnvVars, // Allows RPC variables to be set dynamically based on changing env vars.
- decodeError, // Extract and interpret error messages.
- validateArraySize // Ensure the passed array meets rate limiting requirements.
-}
-
-// This function expects the Request Express.js object and an array as input.
-// The array is then validated against freemium and pro-tier rate limiting
-// requirements. A boolean is returned to indicate if the array size if valid
-// or not.
-function validateArraySize(req, array) {
- const FREEMIUM_INPUT_SIZE = 20
- const PRO_INPUT_SIZE = 100
-
- if (req.locals && req.locals.proLimit) {
- if (array.length <= PRO_INPUT_SIZE) return true
- } else if (array.length <= FREEMIUM_INPUT_SIZE) {
- return true
- }
-
- return false
-}
-
-// Returns true if user-provided cash address matches the correct network,
-// mainnet or testnet. If NETWORK env var is not defined, it returns false.
-// This prevent a common user-error issue that is easy to make: passing a
-// testnet address into rest.bitcoin.com or passing a mainnet address into
-// trest.bitcoin.com.
-function validateNetwork(addr) {
- try {
- const network = process.env.NETWORK
-
- // Return false if NETWORK is not defined.
- if (!network || network === "") {
- console.log(`Warning: NETWORK environment variable is not defined!`)
- return false
- }
-
- // Convert the user-provided address to a cashaddress, for easy detection
- // of the intended network.
- const cashAddr = BITBOX.Address.toCashAddress(addr)
-
- // Return true if the network and address both match testnet
- const addrIsTest = BITBOX.Address.isTestnetAddress(cashAddr)
- if (network === "testnet" && addrIsTest) return true
-
- // Return true if the network and address both match mainnet
- const addrIsMain = BITBOX.Address.isMainnetAddress(cashAddr)
- if (network === "mainnet" && addrIsMain) return true
-
- return false
- } catch (err) {
- logger.error(`Error in validateNetwork()`)
- return false
- }
-}
-
-// Dynamically set these based on env vars. Allows unit testing.
-function setEnvVars() {
- const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
- })
- const username = process.env.RPC_USERNAME
- const password = process.env.RPC_PASSWORD
-
- const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
- }
-
- return { BitboxHTTP, username, password, requestConfig }
-}
-
-// Error messages returned by a full node can be burried pretty deep inside the
-// error object returned by Axios. This function attempts to extract and interpret
-// error messages.
-// Returns an object. If successful, obj.msg is a string.
-// If there is a failure, obj.msg is false.
-function decodeError(err) {
- try {
- // Attempt to extract the full node error message.
- if (
- err.response &&
- err.response.data &&
- err.response.data.error &&
- err.response.data.error.message
- )
- return { msg: err.response.data.error.message, status: 400 }
-
- // Attempt to extract the Insight error message
- if (err.response && err.response.data)
- return { msg: err.response.data, status: err.response.status }
-
- // Attempt to detect a network connection error.
- if (err.message && err.message.indexOf("ENOTFOUND") > -1) {
- return {
- msg:
- "Network error: Could not communicate with full node or other external service.",
- status: 503
- }
- }
-
- // Different kind of network error
- if (err.message && err.message.indexOf("ENETUNREACH") > -1) {
- return {
- msg:
- "Network error: Could not communicate with full node or other external service.",
- status: 503
- }
- }
-
- return { msg: false, status: 500 }
- } catch (err) {
- wlogger.error(`unhandled error in route-utils.js/decodeError(): `, err)
- return { msg: false, status: 500 }
- }
-}
diff --git a/src/routes/v2/services/bitbox.js b/src/routes/v2/services/bitbox.js
deleted file mode 100644
index 8fb0414..0000000
--- a/src/routes/v2/services/bitbox.js
+++ /dev/null
@@ -1,11 +0,0 @@
-"use strict"
-
-const axios = require("axios")
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-
-const getInstance = () => BitboxHTTP
-
-module.exports = getInstance
diff --git a/src/routes/v2/services/requestUtils.js b/src/routes/v2/services/requestUtils.js
deleted file mode 100644
index 7f64965..0000000
--- a/src/routes/v2/services/requestUtils.js
+++ /dev/null
@@ -1,20 +0,0 @@
-"use strict"
-
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const getRequestConfig = (method, params) => ({
- method: "post",
- auth: {
- username,
- password
- },
- data: {
- jsonrpc: "1.0",
- id: method,
- method,
- params
- }
-})
-
-module.exports = getRequestConfig
diff --git a/src/routes/v2/slp.js b/src/routes/v2/slp.js
deleted file mode 100644
index af9cdb0..0000000
--- a/src/routes/v2/slp.js
+++ /dev/null
@@ -1,1369 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const strftime = require("strftime")
-const wlogger = require("../../util/winston-logging")
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 5 }
-
-const SLPSDK = require("slp-sdk")
-const SLP = new SLPSDK()
-
-// Instantiate SLPJS.
-const slp = require("slpjs")
-const slpjs = new slp.Slp(SLP)
-const utils = slp.Utils
-
-// SLP tx db (LevelDB for caching)
-const level = require("level")
-const slpTxDb = level("./slp-tx-db")
-
-// Setup JSON RPC
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-// Setup REST and TREST URLs used by slpjs
-// Dev note: this allows for unit tests to mock the URL.
-if (!process.env.REST_URL) process.env.REST_URL = `https://rest.bitcoin.com/v2/`
-if (!process.env.TREST_URL)
- process.env.TREST_URL = `https://trest.bitcoin.com/v2/`
-
-router.get("/", root)
-router.get("/list", list)
-router.get("/list/:tokenId", listSingleToken)
-router.post("/list", listBulkToken)
-router.get("/balancesForAddress/:address", balancesForAddress)
-router.get("/balancesForToken/:tokenId", balancesForTokenSingle)
-router.get("/balance/:address/:tokenId", balancesForAddressByTokenID)
-router.get("/convert/:address", convertAddressSingle)
-router.post("/convert", convertAddressBulk)
-router.post("/validateTxid", validateBulk)
-router.get("/validateTxid/:txid", validateSingle)
-router.get("/txDetails/:txid", txDetails)
-router.get("/tokenStats/:tokenId", tokenStats)
-router.get("/transactions/:tokenId/:address", txsTokenIdAddressSingle)
-
-if (process.env.NON_JS_FRAMEWORK && process.env.NON_JS_FRAMEWORK === "true") {
- router.get(
- "/createTokenType1/:fundingAddress/:fundingWif/:tokenReceiverAddress/:batonReceiverAddress/:bchChangeReceiverAddress/:decimals/:name/:symbol/:documentUri/:documentHash/:initialTokenQty",
- createTokenType1
- )
- router.get(
- "/mintTokenType1/:fundingAddress/:fundingWif/:tokenReceiverAddress/:batonReceiverAddress/:bchChangeReceiverAddress/:tokenId/:additionalTokenQty",
- mintTokenType1
- )
- router.get(
- "/sendTokenType1/:fundingAddress/:fundingWif/:tokenReceiverAddress/:bchChangeReceiverAddress/:tokenId/:amount",
- sendTokenType1
- )
- router.get(
- "/burnTokenType1/:fundingAddress/:fundingWif/:bchChangeReceiverAddress/:tokenId/:amount",
- burnTokenType1
- )
- router.get(
- "/burnAllTokenType1/:fundingAddress/:fundingWif/:bchChangeReceiverAddress/:tokenId",
- burnAllTokenType1
- )
-}
-
-// Retrieve raw transactions details from the full node.
-// TODO: move this function to a separate support library.
-// TODO: Add unit tests for this function.
-async function getRawTransactionsFromNode(txids) {
- try {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- const txPromises = txids.map(async txid => {
- // Check slpTxDb
- try {
- if (slpTxDb.isOpen()) {
- const rawTx = await slpTxDb.get(txid)
- return rawTx
- }
- } catch (err) {}
-
- requestConfig.data.id = "getrawtransaction"
- requestConfig.data.method = "getrawtransaction"
- requestConfig.data.params = [txid, 0]
-
- const response = await BitboxHTTP(requestConfig)
- const result = response.data.result
-
- // Insert to slpTxDb
- try {
- if (slpTxDb.isOpen()) await slpTxDb.put(txid, result)
- } catch (err) {
- // console.log("Error inserting to slpTxDb", err)
- }
-
- return result
- })
-
- const results = await axios.all(txPromises)
- return results
- } catch (err) {
- wlogger.error(`Error in slp.ts/getRawTransactionsFromNode().`, err)
- throw err
- }
-}
-
-// Create a validator for validating SLP transactions.
-function createValidator(network, getRawTransactions = null) {
- let tmpSLP
-
- if (network === "mainnet")
- tmpSLP = new SLPSDK({ restURL: process.env.REST_URL })
- else tmpSLP = new SLPSDK({ restURL: process.env.TREST_URL })
-
- const slpValidator = new slp.LocalValidator(
- tmpSLP,
- getRawTransactions
- ? getRawTransactions
- : tmpSLP.RawTransactions.getRawTransaction.bind(this)
- )
-
- return slpValidator
-}
-
-// Instantiate the local SLP validator.
-const slpValidator = createValidator(
- process.env.NETWORK,
- getRawTransactionsFromNode
-)
-
-// Instantiate the bitboxproxy class in SLPJS.
-const bitboxproxy = new slp.BitboxNetwork(SLP, slpValidator)
-
-const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
-}
-
-function formatTokenOutput(token) {
- token.tokenDetails.id = token.tokenDetails.tokenIdHex
- delete token.tokenDetails.tokenIdHex
- token.tokenDetails.documentHash = token.tokenDetails.documentSha256Hex
- delete token.tokenDetails.documentSha256Hex
- token.tokenDetails.initialTokenQty = parseFloat(
- token.tokenDetails.genesisOrMintQuantity
- )
- delete token.tokenDetails.genesisOrMintQuantity
- delete token.tokenDetails.transactionType
- delete token.tokenDetails.batonVout
- delete token.tokenDetails.sendOutputs
-
- token.tokenDetails.blockCreated = token.tokenStats.block_created
- token.tokenDetails.blockLastActiveSend =
- token.tokenStats.block_last_active_send
- token.tokenDetails.blockLastActiveMint =
- token.tokenStats.block_last_active_mint
- token.tokenDetails.txnsSinceGenesis =
- token.tokenStats.qty_valid_txns_since_genesis
- token.tokenDetails.validAddresses = token.tokenStats.qty_valid_token_addresses
- token.tokenDetails.totalMinted = parseFloat(token.tokenStats.qty_token_minted)
- token.tokenDetails.totalBurned = parseFloat(token.tokenStats.qty_token_burned)
- token.tokenDetails.circulatingSupply = parseFloat(
- token.tokenStats.qty_token_circulating_supply
- )
- token.tokenDetails.mintingBatonStatus = token.tokenStats.minting_baton_status
-
- delete token.tokenStats.block_last_active_send
- delete token.tokenStats.block_last_active_mint
- delete token.tokenStats.qty_valid_txns_since_genesis
- delete token.tokenStats.qty_valid_token_addresses
- return token
-}
-
-function root(req, res, next) {
- return res.json({ status: "slp" })
-}
-
-async function list(req, res, next) {
- try {
- const query = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- $query: {}
- },
- project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
- sort: { "tokenStats.block_created": -1 },
- limit: 10000
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from SLPDB.
- const tokenRes = await axios.get(url)
-
- const formattedTokens = []
-
- if (tokenRes.data.t.length) {
- tokenRes.data.t.forEach(token => {
- token = formatTokenOutput(token)
- formattedTokens.push(token.tokenDetails)
- })
- }
-
- res.status(200)
- return res.json(formattedTokens)
- } catch (err) {
- wlogger.error(`Error in slp.ts/list().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({ error: `Error in /list: ${err.message}` })
- }
-}
-
-async function listSingleToken(req, res, next) {
- try {
- const tokenId = req.params.tokenId
-
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const t = await lookupToken(tokenId)
-
- res.status(200)
- return res.json(t)
- } catch (err) {
- wlogger.error(`Error in slp.ts/listSingleToken().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({ error: `Error in /list/:tokenId: ${err.message}` })
- }
-}
-
-async function listBulkToken(req, res, next) {
- try {
- const tokenIds = req.body.tokenIds
-
- // Reject if tokenIds is not an array.
- if (!Array.isArray(tokenIds)) {
- res.status(400)
- return res.json({
- error: "tokenIds needs to be an array. Use GET for single tokenId."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, tokenIds)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- const query = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- "tokenDetails.tokenIdHex": {
- $in: tokenIds
- }
- },
- project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
- sort: { "tokenStats.block_created": -1 },
- limit: 10000
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- const tokenRes = await axios.get(url)
-
- const formattedTokens = []
- const txids = []
-
- if (tokenRes.data.t.length) {
- tokenRes.data.t.forEach(token => {
- txids.push(token.tokenDetails.tokenIdHex)
- token = formatTokenOutput(token)
- formattedTokens.push(token.tokenDetails)
- })
- }
-
- tokenIds.forEach(tokenId => {
- if (!txids.includes(tokenId)) {
- formattedTokens.push({
- id: tokenId,
- valid: false
- })
- }
- })
-
- res.status(200)
- return res.json(formattedTokens)
- } catch (err) {
- wlogger.error(`Error in slp.ts/listBulkToken().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({ error: `Error in /list/:tokenId: ${err.message}` })
- }
-}
-
-async function lookupToken(tokenId) {
- try {
- const query = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- $query: {
- "tokenDetails.tokenIdHex": tokenId
- }
- },
- project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
- limit: 1000
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- const tokenRes = await axios.get(url)
- //console.log(`tokenRes.data: ${util.inspect(tokenRes.data,null,2)}`)
- //console.log(`tokenRes.data.t[0]: ${util.inspect(tokenRes.data.t[0],null,2)}`)
-
- const formattedTokens = []
-
- if (tokenRes.data.t.length) {
- tokenRes.data.t.forEach(token => {
- token = formatTokenOutput(token)
- formattedTokens.push(token.tokenDetails)
- })
- }
-
- let t
- formattedTokens.forEach(token => {
- if (token.id === tokenId) t = token
- })
-
- // If token could not be found.
- if (t === undefined) {
- t = {
- id: "not found"
- }
- }
-
- return t
- } catch (err) {
- wlogger.error(`Error in slp.ts/lookupToken().`, err)
- //console.log(`Error in slp.ts/lookupToken()`)
- throw err
- }
-}
-
-// Retrieve token balances for all tokens for a single address.
-async function balancesForAddress(req, res, next) {
- try {
- // Validate the input data.
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Ensure the input is a valid BCH address.
- try {
- const cash = utils.toCashAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const cashAddr = utils.toCashAddress(address)
- const networkIsValid = routeUtils.validateNetwork(cashAddr)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- const query = {
- v: 3,
- q: {
- db: ["a"],
- find: {
- address: SLP.Address.toSLPAddress(address),
- token_balance: { $gte: 0 }
- },
- limit: 10000
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- const tokenRes = await axios.get(url)
-
- const tokenIds = []
- if (tokenRes.data.a.length > 0) {
- tokenRes.data.a = tokenRes.data.a.map(token => {
- token.tokenId = token.tokenDetails.tokenIdHex
- tokenIds.push(token.tokenId)
- token.balance = parseFloat(token.token_balance)
- token.slpAddress = token.address
- delete token.tokenDetails
- delete token.satoshis_balance
- delete token.token_balance
- delete token._id
- delete token.address
- return token
- })
-
- const promises = tokenIds.map(async tokenId => {
- try {
- const query2 = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- $query: {
- "tokenDetails.tokenIdHex": tokenId
- }
- },
- project: {
- "tokenDetails.decimals": 1,
- "tokenDetails.tokenIdHex": 1,
- _id: 0
- },
- limit: 1000
- }
- }
-
- const s2 = JSON.stringify(query2)
- const b642 = Buffer.from(s2).toString("base64")
- const url2 = `${process.env.SLPDB_URL}q/${b642}`
-
- const tokenRes2 = await axios.get(url2)
- return tokenRes2.data
- } catch (err) {
- throw err
- }
- })
-
- const details = await axios.all(promises)
- tokenRes.data.a = tokenRes.data.a.map(token => {
- details.forEach(detail => {
- if (detail.t[0].tokenDetails.tokenIdHex === token.tokenId)
- token.decimalCount = detail.t[0].tokenDetails.decimals
- })
- return token
- })
-
- return res.json(tokenRes.data.a)
- }
- return res.json("No balance for this address")
- } catch (err) {
- wlogger.error(`Error in slp.ts/balancesForAddress().`, err)
-
- // Decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({
- error: `Error in /ddress/:address: ${err.message}`
- })
- }
-}
-
-// Retrieve token balances for all addresses by single tokenId.
-async function balancesForTokenSingle(req, res, next) {
- try {
- // Validate the input data.
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const query = {
- v: 3,
- q: {
- find: {
- "tokenDetails.tokenIdHex": tokenId,
- token_balance: { $gte: 0 }
- },
- limit: 10000,
- project: { address: 1, satoshis_balance: 1, token_balance: 1, _id: 0 }
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from SLPDB.
- const tokenRes = await axios.get(url)
- const resBalances = tokenRes.data.a.map((addy, index) => {
- delete addy.satoshis_balance
- addy.tokenBalance = parseFloat(addy.token_balance)
- addy.slpAddress = addy.address
- addy.tokenId = tokenId
- delete addy.address
- delete addy.token_balance
- return addy
- })
- return res.json(resBalances)
- } catch (err) {
- wlogger.error(`Error in slp.ts/balancesForTokenSingle().`, err)
-
- // Decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({
- error: `Error in /balancesForToken/:tokenId: ${err.message}`
- })
- }
-}
-
-// Retrieve token balances for a single token class, for a single address.
-async function balancesForAddressByTokenID(req, res, next) {
- try {
- // Validate input data.
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- // Ensure the input is a valid BCH address.
- try {
- const cash = utils.toCashAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const cashAddr = utils.toCashAddress(address)
- const networkIsValid = routeUtils.validateNetwork(cashAddr)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Convert input to an simpleledger: address.
- const slpAddr = utils.toSlpAddress(req.params.address)
-
- const query = {
- v: 3,
- q: {
- db: ["a"],
- find: {
- address: slpAddr,
- token_balance: { $gte: 0 }
- },
- limit: 10
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from SLPDB.
- const tokenRes = await axios.get(url)
- let resVal
- res.status(200)
- if (tokenRes.data.a.length > 0) {
- tokenRes.data.a.forEach(async token => {
- if (token.tokenDetails.tokenIdHex === tokenId) {
- resVal = {
- tokenId: tokenRes.data.a[0].tokenDetails.tokenIdHex,
- balance: parseFloat(tokenRes.data.a[0].token_balance)
- }
- // const query2 = {
- // v: 3,
- // q: {
- // db: ["t"],
- // find: {
- // $query: {
- // "tokenDetails.tokenIdHex": tokenId
- // }
- // },
- // project: {
- // "tokenDetails.decimals": 1,
- // "tokenDetails.tokenIdHex": 1,
- // _id: 0
- // },
- // limit: 1000
- // }
- // }
- //
- // const s2 = JSON.stringify(query2)
- // const b642 = Buffer.from(s2).toString("base64")
- // const url2 = `${process.env.SLPDB_URL}q/${b642}`
- //
- // const tokenRes2 = await axios.get(url2)
- // console.log("hello world", tokenRes2.data.t)
- // resVal = {
- // tokenId: token.tokenDetails.tokenIdHex,
- // balance: parseFloat(token.token_balance),
- // decimalCount: tokenRes2.data.t[0].tokenDetails.decimals
- // }
- // console.log("resVal", resVal)
- // return res.json(resVal)
- } else {
- resVal = {
- tokenId: tokenId,
- balance: 0
- }
- }
- })
- } else {
- resVal = {
- tokenId: tokenId,
- balance: 0
- }
- }
- return res.json(resVal)
- } catch (err) {
- wlogger.error(`Error in slp.ts/balancesForAddressByTokenID().`, err)
-
- // Decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({
- error: `Error in /balance/:address/:tokenId: ${err.message}`
- })
- }
-}
-
-async function convertAddressSingle(req, res, next) {
- try {
- const address = req.params.address
-
- // Validate input
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const slpAddr = SLP.Address.toSLPAddress(address)
-
- const obj = {
- slpAddress: "",
- cashAddress: "",
- legacyAddress: ""
- }
- obj.slpAddress = slpAddr
- obj.cashAddress = SLP.Address.toCashAddress(slpAddr)
- obj.legacyAddress = SLP.Address.toLegacyAddress(obj.cashAddress)
-
- res.status(200)
- return res.json(obj)
- } catch (err) {
- wlogger.error(`Error in slp.ts/convertAddressSingle().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({
- error: `Error in /address/convert/:address: ${err.message}`
- })
- }
-}
-
-async function convertAddressBulk(req, res, next) {
- const addresses = req.body.addresses
-
- // Reject if hashes is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Convert each address in the array.
- const convertedAddresses = []
- for (let i = 0; i < addresses.length; i++) {
- const address = addresses[i]
-
- // Validate input
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const slpAddr = SLP.Address.toSLPAddress(address)
-
- const obj = {
- slpAddress: "",
- cashAddress: "",
- legacyAddress: ""
- }
- obj.slpAddress = slpAddr
- obj.cashAddress = SLP.Address.toCashAddress(slpAddr)
- obj.legacyAddress = SLP.Address.toLegacyAddress(obj.cashAddress)
-
- convertedAddresses.push(obj)
- }
-
- res.status(200)
- return res.json(convertedAddresses)
-}
-
-async function validateBulk(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" })
- }
-
- // 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.`
- })
- }
-
- logger.debug(`Executing slp/validate with these txids: `, txids)
-
- // Validate each txid
- const validatePromises = txids.map(async txid => {
- try {
- // Dev note: must call module.exports to allow stubs in unit tests.
- const isValid = await module.exports.testableComponents.isValidSlpTxid(
- txid
- )
-
- const tmp = {
- txid: txid,
- valid: isValid ? true : false
- }
- return tmp
- } catch (err) {
- //console.log(`err obj: ${util.inspect(err)}`)
- //console.log(`err.response.data: ${util.inspect(err.response.data)}`)
- throw err
- }
- })
-
- // Filter array to only valid txid results
- const validateResults = await axios.all(validatePromises)
- const validTxids = validateResults.filter(result => result)
-
- res.status(200)
- return res.json(validTxids)
- } catch (err) {
- wlogger.error(`Error in slp.ts/validateBulk().`, err)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function validateSingle(req, res, next) {
- try {
- const txid = req.params.txid
-
- // Validate input
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- logger.debug(`Executing slp/validate/:txid with this txid: `, txid)
-
- // Validate txid
- // Dev note: must call module.exports to allow stubs in unit tests.
- const isValid = await module.exports.testableComponents.isValidSlpTxid(txid)
-
- const tmp = {
- txid: txid,
- valid: isValid ? true : false
- }
-
- res.status(200)
- return res.json(tmp)
- } catch (err) {
- wlogger.error(`Error in slp.ts/validateSingle().`, err)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Returns a Boolean if the input TXID is a valid SLP TXID.
-async function isValidSlpTxid(txid) {
- const isValid = await slpValidator.isValidSlpTxid(txid)
- return isValid
-}
-
-// Below are functions which are enabled for teams not using our javascript SDKs which still need to create txs
-// These should never be enabled on our public REST API
-
-async function createTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const tokenReceiverAddress = req.params.tokenReceiverAddress
- if (!tokenReceiverAddress || tokenReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "tokenReceiverAddress can not be empty" })
- }
-
- const batonReceiverAddress = req.params.batonReceiverAddress
- if (!batonReceiverAddress || batonReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "batonReceiverAddress can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const decimals = req.params.decimals
- if (!decimals || decimals === "") {
- res.status(400)
- return res.json({ error: "decimals can not be empty" })
- }
-
- const name = req.params.name
- if (!name || name === "") {
- res.status(400)
- return res.json({ error: "name can not be empty" })
- }
-
- const symbol = req.params.symbol
- if (!symbol || symbol === "") {
- res.status(400)
- return res.json({ error: "symbol can not be empty" })
- }
-
- const documentUri = req.params.documentUri
- if (!documentUri || documentUri === "") {
- res.status(400)
- return res.json({ error: "documentUri can not be empty" })
- }
-
- const documentHash = req.params.documentHash
- if (!documentHash || documentHash === "") {
- res.status(400)
- return res.json({ error: "documentHash can not be empty" })
- }
-
- const initialTokenQty = req.params.initialTokenQty
- if (!initialTokenQty || initialTokenQty === "") {
- res.status(400)
- return res.json({ error: "initialTokenQty can not be empty" })
- }
-
- const token = await SLP.TokenType1.create({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenReceiverAddress: tokenReceiverAddress,
- batonReceiverAddress: batonReceiverAddress,
- bchChangeReceiverAddress: bchChangeReceiverAddress,
- decimals: decimals,
- name: name,
- symbol: symbol,
- documentUri: documentUri,
- documentHash: documentHash,
- initialTokenQty: initialTokenQty
- })
-
- res.status(200)
- return res.json(token)
-}
-
-async function mintTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const tokenReceiverAddress = req.params.tokenReceiverAddress
- if (!tokenReceiverAddress || tokenReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "tokenReceiverAddress can not be empty" })
- }
-
- const batonReceiverAddress = req.params.batonReceiverAddress
- if (!batonReceiverAddress || batonReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "batonReceiverAddress can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const additionalTokenQty = req.params.additionalTokenQty
- if (!additionalTokenQty || additionalTokenQty === "") {
- res.status(400)
- return res.json({ error: "additionalTokenQty can not be empty" })
- }
-
- const mint = await SLP.TokenType1.mint({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenReceiverAddress: tokenReceiverAddress,
- batonReceiverAddress: batonReceiverAddress,
- bchChangeReceiverAddress: bchChangeReceiverAddress,
- tokenId: tokenId,
- additionalTokenQty: additionalTokenQty
- })
-
- res.status(200)
- return res.json(mint)
-}
-
-async function sendTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const tokenReceiverAddress = req.params.tokenReceiverAddress
- if (!tokenReceiverAddress || tokenReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "tokenReceiverAddress can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const amount = req.params.amount
- if (!amount || amount === "") {
- res.status(400)
- return res.json({ error: "amount can not be empty" })
- }
- const send = await SLP.TokenType1.send({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenReceiverAddress: tokenReceiverAddress,
- bchChangeReceiverAddress: bchChangeReceiverAddress,
- tokenId: tokenId,
- amount: amount
- })
-
- res.status(200)
- return res.json(send)
-}
-
-async function burnTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const amount = req.params.amount
- if (!amount || amount === "") {
- res.status(400)
- return res.json({ error: "amount can not be empty" })
- }
-
- const burn = await SLP.TokenType1.burn({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenId: tokenId,
- amount: amount,
- bchChangeReceiverAddress: bchChangeReceiverAddress
- })
-
- res.status(200)
- return res.json(burn)
-}
-
-async function burnAllTokenType1(req, res, next) {
- const fundingAddress = req.params.fundingAddress
- if (!fundingAddress || fundingAddress === "") {
- res.status(400)
- return res.json({ error: "fundingAddress can not be empty" })
- }
-
- const fundingWif = req.params.fundingWif
- if (!fundingWif || fundingWif === "") {
- res.status(400)
- return res.json({ error: "fundingWif can not be empty" })
- }
-
- const bchChangeReceiverAddress = req.params.bchChangeReceiverAddress
- if (!bchChangeReceiverAddress || bchChangeReceiverAddress === "") {
- res.status(400)
- return res.json({ error: "bchChangeReceiverAddress can not be empty" })
- }
-
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const burnAll = await SLP.TokenType1.burnAll({
- fundingAddress: fundingAddress,
- fundingWif: fundingWif,
- tokenId: tokenId,
- bchChangeReceiverAddress: bchChangeReceiverAddress
- })
-
- res.status(200)
- return res.json(burnAll)
-}
-
-async function txDetails(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" })
- }
-
- if (txid.length !== 64) {
- res.status(400)
- return res.json({ error: "This is not a txid" })
- }
-
- let tmpSLP
- if (process.env.NETWORK === "testnet")
- tmpSLP = new SLPSDK({ restURL: process.env.TREST_URL })
- else tmpSLP = new SLPSDK({ restURL: process.env.REST_URL })
-
- const tmpbitboxNetwork = new slp.BitboxNetwork(tmpSLP, slpValidator)
- //console.log(
- // `tmpbitboxNetwork: ${JSON.stringify(tmpbitboxNetwork, null, 2)}`
- //)
-
- // Get TX info + token info
- const result = await tmpbitboxNetwork.getTransactionDetails(txid)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- wlogger.error(`Error in slp.ts/txDetails().`, err)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Handle corner case of mis-typted txid
- if (err.error.indexOf("Not found") > -1) {
- res.status(400)
- return res.json({ error: "TXID not found" })
- }
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function tokenStats(req, res, next) {
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- try {
- const query = {
- v: 3,
- q: {
- db: ["t"],
- find: {
- $query: {
- "tokenDetails.tokenIdHex": tokenId
- }
- },
- project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
- limit: 10
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from BitDB.
- const tokenRes = await axios.get(url)
-
- const formattedTokens = []
-
- if (tokenRes.data.t.length) {
- tokenRes.data.t.forEach(token => {
- token = formatTokenOutput(token)
- formattedTokens.push(token.tokenDetails)
- })
- }
-
- res.status(200)
- return res.json(formattedTokens[0])
- } catch (err) {
- wlogger.error(`Error in slp.ts/tokenStats().`, err)
-
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
- res.status(500)
- return res.json({ error: `Error in /tokenStats: ${err.message}` })
- }
-}
-
-// Retrieve transactions by tokenId and address.
-async function txsTokenIdAddressSingle(req, res, next) {
- try {
- // Validate the input data.
- const tokenId = req.params.tokenId
- if (!tokenId || tokenId === "") {
- res.status(400)
- return res.json({ error: "tokenId can not be empty" })
- }
-
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const query = {
- v: 3,
- q: {
- find: {
- db: ["c", "u"],
- $query: {
- $or: [
- {
- "in.e.a": address
- },
- {
- "out.e.a": address
- }
- ],
- "slp.detail.tokenIdHex": tokenId
- },
- $orderby: {
- "blk.i": -1
- }
- },
- limit: 100
- },
- r: {
- f: "[.[] | { txid: .tx.h, tokenDetails: .slp } ]"
- }
- }
-
- const s = JSON.stringify(query)
- const b64 = Buffer.from(s).toString("base64")
- const url = `${process.env.SLPDB_URL}q/${b64}`
-
- // Get data from SLPDB.
- const tokenRes = await axios.get(url)
- //console.log(`tokenRes.data: ${JSON.stringify(tokenRes.data,null,2)}`)
-
- return res.json(tokenRes.data.c)
- } catch (err) {
- wlogger.error(`Error in slp.ts/txsTokenIdAddressSingle().`, err)
-
- // Decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- res.status(500)
- return res.json({
- error: `Error in /transactions/:tokenId/:address: ${err.message}`
- })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- list,
- listSingleToken,
- listBulkToken,
- balancesForAddress,
- balancesForAddressByTokenID,
- convertAddressSingle,
- convertAddressBulk,
- validateBulk,
- isValidSlpTxid,
- createTokenType1,
- mintTokenType1,
- sendTokenType1,
- burnTokenType1,
- burnAllTokenType1,
- txDetails,
- tokenStats,
- balancesForTokenSingle,
- txsTokenIdAddressSingle
- }
-}
diff --git a/src/routes/v2/transaction.js b/src/routes/v2/transaction.js
deleted file mode 100644
index 3f8e8eb..0000000
--- a/src/routes/v2/transaction.js
+++ /dev/null
@@ -1,188 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-const BITBOXJS = require("@chris.troutner/bch-js")
-const BITBOX = new BITBOXJS()
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 3 }
-
-// Manipulates and formats the raw data comming from Insight API.
-const processInputs = tx => {
- // Add legacy and cashaddr to tx vin
- if (tx.vin) {
- tx.vin.forEach(vin => {
- if (!vin.coinbase) {
- vin.value = vin.valueSat
- const address = vin.addr
- if (address) {
- vin.legacyAddress = BITBOX.Address.toLegacyAddress(address)
- vin.cashAddress = BITBOX.Address.toCashAddress(address)
- delete vin.addr
- }
- delete vin.valueSat
- delete vin.doubleSpentTxID
- }
- })
- }
-
- // Add legacy and cashaddr to tx vout
- if (tx.vout) {
- tx.vout.forEach(vout => {
- // Overwrite value string with value in satoshis
- //vout.value = parseFloat(vout.value) * 100000000
-
- if (vout.scriptPubKey) {
- if (vout.scriptPubKey.addresses) {
- const cashAddrs = []
- vout.scriptPubKey.addresses.forEach(addr => {
- const cashAddr = BITBOX.Address.toCashAddress(addr)
- cashAddrs.push(cashAddr)
- })
- vout.scriptPubKey.cashAddrs = cashAddrs
- }
- }
- })
- }
-}
-
-router.get("/", root)
-router.post("/details", detailsBulk)
-router.get("/details/:txid", detailsSingle)
-
-function root(req, res, next) {
- return res.json({ status: "transaction" })
-}
-
-// Retrieve transaction data from the Insight API
-// This function is also used by the SLP route library.
-async function transactionsFromInsight(txid) {
- try {
- const path = `${process.env.BITCOINCOM_BASEURL}tx/${txid}`
-
- // Query the Insight server.
- const response = await axios.get(path)
- //console.log(`Insight output: ${JSON.stringify(response.data, null, 2)}`)
-
- // Parse the data.
- const parsed = response.data
- if (parsed) processInputs(parsed)
-
- return parsed
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-async function detailsBulk(req, res, next) {
- try {
- const txids = req.body.txids
-
- // Reject if address is not an array.
- if (!Array.isArray(txids)) {
- res.status(400)
- return res.json({ error: "txids needs to be an array" })
- }
-
- // 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.`
- })
- }
-
- logger.debug(`Executing transaction/details with these txids: `, txids)
-
- // Collect an array of promises
- const promises = txids.map(
- async txid => await transactionsFromInsight(txid)
- )
-
- // Wait for all parallel promises to return.
- const result = await Promise.all(promises)
-
- // Return the array of retrieved transaction information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in transactions.ts/detailsBulk().`, err)
-
- //console.log(`Error in transaction details: `, err)
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function detailsSingle(req, res, next) {
- try {
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(txid)) {
- res.status(400)
- return res.json({
- error: "txid can not be an array. Use POST for bulk upload."
- })
- }
-
- logger.debug(
- `Executing transaction.ts/detailsSingle with this txid: `,
- txid
- )
-
- // Query the Insight API.
- const retData = await transactionsFromInsight(txid)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in transactions.ts/detailsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- transactionsFromInsight,
- testableComponents: {
- root,
- detailsBulk,
- detailsSingle
- }
-}
diff --git a/src/routes/v2/util.js b/src/routes/v2/util.js
deleted file mode 100644
index fed94cc..0000000
--- a/src/routes/v2/util.js
+++ /dev/null
@@ -1,173 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const logger = require("./logging.js")
-const wlogger = require("../../util/winston-logging")
-
-const BITBOXJS = require("@chris.troutner/bch-js")
-const BITBOX = new BITBOXJS()
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const requestConfig = {
- method: "post",
- auth: {
- username: username,
- password: password
- },
- data: {
- jsonrpc: "1.0"
- }
-}
-
-router.get("/", root)
-router.get("/validateAddress/:address", validateAddressSingle)
-router.post("/validateAddress", validateAddressBulk)
-
-function root(req, res, next) {
- return res.json({ status: "util" })
-}
-
-async function validateAddressSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "validateaddress"
- requestConfig.data.method = "validateaddress"
- requestConfig.data.params = [address]
-
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in util.ts/validateAddressSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-async function validateAddressBulk(req, res, next) {
- try {
- const addresses = req.body.addresses
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the array.
- for (let i = 0; i < addresses.length; i++) {
- const address = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = BITBOX.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- logger.debug(`Executing util/validate with these addresses: `, addresses)
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each address and creates an array of requests to call in parallel
- const promises = addresses.map(async address => {
- requestConfig.data.id = "validateaddress"
- requestConfig.data.method = "validateaddress"
- requestConfig.data.params = [address]
-
- return await BitboxHTTP(requestConfig)
- })
-
- // Wait for all parallel Insight requests to return.
- const axiosResult = await axios.all(promises)
-
- // Retrieve the data part of the result.
- const result = axiosResult.map(x => x.data.result)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in util.ts/validateAddressSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- validateAddressSingle,
- validateAddressBulk
- }
-}
diff --git a/src/routes/v3/bitcore.js b/src/routes/v3/bitcore.js
deleted file mode 100644
index 83342fd..0000000
--- a/src/routes/v3/bitcore.js
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- Bitcore Node API route
-*/
-
-"use strict"
-
-const express = require("express")
-const requestUtils = require("./services/requestUtils")
-const axios = require("axios")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
-
-const router = express.Router()
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BCHJS = require("@chris.troutner/bch-js")
-const bchjs = new BCHJS()
-
-//const BITCORE_URL = process.env.BITCORE_URL
-
-// Connect the route endpoints to their handler functions.
-router.get("/", root)
-router.get("/balance/:address", balanceSingle)
-router.post("/balance", balanceBulk)
-router.get("/utxos/:address", utxosSingle)
-router.post("/utxos", utxosBulk)
-
-// Root API endpoint. Simply acknowledges that it exists.
-function root(req, res, next) {
- return res.json({ status: "address" })
-}
-
-// Query the Bitcore Node API for a balance on a single BCH address.
-// Returns a Promise.
-async function balanceFromBitcore(thisAddress) {
- try {
- //console.log(`BITCORE_URL: ${BITCORE_URL}`)
-
- // Convert the address to a cashaddr without a prefix.
- const addr = bchjs.Address.toCashAddress(thisAddress, false)
-
- // Determine if we are working with the testnet or mainnet networks.
- let network = "mainnet"
- if (process.env.NETWORK === "testnet") network = "testnet"
-
- const path = `${process.env.BITCORE_URL}api/BCH/${network}/address/${addr}/balance`
-
- //console.log(`path: ${path}`)
-
- // Query the Bitcore Node API.
- const axiosResponse = await axios.get(path)
- const retData = axiosResponse.data
- //console.log(`retData: ${util.inspect(retData)}`)
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-/**
- * @api {get} /bitcore/balance/:address Get BCH balance for an address
- * @apiName GetBalance
- * @apiGroup Bitcore
- *
- * @apiParam {String} address Bitcoin Cash address.
- *
- * @apiSuccess {String} firstname Firstname of the User.
- * @apiSuccess {String} lastname Lastname of the User.
- */
-// GET handler for single balance
-async function balanceSingle(req, res, next) {
- try {
- const address = req.params.address
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(
- `Executing bitcore/balanceSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- const legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Bitcore Node API.
- const retData = await balanceFromBitcore(address)
-
- // Return the retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- wlogger.error(`Error in bitcore.js/balanceSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// POST handler for bulk queries on address details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v2/address/details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v2/address/details
-async function balanceBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- wlogger.debug(
- `Executing bitcore.js/balanceBulk with these addresses: `,
- addresses
- )
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- balanceFromBitcore(address)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in bitcore.js/balanceBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Query the Bitcore Node API for utxos associated with a BCH address.
-// Returns a Promise.
-async function utxosFromBitcore(thisAddress) {
- try {
- //console.log(`BITCORE_URL: ${BITCORE_URL}`)
-
- // Convert the address to a cashaddr without a prefix.
- const addr = bchjs.Address.toCashAddress(thisAddress, false)
-
- // Determine if we are working with the testnet or mainnet networks.
- let network = "mainnet"
- if (process.env.NETWORK === "testnet") network = "testnet"
-
- const path = `${process.env.BITCORE_URL}api/BCH/${network}/address/${addr}/?unspent=true`
-
- // Query the Bitcore Node API.
- const axiosResponse = await axios.get(path)
- const retData = axiosResponse.data
- //console.log(`retData: ${util.inspect(retData)}`)
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// GET handler for single balance
-async function utxosSingle(req, res, next) {
- try {
- const address = req.params.address
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(`Executing bitcore/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- const legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Bitcore Node API.
- const retData = await utxosFromBitcore(address)
-
- // Return the retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- wlogger.error(`Error in bitcore.js/utxosSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// POST handler for bulk queries on address utxos
-async function utxosBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- wlogger.debug(
- `Executing bitcore.js/utxosBulk with these addresses: `,
- addresses
- )
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- utxosFromBitcore(address)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in bitcore.js/utxosBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- balanceSingle,
- balanceBulk,
- utxosSingle,
- utxosBulk
- }
-}
diff --git a/src/routes/v3/blockbook.js b/src/routes/v3/blockbook.js
index 8b548c1..a499fc5 100644
--- a/src/routes/v3/blockbook.js
+++ b/src/routes/v3/blockbook.js
@@ -5,7 +5,6 @@
"use strict"
const express = require("express")
-const requestUtils = require("./services/requestUtils")
const axios = require("axios")
const routeUtils = require("./route-utils")
const wlogger = require("../../util/winston-logging")
diff --git a/src/routes/v3/control.js b/src/routes/v3/control.js
deleted file mode 100644
index da6eb78..0000000
--- a/src/routes/v3/control.js
+++ /dev/null
@@ -1,156 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-router.get("/", root)
-router.get("/getinfo", getInfo)
-router.get("/getnetworkinfo", getNetworkInfo)
-
-function root(req, res, next) {
- return res.json({ status: "control" })
-}
-
-/**
- * @api {get} /control/getinfo Get full node info
- * @apiName GetInfo
- * @apiGroup Control
- * @apiDescription RPC call which gets basic full node information.
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/control/getinfo" -H "accept: application/json"
- *
- * @apiSuccess {Object} object Object containing data
- * @apiSuccess {Number} object.version Full node version
- * @apiSuccess {Number} object.protocolversion Protocol version
- * @apiSuccess {Number} object.blocks Current block
- * @apiSuccess {Number} object.timeoffset ?
- * @apiSuccess {Number} object.connections Number of connected peers
- * @apiSuccess {String} object.proxy ?
- * @apiSuccess {Number} object.difficulty Current difficulty setting
- * @apiSuccess {Boolean} object.testnet testnet = true, mainnet = false
- * @apiSuccess {Number} object.paytxfee ?
- * @apiSuccess {Number} object.relayfee ?
- * @apiSuccess {String} object.errors Recent errors
- */
-async function getInfo(req, res, next) {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getinfo"
- requestConfig.data.method = "getinfo"
- requestConfig.data.params = []
-
- try {
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (error) {
- wlogger.error(`Error in control.ts/getInfo().`, error)
-
- // Write out error to error log.
- //logger.error(`Error in control/getInfo: `, error)
-
- res.status(500)
- if (error.response && error.response.data && error.response.data.error)
- return res.json({ error: error.response.data.error })
- return res.json({ error: util.inspect(error) })
- }
-}
-
-/**
- * @api {get} /control/getnetworkinfo Get Network Info
- * @apiName GetNetworkInfo
- * @apiGroup Control
- * @apiDescription RPC call which gets basic full node information.
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/control/getnetworkinfo" -H "accept: application/json"
- *
- */
-async function getNetworkInfo(req, res, next) {
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getnetworkinfo"
- requestConfig.data.method = "getnetworkinfo"
- requestConfig.data.params = []
-
- try {
- const response = await BitboxHTTP(requestConfig)
-
- return res.json(response.data.result)
- } catch (error) {
- wlogger.error(`Error in control.ts/getNetworkInfo().`, error)
-
- // Write out error to error log.
- //logger.error(`Error in control/getInfo: `, error)
-
- res.status(500)
- if (error.response && error.response.data && error.response.data.error)
- return res.json({ error: error.response.data.error })
- return res.json({ error: util.inspect(error) })
- }
-}
-
-// router.get('/getMemoryInfo', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getmemoryinfo",
-// method: "getmemoryinfo"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/help', (req, res, next) => {
-// BITBOX.Control.help()
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.post('/stop', (req, res, next) => {
-// BITBOX.Control.stop()
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-
-module.exports = {
- router,
- testableComponents: {
- root,
- getInfo,
- getNetworkInfo
- }
-}
diff --git a/src/routes/v3/blockchain.js b/src/routes/v3/full-node/blockchain.js
similarity index 99%
rename from src/routes/v3/blockchain.js
rename to src/routes/v3/full-node/blockchain.js
index 092e8bf..cd3d556 100644
--- a/src/routes/v3/blockchain.js
+++ b/src/routes/v3/full-node/blockchain.js
@@ -9,8 +9,8 @@ const express = require("express")
const router = express.Router()
const axios = require("axios")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
+const routeUtils = require("../route-utils")
+const wlogger = require("../../../util/winston-logging")
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
@@ -732,6 +732,8 @@ async function getTxOut(req, res, next) {
requestConfig.data.method = "gettxout"
requestConfig.data.params = [txid, n, include_mempool]
+ // console.log(`requestConfig: ${JSON.stringify(requestConfig, null, 2)}`)
+
const response = await BitboxHTTP(requestConfig)
return res.json(response.data.result)
diff --git a/src/routes/v2/control.js b/src/routes/v3/full-node/control.js
similarity index 72%
rename from src/routes/v2/control.js
rename to src/routes/v3/full-node/control.js
index fabc233..1a0ae1e 100644
--- a/src/routes/v2/control.js
+++ b/src/routes/v3/full-node/control.js
@@ -4,23 +4,31 @@ const express = require("express")
const router = express.Router()
const axios = require("axios")
-const logger = require("./logging.js")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
+const routeUtils = require("../route-utils")
+const wlogger = require("../../../util/winston-logging")
// Used for processing error messages before sending them to the user.
const util = require("util")
util.inspect.defaultOptions = { depth: 1 }
router.get("/", root)
-router.get("/getInfo", getInfo)
+router.get("/getnetworkinfo", getNetworkInfo)
function root(req, res, next) {
return res.json({ status: "control" })
}
-// Execute the RPC getinfo call.
-async function getInfo(req, res, next) {
+/**
+ * @api {get} /control/getnetworkinfo Get Network Info
+ * @apiName GetNetworkInfo
+ * @apiGroup Control
+ * @apiDescription RPC call which gets basic full node information.
+ *
+ * @apiExample Example usage:
+ * curl -X GET "https://mainnet.bchjs.cash/v3/control/getnetworkinfo" -H "accept: application/json"
+ *
+ */
+async function getNetworkInfo(req, res, next) {
const {
BitboxHTTP,
username,
@@ -28,8 +36,8 @@ async function getInfo(req, res, next) {
requestConfig
} = routeUtils.setEnvVars()
- requestConfig.data.id = "getinfo"
- requestConfig.data.method = "getinfo"
+ requestConfig.data.id = "getnetworkinfo"
+ requestConfig.data.method = "getnetworkinfo"
requestConfig.data.params = []
try {
@@ -37,7 +45,7 @@ async function getInfo(req, res, next) {
return res.json(response.data.result)
} catch (error) {
- wlogger.error(`Error in control.ts/getInfo().`, error)
+ wlogger.error(`Error in control.ts/getNetworkInfo().`, error)
// Write out error to error log.
//logger.error(`Error in control/getInfo: `, error)
@@ -90,6 +98,6 @@ module.exports = {
router,
testableComponents: {
root,
- getInfo
+ getNetworkInfo
}
}
diff --git a/src/routes/v3/mining.js b/src/routes/v3/full-node/mining.js
similarity index 97%
rename from src/routes/v3/mining.js
rename to src/routes/v3/full-node/mining.js
index 60f48d6..daa6c10 100644
--- a/src/routes/v3/mining.js
+++ b/src/routes/v3/full-node/mining.js
@@ -4,8 +4,8 @@ const express = require("express")
const router = express.Router()
const axios = require("axios")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
+const routeUtils = require("../route-utils")
+const wlogger = require("../../../util/winston-logging")
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
diff --git a/src/routes/v2/network.js b/src/routes/v3/full-node/network.js
similarity index 100%
rename from src/routes/v2/network.js
rename to src/routes/v3/full-node/network.js
diff --git a/src/routes/v3/rawtransactions.js b/src/routes/v3/full-node/rawtransactions.js
similarity index 99%
rename from src/routes/v3/rawtransactions.js
rename to src/routes/v3/full-node/rawtransactions.js
index d72beb9..7ae5998 100644
--- a/src/routes/v3/rawtransactions.js
+++ b/src/routes/v3/full-node/rawtransactions.js
@@ -4,8 +4,8 @@ const express = require("express")
const router = express.Router()
const axios = require("axios")
-const routeUtils = require("./route-utils")
-const wlogger = require("../../util/winston-logging")
+const routeUtils = require("../route-utils")
+const wlogger = require("../../../util/winston-logging")
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
diff --git a/src/routes/v3/insight/address.js b/src/routes/v3/insight/address.js
deleted file mode 100644
index 165156a..0000000
--- a/src/routes/v3/insight/address.js
+++ /dev/null
@@ -1,887 +0,0 @@
-/*
- Address route
-*/
-
-"use strict"
-
-const express = require("express")
-const requestUtils = require("../services/requestUtils")
-const axios = require("axios")
-const routeUtils = require("../route-utils")
-const wlogger = require("../../../util/winston-logging")
-
-//const router = express.Router()
-const router = express.Router()
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const BCHJS = require("@chris.troutner/bch-js")
-const bchjs = new BCHJS()
-
-// Use the default (and max) page size of 1000
-// https://github.com/bitpay/insight-api#notes-on-upgrading-from-v03
-const PAGE_SIZE = 1000
-
-// Connect the route endpoints to their handler functions.
-router.get("/", root)
-router.get("/details/:address", detailsSingle)
-router.post("/details", detailsBulk)
-router.post("/utxo", utxoBulk)
-router.get("/utxo/:address", utxoSingle)
-router.post("/unconfirmed", unconfirmedBulk)
-router.get("/unconfirmed/:address", unconfirmedSingle)
-router.get("/transactions/:address", transactionsSingle)
-router.post("/transactions", transactionsBulk)
-router.get("/fromXPub/:xpub", fromXPubSingle)
-
-// Root API endpoint. Simply acknowledges that it exists.
-function root(req, res, next) {
- return res.json({ status: "address" })
-}
-
-// Query the Insight API for details on a single BCH address.
-// Returns a Promise.
-async function detailsFromInsight(thisAddress, currentPage = 0) {
- try {
- //const addr = bchjs.Address.toLegacyAddress(thisAddress)
- const addr = bchjs.Address.toCashAddress(thisAddress)
-
- let path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}`
-
- // Set from and to params based on currentPage and pageSize
- // https://github.com/bitpay/insight-api/blob/master/README.md#notes-on-upgrading-from-v02
- const from = currentPage * PAGE_SIZE
- const to = from + PAGE_SIZE
- path = `${path}?from=${from}&to=${to}`
-
- //console.log(`insight path: ${path}`)
-
- // Query the Insight server.
- const axiosResponse = await axios.get(path)
- const retData = axiosResponse.data
- //console.log(`retData: ${util.inspect(retData)}`)
-
- // Calculate pagesTotal from response
- const pagesTotal = Math.ceil(retData.txApperances / PAGE_SIZE)
-
- // Append different address formats to the return data.
- retData.legacyAddress = bchjs.Address.toLegacyAddress(retData.addrStr)
- retData.cashAddress = bchjs.Address.toCashAddress(retData.addrStr)
- delete retData.addrStr
-
- // Append pagination information to the return data.
- retData.currentPage = currentPage
- retData.pagesTotal = pagesTotal
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-
-// POST handler for bulk queries on address details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v2/address/details
-// curl -d '{"addresses": ["bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr", "bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v2/address/details
-/**
- * @api {post} /address/details Get Address details bulk.
- * @apiName Address details bulk
- * @apiGroup Address
- * @apiDescription Returns the details of multiple addresses.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/details
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/details
- *
- */
-async function detailsBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if addresses is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({
- error: "addresses needs to be an array. Use GET for single address."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- wlogger.debug(`Executing address/details with these addresses: `, addresses)
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- detailsFromInsight(address, currentPage)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- //logger.error(`Error in detailsBulk(): `, err)
- wlogger.error(`Error in address.ts/detailsBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler for single address details
-/**
- * @api {get} insight/address/details/{address} Get Address details single.
- * @apiName Address details single
- * @apiGroup Address
- * @apiDescription Returns the details of an address including balance.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/details/bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c" -H "accept: application/json"
- *
- *
- */
-async function detailsSingle(req, res, next) {
- try {
- const address = req.params.address
- const currentPage = req.query.page ? parseInt(req.query.page, 10) : 0
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(
- `Executing address/detailsSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await detailsFromInsight(address, currentPage)
-
- // Return the retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in address.ts/detailsSingle: `, err)
- wlogger.error(`Error in address.ts/detailsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve UTXO data from the Insight API
-async function utxoFromInsight(thisAddress) {
- try {
- const addr = bchjs.Address.toCashAddress(thisAddress)
-
- const path = `${process.env.BITCOINCOM_BASEURL}addr/${addr}/utxo`
-
- // Query the Insight server.
- const response = await axios.get(path)
-
- // Append different address formats to the return data.
- const retData = {
- utxos: Array,
- legacyAddress: String,
- cashAddress: String,
- scriptPubKey: String
- }
- if (response.data.length && response.data[0].scriptPubKey) {
- const spk = response.data[0].scriptPubKey
- retData.scriptPubKey = spk
- }
- retData.legacyAddress = bchjs.Address.toLegacyAddress(thisAddress)
- retData.cashAddress = bchjs.Address.toCashAddress(thisAddress)
- retData.utxos = response.data.map(utxo => {
- delete utxo.address
- delete utxo.scriptPubKey
- return utxo
- })
- //console.log(`utxoFromInsight retData: ${util.inspect(retData)}`)
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-/**
- * @api {post} /address/utxo Get Address utxos bulk.
- * @apiName Address utxos bulk.
- * @apiGroup Address
- * @apiDescription Returns the utxo of multiple addresses.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/utxo
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/utxo
- *
- */
-// Retrieve UTXO information for an address.
-async function utxoBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (er) {
- //if (er.message.includes("Unsupported address format"))
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- wlogger.debug(
- `Executing address/utxoBulk with these addresses: `,
- addresses
- )
-
- // Loops through each address and creates an array of Promises, querying
- // Insight API in parallel.
- addresses = addresses.map(async (address, index) =>
- utxoFromInsight(address)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/utxoBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler for single address details
-/**
- * @api {get} /insight/address/utxo/{address} Get Address utxos single.
- * @apiName Address utxos single.
- * @apiGroup Address
- * @apiDescription Returns the list of utxo for an address.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/utxo/bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c" -H "accept: application/json"
- *
- *
- */
-async function utxoSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(`Executing address/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await utxoFromInsight(address)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/utxoSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-/**
- * @api {post} /address/utxo Get Unconfirmed transactions bulk.
- * @apiName Unconfirmed transactions bulk
- * @apiGroup Address
- * @apiDescription Returns the list of unconfirmed transactions for an array of addresses.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/unconfirmed
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/unconfirmed
- *
- */
-// Retrieve any unconfirmed TX information for a given address.
-async function unconfirmedBulk(req, res, next) {
- try {
- const addresses = req.body.addresses
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- wlogger.debug(`Executing address/utxo with these addresses: `, addresses)
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Collect an array of promises.
- const promises = addresses.map(address => utxoFromInsight(address))
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(promises)
-
- // Loop through each result
- const finalResult = result.map(elem => {
- //console.log(`elem: ${util.inspect(elem)}`)
-
- // Filter out confirmed transactions.
- const unconfirmedUtxos = elem.utxos.filter(
- utxo => utxo.confirmations === 0
- )
-
- elem.utxos = unconfirmedUtxos
-
- return elem
- })
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(finalResult)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/unconfirmedBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-/**
- * @api {get} /insight/address/utxo/{address} Get Unconfirmed transactions single.
- * @apiName Unconfirmed transactions single.
- * @apiGroup Address
- * @apiDescription Returns the list of unconfirmed transactions for an address.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/unconfirmed/bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c" -H "accept: application/json"
- *
- *
- */
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function unconfirmedSingle(req, res, next) {
- try {
- const address = req.params.address
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(`Executing address/utxoSingle with this address: `, address)
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await utxoFromInsight(address)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Loop through each returned UTXO.
- const unconfirmedUTXOs = []
- for (let j = 0; j < retData.utxos.length; j++) {
- const thisUtxo = retData.utxos[j]
-
- // Only interested in UTXOs with no confirmations.
- if (thisUtxo.confirmations === 0) unconfirmedUTXOs.push(thisUtxo)
- }
-
- retData.utxos = unconfirmedUTXOs
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/unconfirmedSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// Retrieve transaction data from the Insight API
-async function transactionsFromInsight(thisAddress, currentPage = 0) {
- try {
- const path = `${process.env.BITCOINCOM_BASEURL}txs/?address=${thisAddress}&pageNum=${currentPage}`
-
- // Query the Insight server.
- const response = await axios.get(path)
-
- // Append different address formats to the return data.
- const retData = response.data
- retData.legacyAddress = bchjs.Address.toLegacyAddress(thisAddress)
- retData.cashAddress = bchjs.Address.toCashAddress(thisAddress)
- retData.currentPage = currentPage
-
- return retData
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-/**
- * @api {post} /address/transactions Get Transactions bulk.
- * @apiName Transactions bulk.
- * @apiGroup Address
- * @apiDescription Returns the list of transactions for an array of addresses.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"]}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/transactions
- * curl -d '{"addresses": ["bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c", "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"], "from": 1, "to": 5}' -H "Content-Type: application/json" https://mainnet.bchjs.cash/v3/insight/address/transactions
- *
- */
-// Get an array of TX information for a given address.
-async function transactionsBulk(req, res, next) {
- try {
- let addresses = req.body.addresses
- const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
-
- // Reject if address is not an array.
- if (!Array.isArray(addresses)) {
- res.status(400)
- return res.json({ error: "addresses needs to be an array" })
- }
-
- wlogger.debug(`Executing address/utxo with these addresses: `, addresses)
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, addresses)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- // Validate each element in the address array.
- for (let i = 0; i < addresses.length; i++) {
- const thisAddress = addresses[i]
-
- // Ensure the input is a valid BCH address.
- try {
- bchjs.Address.toLegacyAddress(thisAddress)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${thisAddress}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(thisAddress)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network for address ${thisAddress}. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
- }
-
- // Loop through each address and collect an array of promises.
- addresses = addresses.map(async (address, index) =>
- transactionsFromInsight(address, currentPage)
- )
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(addresses)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/transactionsBulk().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-/**
- * @api {get} /insight/address/transactions/{address} Get Transactions single.
- * @apiName Transactions single.
- * @apiGroup Address
- * @apiDescription Returns the list of transactions for an address.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/transactions/bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c" -H "accept: application/json"
- *
- *
- */
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-async function transactionsSingle(req, res, next) {
- try {
- const address = req.params.address
- const currentPage = req.query.page ? parseInt(req.query.page, 10) : 0
-
- if (!address || address === "") {
- res.status(400)
- return res.json({ error: "address can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(address)) {
- res.status(400)
- return res.json({
- error: "address can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(
- `Executing address/transactionsSingle with this address: `,
- address
- )
-
- // Ensure the input is a valid BCH address.
- try {
- var legacyAddr = bchjs.Address.toLegacyAddress(address)
- } catch (err) {
- res.status(400)
- return res.json({
- error: `Invalid BCH address. Double check your address is valid: ${address}`
- })
- }
-
- // Prevent a common user error. Ensure they are using the correct network address.
- const networkIsValid = routeUtils.validateNetwork(address)
- if (!networkIsValid) {
- res.status(400)
- return res.json({
- error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
- })
- }
-
- // Query the Insight API.
- const retData = await transactionsFromInsight(address, currentPage)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/transactionsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-/**
- * @api {get} /insight/address/fromXPub/{xpub} Get FromXPub
- * @apiName FromXPub
- * @apiGroup Address
- * @apiDescription Returns an address for an extended public key and hdpath.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/address/fromXPub/xpub661MyMwAqRbcG4CnhNYoK1r1TKLwQQ1UdC3LHoWFK61rsnzh7Hx35qQ9Z53ucYcE5WvA7GEDXhqqKjSY2e6Y8n7WNVLYHpXCuuX945VPuYn" -H "accept: application/json"
- *
- *
- */
-async function fromXPubSingle(req, res, next) {
- try {
- const xpub = req.params.xpub
- const hdPath = req.query.hdPath ? req.query.hdPath : "0"
-
- if (!xpub || xpub === "") {
- res.status(400)
- return res.json({ error: "xpub can not be empty" })
- }
-
- // Reject if xpub is an array.
- if (Array.isArray(xpub)) {
- res.status(400)
- return res.json({
- error: "xpub can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(`Executing address/fromXPub with this xpub: `, xpub)
-
- const cashAddr = bchjs.Address.fromXPub(xpub, hdPath)
- const legacyAddr = bchjs.Address.toLegacyAddress(cashAddr)
- res.status(200)
- return res.json({
- cashAddress: cashAddr,
- legacyAddress: legacyAddr
- })
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in address.ts/fromXPubSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- detailsBulk,
- detailsSingle,
- utxoBulk,
- utxoSingle,
- unconfirmedBulk,
- unconfirmedSingle,
- transactionsBulk,
- transactionsSingle,
- fromXPubSingle
- }
-}
diff --git a/src/routes/v3/insight/block.js b/src/routes/v3/insight/block.js
deleted file mode 100644
index d813806..0000000
--- a/src/routes/v3/insight/block.js
+++ /dev/null
@@ -1,324 +0,0 @@
-"use strict"
-
-const express = require("express")
-const requestUtils = require("../services/requestUtils")
-const axios = require("axios")
-const bitbox = require("../services/bitbox")
-const wlogger = require("../../../util/winston-logging")
-
-const routeUtils = require("../route-utils")
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 3 }
-
-const router = express.Router()
-//const BitboxHTTP = bitbox.getInstance()
-
-router.get("/", root)
-router.get("/detailsByHash/:hash", detailsByHashSingle)
-router.post("/detailsByHash", detailsByHashBulk)
-router.get("/detailsByHeight/:height", detailsByHeightSingle)
-router.post("/detailsByHeight", detailsByHeightBulk)
-
-function root(req, res, next) {
- return res.json({ status: "block" })
-}
-/**
- * @api {get} /block/detailsByHash/{hash} Get Block details single.
- * @apiName Block details single
- * @apiGroup Block
- * @apiDescription Returns details about a single block by hash.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/block/detailsByHash/000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201" -H "accept: application/json"
- *
- *
- */
-// Call the insight server to get block details based on the hash.
-async function detailsByHashSingle(req, res, next) {
- try {
- const hash = req.params.hash
-
- // Reject if hash is empty
- if (!hash || hash === "") {
- res.status(400)
- return res.json({ error: "hash must not be empty" })
- }
-
- const response = await axios.get(
- `${process.env.BITCOINCOM_BASEURL}block/${hash}`
- )
- //console.log(`response.data: ${JSON.stringify(response.data,null,2)}`)
-
- const parsed = response.data
- return res.json(parsed)
- } catch (error) {
- //console.log(`error object: ${util.inspect(error)}`)
-
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHashSingle().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-/**
- * @api {post} /block/detailsByHash Get Block details bulk.
- * @apiName Block details bulk
- * @apiGroup Block
- * @apiDescription Returns retails about multiple blocks by hashes.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"hashes":["0000000000000000040e83398a79a16390897f0d18c92bada6350a19a32ec984","000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"]}' -H "Content-Type: application/json" "https://mainnet.bchjs.cash/v3/insight/block/detailsByHash"
- * curl -d '{"hashes":["0000000000000000040e83398a79a16390897f0d18c92bada6350a19a32ec984","000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"], "from": 1, "to": 5}' -H "Content-Type: application/json" "https://mainnet.bchjs.cash/v3/insight/block/detailsByHash"
- *
- */
-async function detailsByHashBulk(req, res, next) {
- try {
- const hashes = req.body.hashes
- //console.log(`hashes: ${JSON.stringify(hashes, null, 2)}`)
-
- // Reject if hashes is not an array.
- if (!Array.isArray(hashes)) {
- res.status(400)
- return res.json({
- error: "hashes needs to be an array. Use GET for single address."
- })
- }
-
- // 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.`
- })
- }
-
- // Validate each hash in the array.
- for (let i = 0; i < hashes.length; i++) {
- const thisHash = hashes[i]
-
- if (thisHash.length !== 64) {
- res.status(400)
- return res.json({
- error: `Invalid hash. Double check your hash is valid: ${thisHash}`
- })
- }
- }
-
- // Loop through each hash and creates an array of promises
- const axiosPromises = hashes.map(async hash =>
- axios.get(`${process.env.BITCOINCOM_BASEURL}block/${hash}`)
- )
-
- // Wait for all parallel promises to return.
- const axiosResult = await axios.all(axiosPromises)
-
- // Extract the data component from the axios response.
- const result = axiosResult.map(x => x.data)
- //console.log(`result: ${util.inspect(result)}`)
-
- res.status(200)
- return res.json(result)
- } catch (error) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHashBulk().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-/**
- * @api {get} /block/detailsByHeight/{hash} Get Block details single by height.
- * @apiName Block details single by height
- * @apiGroup Block
- * @apiDescription Returns Details about a single block by height.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/block/block/detailsByHeight/500000" -H "accept: application/json"
- *
- *
- */
-// Call the Full Node to get block hash based on height, then call the Insight
-// server to get details from that hash.
-async function detailsByHeightSingle(req, res, next) {
- try {
- const height = req.params.height
-
- // Reject if id is empty
- if (!height || height === "") {
- res.status(400)
- return res.json({ error: "height must not be empty" })
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- requestConfig.data.id = "getblockhash"
- requestConfig.data.method = "getblockhash"
- requestConfig.data.params = [parseInt(height)]
-
- const response = await BitboxHTTP(requestConfig)
-
- const hash = response.data.result
- //console.log(`response.data: ${util.inspect(response.data)}`)
-
- // Call detailsByHashSingle now that the hash has been retrieved.
- req.params.hash = hash
- return detailsByHashSingle(req, res, next)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in control/getInfo: `, error)
- wlogger.error(`Error in block.ts/detailsByHeightSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-/**
- * @api {post} /block/detailsByHash Get Block details bulk by height.
- * @apiName Block details bulk by height
- * @apiGroup Block
- * @apiDescription Returns Bulk details about blocks by heights.
- *
- *
- * @apiExample Example usage:
- * curl -d '{"heights":[499000,500000]}' -H "Content-Type: application/json" "https://mainnet.bchjs.cash/v3/insight/block/detailsByHeight"
- * curl -d '{"heights":[499000,500000], "from": 1, "to": 5}' -H "Content-Type: application/json" "https://mainnet.bchjs.cash/v3/insight/block/detailsByHeight"
- *
- */
-async function detailsByHeightBulk(req, res, next) {
- try {
- const heights = req.body.heights
-
- // Reject if heights is not an array.
- if (!Array.isArray(heights)) {
- res.status(400)
- return res.json({
- error: "heights needs to be an array. Use GET for single height."
- })
- }
-
- // Enforce array size rate limits
- if (!routeUtils.validateArraySize(req, heights)) {
- res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
- return res.json({
- error: `Array too large.`
- })
- }
-
- wlogger.debug(`Executing detailsByHeight with these heights: `, heights)
-
- // Validate each element in the address array.
- for (let i = 0; i < heights.length; i++) {
- const thisHeight = heights[i]
-
- // Reject if id is empty
- if (!thisHeight || thisHeight === "") {
- res.status(400)
- return res.json({ error: "height must not be empty" })
- }
- }
-
- const {
- BitboxHTTP,
- username,
- password,
- requestConfig
- } = routeUtils.setEnvVars()
-
- // Loop through each height and creates an array of requests to call in parallel
- const promises = heights.map(async height => {
- requestConfig.data.id = "getblockhash"
- requestConfig.data.method = "getblockhash"
- requestConfig.data.params = [parseInt(height)]
-
- const response = await BitboxHTTP(requestConfig)
-
- const hash = response.data.result
-
- const axiosResult = await axios.get(
- `${process.env.BITCOINCOM_BASEURL}block/${hash}`
- )
-
- return axiosResult.data
- })
-
- // Wait for all parallel Insight requests to return.
- const result = await axios.all(promises)
-
- res.status(200)
- return res.json(result)
- } catch (error) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(error)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- if (error.response && error.response.status === 404) {
- res.status(404)
- return res.json({ error: "Not Found" })
- }
-
- // Write out error to error log.
- //logger.error(`Error in block/detailsByHash: `, error)
- wlogger.error(`Error in block.ts/detailsByHeightBulk().`, error)
-
- res.status(500)
- return res.json({ error: util.inspect(error) })
- }
-}
-
-module.exports = {
- router,
- testableComponents: {
- root,
- detailsByHashSingle,
- detailsByHashBulk,
- detailsByHeightSingle,
- detailsByHeightBulk
- }
-}
diff --git a/src/routes/v3/insight/index.js b/src/routes/v3/insight/index.js
deleted file mode 100644
index 8f3c11f..0000000
--- a/src/routes/v3/insight/index.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- Insight API route
- A parent route that encompases the other libraries.
-*/
-
-"use strict"
-
-const express = require("express")
-const requestUtils = require("../services/requestUtils")
-const axios = require("axios")
-const routeUtils = require("../route-utils")
-const wlogger = require("../../../util/winston-logging")
-
-const router = express.Router()
-
-// Used for processing error messages before sending them to the user.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-//const BCHJS = require("@chris.troutner/bch-js")
-//const bchjs = new BCHJS()
-
-//const BITCORE_URL = process.env.BITCORE_URL
-
-// Connect the route endpoints to their handler functions.
-router.get("/", root)
-
-// Root API endpoint. Simply acknowledges that it exists.
-function root(req, res, next) {
- return res.json({ status: "address" })
-}
-
-module.exports = {
- router,
- testableComponents: {
- root
- }
-}
diff --git a/src/routes/v3/insight/transaction.js b/src/routes/v3/insight/transaction.js
deleted file mode 100644
index ad6cc29..0000000
--- a/src/routes/v3/insight/transaction.js
+++ /dev/null
@@ -1,210 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-const axios = require("axios")
-
-const routeUtils = require("../route-utils")
-const wlogger = require("../../../util/winston-logging")
-
-const BCHJS = require("@chris.troutner/bch-js")
-const bchjs = new BCHJS()
-
-// Used to convert error messages to strings, to safely pass to users.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 3 }
-
-// Manipulates and formats the raw data comming from Insight API.
-const processInputs = tx => {
- // Add legacy and cashaddr to tx vin
- if (tx.vin) {
- tx.vin.forEach(vin => {
- if (!vin.coinbase) {
- vin.value = vin.valueSat
- const address = vin.addr
- if (address) {
- vin.legacyAddress = bchjs.Address.toLegacyAddress(address)
- vin.cashAddress = bchjs.Address.toCashAddress(address)
- delete vin.addr
- }
- delete vin.valueSat
- delete vin.doubleSpentTxID
- }
- })
- }
-
- // Add legacy and cashaddr to tx vout
- if (tx.vout) {
- tx.vout.forEach(vout => {
- // Overwrite value string with value in satoshis
- //vout.value = parseFloat(vout.value) * 100000000
-
- if (vout.scriptPubKey) {
- if (vout.scriptPubKey.addresses) {
- const cashAddrs = []
- vout.scriptPubKey.addresses.forEach(addr => {
- const cashAddr = bchjs.Address.toCashAddress(addr)
- cashAddrs.push(cashAddr)
- })
- vout.scriptPubKey.cashAddrs = cashAddrs
- }
- }
- })
- }
-}
-
-router.get("/", root)
-router.post("/details", detailsBulk)
-router.get("/details/:txid", detailsSingle)
-
-function root(req, res, next) {
- return res.json({ status: "transaction" })
-}
-
-// Retrieve transaction data from the Insight API
-// This function is also used by the SLP route library.
-async function transactionsFromInsight(txid) {
- try {
- const path = `${process.env.BITCOINCOM_BASEURL}tx/${txid}`
-
- // Query the Insight server.
- const response = await axios.get(path)
- //console.log(`Insight output: ${JSON.stringify(response.data, null, 2)}`)
-
- // Parse the data.
- const parsed = response.data
- if (parsed) processInputs(parsed)
-
- return parsed
- } catch (err) {
- // Dev Note: Do not log error messages here. Throw them instead and let the
- // parent function handle it.
- throw err
- }
-}
-/**
- * @api {post} /transaction/details Get Transaction details bulk.
- * @apiName Transaction details bulk
- * @apiGroup Transaction
- * @apiDescription Returns Bulk Details about a transaction.
- *
- *
- * @apiExample Example usage:
- * curl -X POST "https://mainnet.bchjs.cash/v3/insight/transaction/details" -H "Content-Type: application/json" -d "{"txids":["a5f972572ee1753e2fd2457dd61ce5f40fa2f8a30173d417e49feef7542c96a1","5165dc531aad05d1149bb0f0d9b7bda99c73e2f05e314bcfb5b4bb9ca5e1af5e"]}"
- *
- */
-
-async function detailsBulk(req, res, next) {
- try {
- const txids = req.body.txids
-
- // Reject if address is not an array.
- if (!Array.isArray(txids)) {
- res.status(400)
- return res.json({ error: "txids needs to be an array" })
- }
-
- // 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 transaction/details with these txids: `, txids)
-
- // Collect an array of promises
- const promises = txids.map(
- async txid => await transactionsFromInsight(txid)
- )
-
- // Wait for all parallel promises to return.
- const result = await Promise.all(promises)
-
- // Return the array of retrieved transaction information.
- res.status(200)
- return res.json(result)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- wlogger.error(`Error in transactions.ts/detailsBulk().`, err)
-
- //console.log(`Error in transaction details: `, err)
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-// GET handler. Retrieve any unconfirmed TX information for a given address.
-/**
- * @api {get} insight/transaction/details/{txid} Get Transaction details single.
- * @apiName Transaction details single
- * @apiGroup Transaction
- * @apiDescription Returns the details about a single transaction.
- *
- *
- * @apiExample Example usage:
- * curl -X GET "https://mainnet.bchjs.cash/v3/insight/transaction/details/fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" -H "accept: application/json"
- *
- *
- */
-async function detailsSingle(req, res, next) {
- try {
- const txid = req.params.txid
- if (!txid || txid === "") {
- res.status(400)
- return res.json({ error: "txid can not be empty" })
- }
-
- // Reject if address is an array.
- if (Array.isArray(txid)) {
- res.status(400)
- return res.json({
- error: "txid can not be an array. Use POST for bulk upload."
- })
- }
-
- wlogger.debug(
- `Executing transaction.ts/detailsSingle with this txid: `,
- txid
- )
-
- // Query the Insight API.
- const retData = await transactionsFromInsight(txid)
- //console.log(`retData: ${JSON.stringify(retData,null,2)}`)
-
- // Return the array of retrieved address information.
- res.status(200)
- return res.json(retData)
- } catch (err) {
- // Attempt to decode the error message.
- const { msg, status } = routeUtils.decodeError(err)
- if (msg) {
- res.status(status)
- return res.json({ error: msg })
- }
-
- // Write out error to error log.
- //logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
- wlogger.error(`Error in transactions.ts/detailsSingle().`, err)
-
- res.status(500)
- return res.json({ error: util.inspect(err) })
- }
-}
-
-module.exports = {
- router,
- transactionsFromInsight,
- testableComponents: {
- root,
- detailsBulk,
- detailsSingle
- }
-}
diff --git a/src/routes/v3/network.js b/src/routes/v3/network.js
deleted file mode 100644
index 0af2366..0000000
--- a/src/routes/v3/network.js
+++ /dev/null
@@ -1,168 +0,0 @@
-"use strict"
-
-const express = require("express")
-const router = express.Router()
-
-router.get("/", async (req, res, next) => {
- res.json({ status: "network" })
-})
-
-// router.post('/addNode/:node/:command', (req, res, next) => {
-// BITBOX.Network.addNode(req.params.node, req.params.command)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.post('/clearBanned', (req, res, next) => {
-// BITBOX.Network.clearBanned()
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.post('/disconnectNode/:address/:nodeid', (req, res, next) => {
-// BITBOX.Network.disconnectNode(req.params.address, req.params.nodeid)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.get('/getAddedNodeInfo/:node', (req, res, next) => {
-// BITBOX.Network.getAddedNodeInfo(req.params.node)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.get('/getConnectionCount', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getconnectioncount",
-// method: "getconnectioncount"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/getNetTotals', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getnettotals",
-// method: "getnettotals"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/getNetworkInfo', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getnetworkinfo",
-// method: "getnetworkinfo"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/getPeerInfo', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"getpeerinfo",
-// method: "getpeerinfo"
-// }
-// })
-// .then((response) => {
-// res.json(response.data.result);
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.get('/ping', (req, res, next) => {
-// BitboxHTTP({
-// method: 'post',
-// auth: {
-// username: username,
-// password: password
-// },
-// data: {
-// jsonrpc: "1.0",
-// id:"ping",
-// method: "ping"
-// }
-// })
-// .then((response) => {
-// res.json(JSON.stringify(response.data.result));
-// })
-// .catch((error) => {
-// res.send(error.response.data.error.message);
-// });
-// });
-//
-// router.post('/setBan/:subnet/:command', (req, res, next) => {
-// // TODO finish this
-// BITBOX.Network.getConnectionCount(req.params.subnet, req.params.command)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-//
-// router.post('/setNetworkActive/:state', (req, res, next) => {
-// let state = true;
-// if(req.params.state && req.params.state === 'false') {
-// state = false;
-// }
-// BITBOX.Network.getConnectionCount(state)
-// .then((result) => {
-// res.json(result);
-// }, (err) => { console.log(err);
-// });
-// });
-
-module.exports = router
diff --git a/src/routes/v3/route-utils.js b/src/routes/v3/route-utils.js
index be11a4e..38652fc 100644
--- a/src/routes/v3/route-utils.js
+++ b/src/routes/v3/route-utils.js
@@ -26,7 +26,7 @@ module.exports = {
// or not.
function validateArraySize(req, array) {
const FREEMIUM_INPUT_SIZE = 20
- const PRO_INPUT_SIZE = 100
+ const PRO_INPUT_SIZE = 20
if (req.locals && req.locals.proLimit) {
if (array.length <= PRO_INPUT_SIZE) return true
@@ -131,6 +131,15 @@ function decodeError(err) {
}
}
+ // Different kind of network error
+ if (err.message && err.message.indexOf("EAI_AGAIN") > -1) {
+ return {
+ msg:
+ "Network error: Could not communicate with full node or other external service.",
+ status: 503
+ }
+ }
+
return { msg: false, status: 500 }
} catch (err) {
wlogger.error(`unhandled error in route-utils.js/decodeError(): `, err)
diff --git a/src/routes/v3/services/bitbox.js b/src/routes/v3/services/bitbox.js
deleted file mode 100644
index 8fb0414..0000000
--- a/src/routes/v3/services/bitbox.js
+++ /dev/null
@@ -1,11 +0,0 @@
-"use strict"
-
-const axios = require("axios")
-
-const BitboxHTTP = axios.create({
- baseURL: process.env.RPC_BASEURL
-})
-
-const getInstance = () => BitboxHTTP
-
-module.exports = getInstance
diff --git a/src/routes/v3/services/requestUtils.js b/src/routes/v3/services/requestUtils.js
deleted file mode 100644
index 7f64965..0000000
--- a/src/routes/v3/services/requestUtils.js
+++ /dev/null
@@ -1,20 +0,0 @@
-"use strict"
-
-const username = process.env.RPC_USERNAME
-const password = process.env.RPC_PASSWORD
-
-const getRequestConfig = (method, params) => ({
- method: "post",
- auth: {
- username,
- password
- },
- data: {
- jsonrpc: "1.0",
- id: method,
- method,
- params
- }
-})
-
-module.exports = getRequestConfig
diff --git a/src/routes/v3/slp.js b/src/routes/v3/slp.js
index d86c6dc..c3eb6eb 100644
--- a/src/routes/v3/slp.js
+++ b/src/routes/v3/slp.js
@@ -9,22 +9,13 @@ const routeUtils = require("./route-utils")
const strftime = require("strftime")
const wlogger = require("../../util/winston-logging")
+const BCHJS = require("@chris.troutner/bch-js")
+const bchjs = new BCHJS()
+
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
util.inspect.defaultOptions = { depth: 5 }
-const SLPSDK = require("slp-sdk")
-const SLP = new SLPSDK()
-
-// Instantiate SLPJS.
-const slp = require("slpjs")
-const slpjs = new slp.Slp(SLP)
-const utils = slp.Utils
-
-// SLP tx db (LevelDB for caching)
-// const level = require("level")
-// const slpTxDb = level("./slp-tx-db")
-
// Setup JSON RPC
const BitboxHTTP = axios.create({
baseURL: process.env.RPC_BASEURL
@@ -36,7 +27,8 @@ const password = process.env.RPC_PASSWORD
// https://gist.github.com/christroutner/fc717ca704dec3dded8b52fae387eab2
const SLPDB_PASS = process.env.SLPDB_PASS ? process.env.SLPDB_PASS : "BITBOX"
-const transactions = require("./insight/transaction")
+// const transactions = require("./insight/transaction")
+const rawtransactions = require("./full-node/rawtransactions")
// Setup REST and TREST URLs used by slpjs
// Dev note: this allows for unit tests to mock the URL.
@@ -375,7 +367,7 @@ async function balancesForAddress(req, res, next) {
// Ensure the input is a valid BCH address.
try {
- const cash = utils.toCashAddress(address)
+ const cash = bchjs.SLP.Address.toCashAddress(address)
} catch (err) {
res.status(400)
return res.json({
@@ -384,7 +376,7 @@ async function balancesForAddress(req, res, next) {
}
// Prevent a common user error. Ensure they are using the correct network address.
- const cashAddr = utils.toCashAddress(address)
+ const cashAddr = bchjs.SLP.Address.toCashAddress(address)
const networkIsValid = routeUtils.validateNetwork(cashAddr)
if (!networkIsValid) {
res.status(400)
@@ -398,7 +390,7 @@ async function balancesForAddress(req, res, next) {
q: {
db: ["a"],
find: {
- address: SLP.Address.toSLPAddress(address),
+ address: bchjs.SLP.Address.toSLPAddress(address),
token_balance: { $gte: 0 }
},
limit: 10000
@@ -481,7 +473,7 @@ async function balancesForAddress(req, res, next) {
res.status(500)
return res.json({
- error: `Error in /ddress/:address: ${err.message}`
+ error: `Error in /address/:address: ${err.message}`
})
}
}
@@ -533,7 +525,7 @@ async function balancesForAddressBulk(req, res, next) {
// Ensure the input is a valid BCH address.
try {
- utils.toCashAddress(address)
+ bchjs.SLP.Address.toCashAddress(address)
} catch (err) {
res.status(400)
return res.json({
@@ -542,7 +534,7 @@ async function balancesForAddressBulk(req, res, next) {
}
// Prevent a common user error. Ensure they are using the correct network address.
- const cashAddr = utils.toCashAddress(address)
+ const cashAddr = bchjs.SLP.Address.toCashAddress(address)
const networkIsValid = routeUtils.validateNetwork(cashAddr)
if (!networkIsValid) {
res.status(400)
@@ -561,7 +553,7 @@ async function balancesForAddressBulk(req, res, next) {
q: {
db: ["a"],
find: {
- address: SLP.Address.toSLPAddress(address),
+ address: bchjs.SLP.Address.toSLPAddress(address),
token_balance: { $gte: 0 }
},
limit: 10000
@@ -1210,8 +1202,9 @@ async function txDetails(req, res, next) {
// console.log(`formatted: ${JSON.stringify(formatted,null,2)}`)
// Get information on the transaction from Insight API.
- const retData = await transactions.transactionsFromInsight(txid)
- // console.log(`retData: ${JSON.stringify(retData,null,2)}`)
+ // const retData = await transactions.transactionsFromInsight(txid)
+ const retData = await rawtransactions.getRawTransactionsFromNode(txid, true)
+ // console.log(`retData: ${JSON.stringify(retData, null, 2)}`)
// Return both the tx data from Insight and the formatted token information.
const response = {
diff --git a/src/routes/v3/xpub.js b/src/routes/v3/xpub.js
index d7da89a..142a75e 100644
--- a/src/routes/v3/xpub.js
+++ b/src/routes/v3/xpub.js
@@ -5,7 +5,6 @@
"use strict"
const express = require("express")
-const requestUtils = require("./services/requestUtils")
const axios = require("axios")
const routeUtils = require("./route-utils")
const wlogger = require("../../util/winston-logging")
diff --git a/start-dev-example.sh b/start-dev-example.sh
index 50934c5..4d0ae09 100755
--- a/start-dev-example.sh
+++ b/start-dev-example.sh
@@ -1,21 +1,15 @@
#!/bin/bash
-# Harddrive Mainnet full node
+# Full node
export RPC_BASEURL=http://:8332/
export RPC_USERNAME=
export RPC_PASSWORD=
export NETWORK=mainnet
-# Team DO QA Testnet Insight Server
-export BITCOINCOM_BASEURL=http://:12100/api/
-
-# Testnet SLPDB
+# SLPDB
export SLPDB_URL=http://:12300/
-# Testnet Bitcore Node API
-export BITCORE_URL=http://:12200/
-
-# Testnet Blockbook
+# Blockbook
export BLOCKBOOK_URL=https://:9131/
# Allow node.js to make network calls to https using self-signed certificate.
export NODE_TLS_REJECT_UNAUTHORIZED=0
diff --git a/test/v2/address.js b/test/v2/address.js
deleted file mode 100644
index 070c5d9..0000000
--- a/test/v2/address.js
+++ /dev/null
@@ -1,1373 +0,0 @@
-/*
- TESTS FOR THE ADDRESS.JS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- To-Do:
- -/details/:address
- --Verify to/from query options work correctly.
- -GET /unconfirmed/:address & POST /unconfirmed
- --Should initiate a transfer of BCH to verify unconfirmed TX.
- ---This would be more of an e2e test.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const addressRoute = require("../../src/routes/v2/address")
-const nock = require("nock") // HTTP mocking
-
-let originalUrl // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/address-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#AddressRouter", () => {
- let req, res
-
- before(() => {
- originalUrl = process.env.BITCOINCOM_BASEURL
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit")
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- // console.log(`Testing type is: ${process.env.TEST}`)
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- process.env.BITCOINCOM_BASEURL = originalUrl
- })
-
- describe("#root", () => {
- // root route handler.
- const root = addressRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "address", "Returns static string")
- })
- })
-
- describe("#AddressDetailsBulk", () => {
- // details route handler.
- const detailsBulk = addressRoute.testableComponents.detailsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsBulk(req, res)
- //console.log(`network issue result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 500 expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page defaults to 0
- assert.equal(result[0].currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`],
- page: 5
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=5000&to=6000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page is same as requested
- assert.equal(result[0].currentPage, 5)
- })
-
- it("should calculate the total number of pages", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result[0].pagesTotal, 1)
- })
-
- it("should get details for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "balance",
- "balanceSat",
- "totalReceived",
- "totalReceivedSat",
- "totalSent",
- "totalSentSat",
- "unconfirmedBalance",
- "unconfirmedBalanceSat",
- "unconfirmedTxApperances",
- "txApperances",
- "transactions",
- "legacyAddress",
- "cashAddress",
- "currentPage",
- "pagesTotal"
- ])
- })
-
- it("should get details for multiple addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mwJnEzXzKkveF2q5Af9jxi9j1zrtWAnPU8?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-
- describe("#AddressDetailsSingle", () => {
- // details route handler.
- const detailsSingle = addressRoute.testableComponents.detailsSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page defaults to 0
- assert.equal(result.currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
- req.query.page = 5
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=5000&to=6000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
-
- // Assert current page is same as requested
- assert.equal(result.currentPage, 5)
- })
-
- it("should calculate the total number of pages", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
-
- assert.equal(result.pagesTotal, 1)
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz?from=0&to=1000`)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.hasAllKeys(result, [
- "balance",
- "balanceSat",
- "totalReceived",
- "totalReceivedSat",
- "totalSent",
- "totalSentSat",
- "unconfirmedBalance",
- "unconfirmedBalanceSat",
- "unconfirmedTxApperances",
- "txApperances",
- "transactions",
- "legacyAddress",
- "cashAddress",
- "currentPage",
- "pagesTotal"
- ])
- })
- })
-
- describe("#AddressUtxoBulk", () => {
- // utxo route handler.
- const utxoBulk = addressRoute.testableComponents.utxoBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await utxoBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get utxos for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result, "result should be an array")
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result[0], [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- // Validate the UTXO data structure.
- assert.hasAnyKeys(result[0].utxos[0], [
- "txid",
- "vout",
- "amount",
- "satoshis",
- "height",
- "confirmations"
- ])
- })
-
- it("should get utxos for mulitple addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mwJnEzXzKkveF2q5Af9jxi9j1zrtWAnPU8/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
- })
-
- describe("#AddressUtxoSingle", () => {
- // details route handler.
- const utxoSingle = addressRoute.testableComponents.utxoSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await utxoSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await utxoSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result, [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- // Validate the UTXO data structure.
- assert.hasAnyKeys(result.utxos[0], [
- "txid",
- "vout",
- "amount",
- "satoshis",
- "height",
- "confirmations"
- ])
- })
- })
-
- describe("#AddressUnconfirmedBulk", () => {
- // unconfirmed route handler.
- const unconfirmedBulk = addressRoute.testableComponents.unconfirmedBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await unconfirmedBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await unconfirmedBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get unconfirmed data for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
- //console.log(`result[0].utxos: ${util.inspect(result[0].utxos)}`)
-
- assert.isArray(result, "result should be an array")
-
- // Dev note: Unconfirmed TXs are hard to test in an integration test because
- // the nature of an unconfirmed transation is transient. It quickly becomes
- // confirmed and thus should not show up.
- })
-
- it("should get unconfirmed data for an array of addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mwJnEzXzKkveF2q5Af9jxi9j1zrtWAnPU8/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedBulk(req, res)
-
- assert.isArray(result)
- })
- })
-
- describe("#AddressUnconfirmedSingle", () => {
- // details route handler.
- const unconfirmedSingle = addressRoute.testableComponents.unconfirmedSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await unconfirmedSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await unconfirmedSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/addr/mgps7qxk2Z5ma4mXsviznnet8wx4VvMPFz/utxo`)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result, [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- assert.isArray(result.utxos)
- })
- })
-
- describe("#AddressTransactionsBulk", () => {
- // unconfirmed route handler.
- const transactionsBulk = addressRoute.testableComponents.transactionsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await transactionsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await transactionsBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsBulk(req, res)
-
- // Assert current page defaults to 0
- assert.equal(result[0].currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`],
- page: 5
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=5`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsBulk(req, res)
-
- // Assert current page is same as requested
- assert.equal(result[0].currentPage, 5)
- })
-
- it("should get transactions for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsBulk(req, res)
-
- assert.isArray(result, "result should be an array")
-
- assert.exists(result[0].pagesTotal)
- assert.exists(result[0].currentPage)
- assert.exists(result[0].txs)
- assert.isArray(result[0].txs)
- assert.exists(result[0].legacyAddress)
- assert.exists(result[0].cashAddress)
- })
-
- it("should get transactions for an array of addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsBulk(req, res)
-
- assert.isArray(result, "result should be an array")
-
- assert.equal(result.length, 2, "Array should have 2 elements")
- })
- })
-
- describe("#AddressTransactionsSingle", () => {
- // details route handler.
- const transactionsSingle =
- addressRoute.testableComponents.transactionsSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await transactionsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await transactionsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsSingle(req, res)
-
- // Assert current page defaults to 0
- assert.equal(result.currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
- req.query.page = 5
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=5`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsSingle(req, res)
-
- // Assert current page is same as requested
- assert.equal(result.currentPage, 5)
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- )
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.exists(result.pagesTotal)
- assert.exists(result.currentPage)
- assert.exists(result.txs)
- assert.isArray(result.txs)
- assert.exists(result.legacyAddress)
- assert.exists(result.cashAddress)
- })
- })
-
- describe("#AddressFromXPubSingle", () => {
- // details route handler.
- const fromXPubSingle = addressRoute.testableComponents.fromXPubSingle
-
- it("should throw 400 if xpub is empty", async () => {
- const result = await fromXPubSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "xpub can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.xpub = [
- `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
- ]
-
- const result = await fromXPubSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "xpub can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.xpub = `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await fromXPubSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should create an address from xpub", async () => {
- req.params.xpub = `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
-
- // Mock the Insight URL for unit tests.
- // TODO add unit test
- // if (process.env.TEST === "unit") {
- // nock(`${process.env.BITCOINCOM_BASEURL}`)
- // .get(
- // `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- // )
- // .reply(200, mockData.mockTransactions)
- // }
-
- // Call the details API.
- const result = await fromXPubSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.exists(result.legacyAddress)
- assert.exists(result.cashAddress)
- })
- })
-})
diff --git a/test/v2/block.js b/test/v2/block.js
deleted file mode 100644
index 3817e62..0000000
--- a/test/v2/block.js
+++ /dev/null
@@ -1,610 +0,0 @@
-"use strict"
-
-const blockRoute = require("../../src/routes/v2/block")
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/block-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Block", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", () => {
- // root route handler.
- const root = blockRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "block", "Returns static string")
- })
- })
-
- describe("#detailsByHashSingle", () => {
- const detailsByHash = blockRoute.testableComponents.detailsByHashSingle
-
- it("should throw an error for an empty hash", async () => {
- req.params.hash = ""
-
- const result = await detailsByHash(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hash must not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 50X when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- req.params.hash = "abc123"
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 50X expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should throw an error for invalid hash", async () => {
- req.params.hash = "abc123"
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.params.hash}`)
- .reply(404, "Not found")
- }
-
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.include(result.error, "Not found", "Proper error message")
- })
-
- it("should GET /detailsByHash/:hash", async () => {
- req.params.hash =
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.params.hash}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hash",
- "size",
- "height",
- "version",
- "merkleroot",
- "tx",
- "time",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "confirmations",
- "previousblockhash",
- "nextblockhash",
- "reward",
- "isMainChain",
- "poolInfo"
- ])
- assert.isArray(result.tx)
- })
- })
-
- describe("#detailsByHashBulk", () => {
- // details route handler.
- const detailsByHashBulk = blockRoute.testableComponents.detailsByHashBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsByHashBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- hashes:
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
- }
-
- const result = await detailsByHashBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hashes = testArray
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid hash", async () => {
- req.body = {
- hashes: [`abc123`]
- }
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid hash", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- hashes: [
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
- ]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsByHashBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single hash", async () => {
- req.body = {
- hashes: [
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "bits",
- "chainwork",
- "confirmations",
- "difficulty",
- "hash",
- "height",
- "isMainChain",
- "merkleroot",
- "nextblockhash",
- "nonce",
- "poolInfo",
- "previousblockhash",
- "reward",
- "size",
- "time",
- "tx",
- "version"
- ])
- })
-
- it("should get details for multiple hashes", async () => {
- req.body = {
- hashes: [
- `00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79`,
- `00000000c2b2c19cf499f57d5b0f724c6df753330d7acc7d4a8ebe412d427bd0`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- .reply(200, mockData.mockBlockDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[1]}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
-
- it("should throw an error if hash not found", async () => {
- req.body = {
- hashes: [
- `00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44abcdef`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- //.reply(404, { error: { message: "Not Found" } })
- .reply(404, "Not found")
- }
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 404, "HTTP status code 404 expected.")
- assert.include(result.error, "Not found", "Proper error message")
- })
- })
-
- describe("Block Details By Height", () => {
- // block route handler.
- const detailsByHeight = blockRoute.testableComponents.detailsByHeightSingle
-
- it("should throw an error for an empty height", async () => {
- req.params.height = ""
-
- const result = await detailsByHeight(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "height must not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.height = "abc123"
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or great expected."
- )
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should throw an error for invalid height", async () => {
- req.params.height = "abc123"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: {
- code: -1,
- message: "JSON value is not an integer as expected"
- }
- })
- }
-
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "JSON value is not an integer as expected",
- "Proper error message"
- )
- })
-
- it("should GET /detailsByHeight/:height", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHash })
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/block/00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79`
- )
- .reply(200, mockData.mockBlockDetails)
- }
-
- req.params.height = 500000
-
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hash",
- "size",
- "height",
- "version",
- "merkleroot",
- "tx",
- "time",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "confirmations",
- "previousblockhash",
- "nextblockhash",
- "reward",
- "isMainChain",
- "poolInfo"
- ])
- assert.isArray(result.tx)
- })
- })
-
- describe("#detailsByHeightBulk", () => {
- // details route handler.
- const detailsByHeightBulk =
- blockRoute.testableComponents.detailsByHeightBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsByHeightBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "heights needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single height", async () => {
- req.body = {
- heights: 500000
- }
-
- const result = await detailsByHeightBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "heights needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.heights = testArray
-
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw error for an invalid height", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: {
- code: -1,
- message: "JSON value is not an integer as expected"
- }
- })
- }
-
- req.body.heights = [`abc123`]
-
- const result = await detailsByHeightBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body.heights = [`500000`]
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsByHeightBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single height", async () => {
- req.body.heights = [`500000`]
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHash })
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${mockData.mockBlockHash}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "bits",
- "chainwork",
- "confirmations",
- "difficulty",
- "hash",
- "height",
- "isMainChain",
- "merkleroot",
- "nextblockhash",
- "nonce",
- "poolInfo",
- "previousblockhash",
- "reward",
- "size",
- "time",
- "tx",
- "version"
- ])
- })
-
- it("should get details for multiple block heights", async () => {
- req.body = {
- heights: [`500000`, `500001`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockBlockHash })
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${mockData.mockBlockHash}`)
- .times(2)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-})
diff --git a/test/v2/blockchain.js b/test/v2/blockchain.js
deleted file mode 100644
index a2b4458..0000000
--- a/test/v2/blockchain.js
+++ /dev/null
@@ -1,1148 +0,0 @@
-/*
- TODO:
- -getRawMempool
- --Add tests for 'verbose' input values
- -getMempoolEntry & getMempoolEntryBulk
- --Needs e2e test to create unconfirmed tx, for real-world test.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-const blockchainRoute = require("../../src/routes/v2/blockchain")
-
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-if (!process.env.TEST) process.env.TEST = "unit"
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/blockchain-mock")
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-describe("#BlockchainRouter", () => {
- let req, res
-
- // local node will be started in regtest mode on the port 48332
- //before(panda.runLocalNode)
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // otherwise the panda will run forever
- //process.exit()
-
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", () => {
- // root route handler.
- const root = blockchainRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "blockchain", "Returns static string")
- })
- })
-
- describe("getBestBlockHash()", () => {
- // block route handler.
- const getBestBlockHash = blockchainRoute.testableComponents.getBestBlockHash
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getBestBlockHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getBestBlockHash", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHash })
- }
-
- const result = await getBestBlockHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isString(result)
- assert.equal(result.length, 64, "Hash string is fixed length")
- })
- })
-
- describe("getBlockchainInfo()", () => {
- // block route handler.
- const getBlockchainInfo =
- blockchainRoute.testableComponents.getBlockchainInfo
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getBlockchainInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getBlockchainInfo", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockchainInfo })
- }
-
- const result = await getBlockchainInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "chain",
- "blocks",
- "headers",
- "bestblockhash",
- "difficulty",
- "mediantime",
- "verificationprogress",
- "chainwork",
- "pruned",
- "softforks",
- "bip9_softforks"
- ])
- })
- })
-
- describe("getBlockCount()", () => {
- // block route handler.
- const getBlockCount = blockchainRoute.testableComponents.getBlockCount
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getBlockCount(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getBlockCount", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: 126769 })
- }
-
- const result = await getBlockCount(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isNumber(result)
- })
- })
-
- describe("getBlockHeaderSingle()", async () => {
- const getBlockHeader =
- blockchainRoute.testableComponents.getBlockHeaderSingle
-
- it("should throw 400 error if hash is missing", async () => {
- const result = await getBlockHeader(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hash can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.hash =
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
-
- const result = await getBlockHeader(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Network error: Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET block header", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, {
- result:
- "0000ff7f7d217c9b7845ea8b50d620c59a1bf7c276566406e9b7bc7e463e0000000000006d70322c0b697c1c81d2744f87f09f1e9780ba5d30338952e2cdc64e60456f8423bb0a5ceafa091a3e843526"
- })
- }
-
- req.params.hash =
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
-
- const result = await getBlockHeader(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isString(result)
- assert.equal(
- result,
- "0000ff7f7d217c9b7845ea8b50d620c59a1bf7c276566406e9b7bc7e463e0000000000006d70322c0b697c1c81d2744f87f09f1e9780ba5d30338952e2cdc64e60456f8423bb0a5ceafa091a3e843526"
- )
- })
-
- it("should GET verbose block header", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHeader })
- }
-
- req.query.verbose = true
- req.params.hash =
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
-
- const result = await getBlockHeader(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "hash",
- "confirmations",
- "height",
- "version",
- "versionHex",
- "merkleroot",
- "time",
- "mediantime",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "previousblockhash",
- "nextblockhash"
- ])
- })
- })
-
- describe("#getBlockHeaderBulk", () => {
- // route handler.
- const getBlockHeaderBulk =
- blockchainRoute.testableComponents.getBlockHeaderBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await getBlockHeaderBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single hash", async () => {
- req.body.hashes =
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
-
- const result = await getBlockHeaderBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hashes = testArray
-
- const result = await getBlockHeaderBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw a 400 error for an invalid hash", async () => {
- req.body.hashes = ["badHash"]
-
- await getBlockHeaderBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body.hashes = [
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
- ]
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await getBlockHeaderBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get concise block header for a single hash", async () => {
- req.body.hashes = [
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
- ]
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHeaderConcise })
- }
-
- // Call the details API.
- const result = await getBlockHeaderBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.isArray(result)
- assert.equal(
- result[0],
- "0000ff7f7d217c9b7845ea8b50d620c59a1bf7c276566406e9b7bc7e463e0000000000006d70322c0b697c1c81d2744f87f09f1e9780ba5d30338952e2cdc64e60456f8423bb0a5ceafa091a3e843526"
- )
- })
-
- it("should get verbose block header for a single hash", async () => {
- req.body = {
- hashes: [
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
- ],
- verbose: true
- }
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockBlockHeader })
- }
-
- // Call the details API.
- const result = await getBlockHeaderBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "hash",
- "confirmations",
- "height",
- "version",
- "versionHex",
- "merkleroot",
- "time",
- "mediantime",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "previousblockhash",
- "nextblockhash"
- ])
- })
-
- it("should get details for multiple block heights", async () => {
- req.body.hashes = [
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900",
- "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900"
- ]
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockBlockHeaderConcise })
- }
-
- // Call the details API.
- const result = await getBlockHeaderBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-
- describe("getChainTips()", () => {
- // block route handler.
- const getChainTips = blockchainRoute.testableComponents.getChainTips
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getChainTips(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getChainTips", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockChainTips })
- }
-
- const result = await getChainTips(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], ["height", "hash", "branchlen", "status"])
- })
- })
-
- describe("getDifficulty()", () => {
- // block route handler.
- const getDifficulty = blockchainRoute.testableComponents.getDifficulty
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getDifficulty(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getDifficulty", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: 4049809.205246544 })
- }
-
- const result = await getDifficulty(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isNumber(result)
- })
- })
-
- describe("getMempoolInfo()", () => {
- // block route handler.
- const getMempoolInfo = blockchainRoute.testableComponents.getMempoolInfo
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getMempoolInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getMempoolInfo", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockMempoolInfo })
- }
-
- const result = await getMempoolInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "result",
- "bytes",
- "usage",
- "maxmempool",
- "mempoolminfree"
- ])
- })
- })
-
- describe("getRawMempool()", () => {
- // block route handler.
- const getRawMempool = blockchainRoute.testableComponents.getRawMempool
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getRawMempool(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getMempoolInfo", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawMempool })
- }
-
- const result = await getRawMempool(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- // Not sure what other assertions should be made here.
- })
- })
-
- describe("getMempoolEntry()", () => {
- // block route handler.
- const getMempoolEntry =
- blockchainRoute.testableComponents.getMempoolEntrySingle
-
- it("should throw 400 if txid is empty", async () => {
- const result = await getMempoolEntry(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getMempoolEntry(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getMempoolEntry", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: { error: "Transaction not in mempool" } })
- }
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getMempoolEntry(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.isString(result.error)
- assert.equal(result.error, "Transaction not in mempool")
- })
- })
-
- describe("#getMempoolEntryBulk", () => {
- // route handler.
- const getMempoolEntryBulk =
- blockchainRoute.testableComponents.getMempoolEntryBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await getMempoolEntryBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body.txids = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getMempoolEntryBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.txids = testArray
-
- const result = await getMempoolEntryBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- // Only execute on integration tests.
- if (process.env.TEST !== "unit") {
- // Dev-note: This test passes because it expects an error. TXIDs do not
- // stay in the mempool for long, so it does not work well for a unit or
- // integration test.
- it("should retrieve single mempool entry", async () => {
- req.body.txids = [
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- ]
-
- const result = await getMempoolEntryBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.isString(result.error)
- assert.equal(result.error, "Transaction not in mempool")
- })
-
- // Dev-note: This test passes because it expects an error. TXIDs do not
- // stay in the mempool for long, so it does not work well for a unit or
- // integration test.
- it("should retrieve multiple mempool entries", async () => {
- req.body.txids = [
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`,
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- ]
-
- const result = await getMempoolEntryBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.isString(result.error)
- assert.equal(result.error, "Transaction not in mempool")
- })
- }
- })
-
- describe("getTxOut()", () => {
- // block route handler.
- const getTxOut = blockchainRoute.testableComponents.getTxOut
-
- it("should throw 400 if txid is empty", async () => {
- const result = await getTxOut(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 400 if n is empty", async () => {
- req.params.txid = `sometxid`
- const result = await getTxOut(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "n can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- req.params.n = 0
-
- const result = await getTxOut(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- // This test can only run for unit tests. See TODO at the top of this file.
- it("should GET /getTxOut", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockTxOut })
- }
-
- req.params.txid = `5747e6462e2c452a5d583fd6a5f82866cd8e4a86826c86d9a1842b7d023e0c0c`
- req.params.n = 1
-
- const result = await getTxOut(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.hasAllKeys(result, [
- "bestblock",
- "confirmations",
- "value",
- "scriptPubKey",
- "coinbase"
- ])
- assert.hasAllKeys(result.scriptPubKey, [
- "asm",
- "hex",
- "reqSigs",
- "type",
- "addresses"
- ])
- assert.isArray(result.scriptPubKey.addresses)
- })
- })
-
- describe("getTxOutProof()", () => {
- const getTxOutProof = blockchainRoute.testableComponents.getTxOutProofSingle
-
- it("should throw 400 if txid is empty", async () => {
- const result = await getTxOutProof(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getTxOutProof(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /getTxOutProof", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockTxOutProof })
- }
-
- req.params.txid = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getTxOutProof(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isString(result)
- })
- })
-
- describe("#getTxOutProofBulk", () => {
- // route handler.
- const getTxOutProofBulk =
- blockchainRoute.testableComponents.getTxOutProofBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await getTxOutProofBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body.txids = `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
-
- const result = await getTxOutProofBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.txids = testArray
-
- const result = await getTxOutProofBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should GET proof for single txid", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockTxOutProof })
- }
-
- req.body.txids = [
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- ]
-
- const result = await getTxOutProofBulk(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- })
-
- it("should GET proof for multiple txids", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockTxOutProof })
- }
-
- req.body.txids = [
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`,
- `d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde`
- ]
-
- const result = await getTxOutProofBulk(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "Correct length of returned array")
- })
- })
-
- describe("verifyTxOutProof()", () => {
- const verifyTxOutProof =
- blockchainRoute.testableComponents.verifyTxOutProofSingle
-
- it("should throw 400 if proof is empty", async () => {
- const result = await verifyTxOutProof(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "proof can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.proof = mockData.mockTxOutProof
-
- const result = await verifyTxOutProof(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
- assert.include(
- result.error,
- "Could not communicate with full node",
- "Error message expected"
- )
- })
-
- it("should GET /verifyTxOutProof", async () => {
- const expected =
- "d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: [expected] })
- }
-
- req.params.proof = mockData.mockTxOutProof
-
- const result = await verifyTxOutProof(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- assert.equal(result[0], expected)
- })
- })
-
- describe("#verifyTxOutProofBulk", () => {
- // route handler.
- const verifyTxOutProofBulk =
- blockchainRoute.testableComponents.verifyTxOutProofBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await verifyTxOutProofBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "proofs needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body.proofs = mockData.mockTxOutProof
-
- const result = await verifyTxOutProofBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "proofs needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.proofs = testArray
-
- const result = await verifyTxOutProofBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should get single proof", async () => {
- const expected =
- "d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: [expected] })
- }
-
- req.body.proofs = [mockData.mockTxOutProof]
-
- const result = await verifyTxOutProofBulk(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- assert.equal(result[0], expected)
- })
-
- it("should get multiple proofs", async () => {
- const expected =
- "d65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: [expected] })
- }
-
- req.body.proofs = [mockData.mockTxOutProof, mockData.mockTxOutProof]
-
- const result = await verifyTxOutProofBulk(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- assert.equal(result[0], expected)
- assert.equal(result.length, 2)
- })
- })
-})
diff --git a/test/v2/control.js b/test/v2/control.js
deleted file mode 100644
index e5deaa9..0000000
--- a/test/v2/control.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- TESTS FOR THE CONTROL.JS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const controlRoute = require("../../src/routes/v2/control")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/control-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#ControlRouter", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = controlRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "control", "Returns static string")
- })
- })
-
- describe("#GetInfo", () => {
- const getInfo = controlRoute.testableComponents.getInfo
-
- it("should throw 500 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should get info on the full node", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockGetInfo })
- }
-
- const result = await getInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "version",
- "protocolversion",
- "blocks",
- "timeoffset",
- "connections",
- "proxy",
- "difficulty",
- "testnet",
- "paytxfee",
- "relayfee",
- "errors"
- ])
- })
- })
-})
diff --git a/test/v2/e2e/address.js b/test/v2/e2e/address.js
deleted file mode 100644
index 878ad9e..0000000
--- a/test/v2/e2e/address.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- End-to-end tests for the Address endpoint.
- These tests assume that the repo is running locally and pointed at TESTNET
-*/
-
-"use strict"
-
-const rp = require("request-promise")
-
-const rawtransactions = require("../../../dist/routes/v2/address")
-
-/*
- This unconfirmed utxo test needs to be expanded in the future to automatically
- create a transaction. For now, that is done manually and the address provided
- as a constant.
-
- 1. Start rest running locally, pointed at TESTNET.
- 2. Fund each address with a small amount of tBCH
- 3. Run this program with `node address.js`
- 4. If successful, it will return the unconfirmed UTXOs.
-*/
-const addr1 = "bchtest:qpdcp5pv7qphu5tsjfgwezld9n9aq9ue6swgqpf45c"
-const addr2 = "bchtest:qzpvx999fagau0xqmvu3xvll9evapge7u5hcgeknzv"
-
-async function testSingleUnconfirmed() {
- try {
- const options = {
- method: "GET",
- uri: `http://localhost:3000/v2/address/unconfirmed/${addr1}`,
- resolveWithFullResponse: true,
- json: true
- }
-
- const result = await rp(options)
- // console.log(`result.body: ${JSON.stringify(result.body, null, 2)}`)
- } catch (err) {
- // console.log(`Error: `, err)
- }
-}
-testSingleUnconfirmed()
-
-async function testDoubleUnconfirmed() {
- try {
- const options = {
- method: "POST",
- uri: `http://localhost:3000/v2/address/unconfirmed`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- addresses: [addr1, addr2]
- }
- }
-
- const result = await rp(options)
- // console.log(`result.body: ${JSON.stringify(result.body, null, 2)}`)
- } catch (err) {
- // console.log(`Error: `, err)
- }
-}
-testDoubleUnconfirmed()
diff --git a/test/v2/helpers/panda.js b/test/v2/helpers/panda.js
deleted file mode 100644
index 48a7d7f..0000000
--- a/test/v2/helpers/panda.js
+++ /dev/null
@@ -1,29 +0,0 @@
-"use strict"
-
-/**
- * Read more about panda here: https://panda-suite.github.io/
- */
-const panda = require("pandacash-core")
-
-const runLocalNode = done => {
- const server = panda.server({
- // always the same mnemonic
- // mnemonic: "cigar magnet ocean purchase travel damp snack alone theme budget wagon wrong",
- seedAccounts: true,
- enableLogs: false,
- debug: false
- })
-
- server.listen({
- port: 48332,
- walletPort: 48333,
- }, (err, pandaCashCore) => {
- if (err) return console.error(err)
-
- done()
- })
-}
-
-module.exports = {
- runLocalNode
-}
diff --git a/test/v2/integration/README.md b/test/v2/integration/README.md
deleted file mode 100644
index 3bd22f8..0000000
--- a/test/v2/integration/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-This directory contains integration tests. To run them requires that
-a local copy of rest.bitcoin.com is running. The tests in this directory are
-exactly the same calls that end users would use for their app to interact
-directly with rest.bitcoin.com.
-
-At present, this directory focuses on raw-transations. But more integration tests
-will be added.
diff --git a/test/v2/integration/rate-limits.js b/test/v2/integration/rate-limits.js
deleted file mode 100644
index b61c25e..0000000
--- a/test/v2/integration/rate-limits.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- */
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const axios = require("axios")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const SERVER = `https://rest.btctest.net/v2/`
-//const SERVER = `http://localhost:3000/v2/`
-
-describe("#rate limits", () => {
- it("should get control/getInfo() with no auth", async () => {
- const options = {
- method: "GET",
- url: `${SERVER}control/getInfo`
- }
-
- const result = await axios(options)
- //console.log(`result.status: ${result.status}`)
- //console.log(`result.data: ${util.inspect(result.data)}`)
-
- assert.equal(result.status, 200)
- assert.hasAnyKeys(result.data, ["version"])
- })
-
- it("should trigger rate-limit handler if rate limits exceeds 60 request per minute", async () => {
- try {
- // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
- const options = {
- method: "GET",
- url: `${SERVER}control/getInfo`
- }
-
- const promises = []
- for (let i = 0; i < 250; i++) {
- const promise = axios(options)
- promises.push(promise)
- }
-
- await Promise.all(promises)
-
- assert.equal(true, false, "Unexpected result!")
- } catch (err) {
- //console.log(`err.response: ${util.inspect(err.response)}`)
-
- assert.equal(err.response.status, 429)
- assert.include(err.response.data.error, "Too many requests")
- }
- })
-
- it("should not trigger rate-limit handler if correct pro-tier password is used", async () => {
- try {
- const username = "BITBOX"
-
- // Pro-tier is accessed by using the right password.
- const password = "BITBOX"
- //const password = "something"
-
- const combined = `${username}:${password}`
- const base64Credential = Buffer.from(combined).toString("base64")
- const readyCredential = `Basic ${base64Credential}`
-
- const options = {
- method: "GET",
- url: `${SERVER}control/getInfo`,
- headers: { Authorization: readyCredential }
- }
-
- const promises = []
- for (let i = 0; i < 250; i++) {
- const promise = axios(options)
- promises.push(promise)
- }
-
- await Promise.all(promises)
-
- assert.equal(true, true, "Not throwing an error is a pass!")
- } catch (err) {
- // console.log(`err.response: ${util.inspect(err.response)}`)
-
- assert.equal(
- true,
- false,
- "This error handler should not have been triggered. Is the password correct?"
- )
- }
- })
-})
diff --git a/test/v2/integration/raw-transactions.js b/test/v2/integration/raw-transactions.js
deleted file mode 100644
index 7c17347..0000000
--- a/test/v2/integration/raw-transactions.js
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- These integration tests are intended to be run against a live local copy of
- rest.bitcoin.com. They exercise the endpoints in the same way the SDK or
- end-user application would. These tests were created to replace the parts
- removed from the swagger UI, that otherwise would have excersiced these endpoints.
-
- TODO:
- -/rawtransactions/sendRawTransaction is more appropropriate for an e2e test,
- so it is omitted here.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const rawtransactions = require("../../../dist/routes/v2/rawtransactions")
-const rp = require("request-promise")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-const mockData = require("../mocks/raw-transactions-mocks")
-
-describe("#Raw-Transactions", () => {
- describe("#root", () => {
- it(`should return root`, async () => {
- const options = {
- method: "GET",
- uri: `http://localhost:3000/v2/rawtransactions/`,
- resolveWithFullResponse: true,
- json: true
- }
-
- const result = await rp(options)
- //console.log(`result: ${JSON.stringify(result, null, 0)}`)
-
- assert.equal(result.body.status, "rawtransactions")
- })
- })
-
- describe("#whCreateTx", () => {
- it(`should return tx hex`, async () => {
- const minIn = {
- txid:
- "f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2",
- vout: 1
- }
-
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/create`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- //inputs: [mockData.mockWHCreateInput],
- inputs: [minIn],
- outputs: {}
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.equal(
- result.body,
- "0200000001b29af9aaf74f82ad7ff181fcc6f3d2cf5fa701a1c969620f9185ee3df29cedf70100000000ffffffff0000000000"
- )
- })
- })
-
- describe("#whOpReturn", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/opreturn`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- rawtx: "01000000000000000000",
- payload: "00000000000000020000000006dac2c0"
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.equal(
- result.body,
- "0100000000010000000000000000166a140877686300000000000000020000000006dac2c000000000"
- )
- })
- })
-
- describe("#whReference", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/reference`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- rawtx:
- "0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff03aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a5121f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000",
- destination: "bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf",
- amount: 0.005
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.isString(result.body)
- })
- })
-
- describe("#whChangeOutput", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/change`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- rawtx:
- "0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff025c0d00000000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000",
- destination: "bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf",
- prevtxs: [
- {
- txid:
- "6779a710fcd5f6fb0883ea3306360c3ad8c0a3c5de902768ec57ef3104e65eb1",
- vout: 4,
- scriptPubKey:
- "76a9147b25205fd98d462880a3e5b0541235831ae959e588ac",
- value: 0.00068257
- }
- ],
- fee: 0.000035
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.isString(result.body)
- })
- })
-
- describe("#whInput", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "PUT",
- uri: `http://localhost:3000/v2/rawtransactions/input`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- txid:
- "b006729017df05eda586df9ad3f8ccfee5be340aadf88155b784d1fc0e8342ee",
- n: 0
- }
- }
-
- const result = await rp(options)
- //console.log(`result.body: ${JSON.stringify(result.body, null, 0)}`)
-
- assert.isString(result.body)
- })
- })
-
- describe("#getRawTransaction", () => {
- it(`should return tx hex`, async () => {
- const options = {
- method: "POST",
- uri: `http://localhost:3000/v2/rawtransactions/getRawTransaction`,
- resolveWithFullResponse: true,
- json: true,
- body: {
- txids: [
- "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"
- ],
- verbose: true
- }
- }
-
- const result = await rp(options)
- // console.log(`result.body: ${util.inspect(result.body)}`)
-
- assert.isArray(result.body)
- })
- })
-})
diff --git a/test/v2/mining.js b/test/v2/mining.js
deleted file mode 100644
index 14e1163..0000000
--- a/test/v2/mining.js
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- TESTS FOR THE MINING.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const miningRoute = require("../../src/routes/v2/mining")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/mining-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Mining", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = miningRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "mining", "Returns static string")
- })
- })
-
- describe("#getMiningInfo", async () => {
- const getMiningInfo = miningRoute.testableComponents.getMiningInfo
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getMiningInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET mining information", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockMiningInfo })
- }
-
- const result = await getMiningInfo(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "blocks",
- "currentblocksize",
- "currentblocktx",
- "difficulty",
- "blockprioritypercentage",
- "errors",
- "networkhashps",
- "pooledtx",
- "chain"
- ])
- })
- })
-
- describe("#getNetworkHashPS", async () => {
- const getNetworkHashPS = miningRoute.testableComponents.getNetworkHashPS
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- const result = await getNetworkHashPS(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET Network Hash per second", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: 517604755.6648782 })
- }
-
- const result = await getNetworkHashPS(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isNumber(result)
- })
- })
-})
diff --git a/test/v2/mocks/address-mock.js b/test/v2/mocks/address-mock.js
deleted file mode 100644
index 7d4e3b9..0000000
--- a/test/v2/mocks/address-mock.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockAddressDetails = {
- addrStr: "1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W",
- balance: 0.00126419,
- balanceSat: 126419,
- totalReceived: 0.02175868,
- totalReceivedSat: 2175868,
- totalSent: 0.02049449,
- totalSentSat: 2049449,
- unconfirmedBalance: 0,
- unconfirmedBalanceSat: 0,
- unconfirmedTxApperances: 0,
- txApperances: 3,
- transactions: [
- "2dc053f55a666a3d2a08b1c680b704d62a55506d14ad884add87edcc56b9277d",
- "544c15ce35c0f2e808d28f29d6587f1ec9276233e29856b7f2938cf0daef0026",
- "81039b1d7b855b133f359f9dc65f776bd105650153a941675fedc504228ddbd3"
- ],
- legacyAddress: "1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W",
- cashAddress: "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
-}
-
-const mockUtxoDetails = [
- {
- txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
- vout: 286,
- amount: 0.00001,
- satoshis: 1000,
- height: 546083,
- confirmations: 3490
- },
- {
- txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
- vout: 287,
- amount: 0.00001,
- satoshis: 1000,
- height: 546083,
- confirmations: 3490
- },
- {
- txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
- vout: 288,
- amount: 0.00001,
- satoshis: 1000,
- height: 546083,
- confirmations: 3490
- }
-]
-
-const mockUnconfirmed = [
- {
- address: "1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp",
- txid: "000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786",
- vout: 0,
- scriptPubKey: "76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac",
- amount: 0.00999626,
- satoshis: 999626,
- confirmations: 0,
- ts: 1537989425
- }
-]
-
-const mockTransactions = {
- pagesTotal: 1,
- txs: [
- {
- txid: "000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786",
- version: 2,
- locktime: 549565,
- vin: [
- {
- txid:
- "45c891c6d44619fc85716ba1b593aa83ebc1e500fe611b1ab98531ea203a0f21",
- vout: 209,
- sequence: 4294967294,
- n: 0,
- scriptSig: {
- hex:
- "47304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe4477541210246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a",
- asm:
- "304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe44775[ALL|FORKID] 0246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a"
- },
- addr: "14TdovsQUL69xL5g3zSzhLpmDb93d9rU9m",
- valueSat: 1979534,
- value: 0.01979534,
- doubleSpentTxID: null
- },
- {
- txid:
- "6e5fa79547112a912adf6082c975dc80e282045193512ea369adb6bac7420674",
- vout: 147,
- sequence: 4294967294,
- n: 1,
- scriptSig: {
- hex:
- "473044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a4121038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e",
- asm:
- "3044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a[ALL|FORKID] 038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e"
- },
- addr: "1CEtC2fjELvmAzTd6MWuHb1gvuSq8x3Xpb",
- valueSat: 10466,
- value: 0.00010466,
- doubleSpentTxID: null
- }
- ],
- vout: [
- {
- value: "0.00999626",
- n: 0,
- scriptPubKey: {
- hex: "76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac",
- asm:
- "OP_DUP OP_HASH160 997fabcd94a1e2aaa13a7664362e5e7b96c169a9 OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.00990000",
- n: 1,
- scriptPubKey: {
- hex: "76a914e3335e4d6babe61ea58311293c1c6bfe802801cb88ac",
- asm:
- "OP_DUP OP_HASH160 e3335e4d6babe61ea58311293c1c6bfe802801cb OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["1MiKvgaQTFCTEZbSDMZgw9ahaB52Cr4ofb"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- }
- ],
- blockhash:
- "00000000000000000158b1a2883688873ec5ea076e3b0f576bcdfe1fd277880f",
- blockheight: 549601,
- confirmations: 5,
- time: 1537990026,
- blocktime: 1537990026,
- valueOut: 0.01989626,
- size: 372,
- valueIn: 0.0199,
- fees: 0.00000374
- }
- ]
-}
-
-module.exports = {
- mockAddressDetails,
- mockUtxoDetails,
- mockUnconfirmed,
- mockTransactions
-}
diff --git a/test/v2/mocks/block-mock.js b/test/v2/mocks/block-mock.js
deleted file mode 100644
index 069b90d..0000000
--- a/test/v2/mocks/block-mock.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockBlockDetails = {
- hash: "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79",
- size: 1319,
- height: 1267544,
- version: 536870912,
- merkleroot:
- "c2cd01ec2cf149acc7631385f89ae103d1a2ad212ab810c862d9680a811618ce",
- tx: [
- "52bfa89d449fef8070ec33e7a61f5ec8b5417ff62b050cd6a144ebce9557e0fa",
- "8988e8742d2523f667c2d1374861919e3a82903e059fec75c10795da2303b93b",
- "41def004f22b196d675566a6983ecf97611e72c48375b8ba779983d5ccd369d7",
- "8ca8efb06abb94395f8331f87e101504dcf66aee828f2111922f056971fa7502",
- "9ab409cbb203be7cf22bd6598d787fcdd5b417d885b72207ecc7253470770649"
- ],
- time: 1542048973,
- nonce: 3936284753,
- bits: "1a03c148",
- difficulty: 4467892.99177529,
- chainwork: "00000000000000000000000000000000000000000000003ee27b503a064045bd",
- confirmations: 3,
- previousblockhash:
- "00000000000001891202cbe18729a02a8763cf04da0ca7aded6e6c7d9b500785",
- nextblockhash:
- "000000000000039b93b3f3403a0eb21150904b15229d998cf3788fd8bf192cc2",
- reward: 0.78125,
- isMainChain: true,
- poolInfo: {}
-}
-
-const mockBlockHash =
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
-
-module.exports = {
- mockBlockDetails,
- mockBlockHash
-}
diff --git a/test/v2/mocks/blockchain-mock.js b/test/v2/mocks/blockchain-mock.js
deleted file mode 100644
index 6025583..0000000
--- a/test/v2/mocks/blockchain-mock.js
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockBlockHash =
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
-
-const mockBlockchainInfo = {
- chain: "test",
- blocks: 1267694,
- headers: 1267694,
- bestblockhash:
- "000000000000013eaf80d1e157e32804c36a58ad0bb26ca59833880c80298780",
- difficulty: 4105763.969035785,
- mediantime: 1542131305,
- verificationprogress: 0.9999968911571566,
- chainwork: "00000000000000000000000000000000000000000000003f0443b0b5f02ce255",
- pruned: false,
- softforks: [
- { id: "bip34", version: 2, reject: { status: true } },
- { id: "bip66", version: 3, reject: { status: true } },
- { id: "bip65", version: 4, reject: { status: true } }
- ],
- bip9_softforks: {
- csv: {
- status: "active",
- startTime: 1456790400,
- timeout: 1493596800,
- since: 770112
- }
- }
-}
-
-const mockChainTips = [
- {
- height: 1267696,
- hash: "000000000000035bfc43a642ebbff8cfc1e88b1d564de8b0a6c7e2797eeafb21",
- branchlen: 0,
- status: "active"
- },
- {
- height: 1267581,
- hash: "000000000001bd12e4124207682563135b21353ca3087bc6b0c409f7f9e1da91",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1267375,
- hash: "00000000702036979df70236bcc45dfc72d43d5d0e6834007afa1fa627e49587",
- branchlen: 1036,
- status: "headers-only"
- },
- {
- height: 1266979,
- hash: "00000000e851abbde2174ccdc5c2508b909f81f23c4b7abeac864eee1a4891c7",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266973,
- hash: "000000007e1324d2900ed70947f89ab8fd4a267e87c9244c333215659a7370d5",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266967,
- hash: "000000000f37f12843d4800f50ec4de44dce0432e4d448242d43ff04a7a2948d",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266963,
- hash: "00000000ae11ec99e88898cbd72567cb4cb79e7fc13243357bef79632769deb4",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266962,
- hash: "000000004f97851259b4460a049e44fa5bd4beadee04a85bf81bd2e90c4f24f9",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266950,
- hash: "00000000d12a0e4a827f73ecaadb563df7e99817294939f2be8e943079dc60b2",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266944,
- hash: "00000000612d16af273217818e8e7ac5014a19f68ed04e1bc897b1be0a9c744f",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266941,
- hash: "0000000000002b91cdb15cacf3368da2c9ffce511d64092193b507dad75f4a27",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266896,
- hash: "000000000002745f67a66617b1f9f65c2dfb4c4b8a9ed9b1320b98d3ca46cbe5",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266481,
- hash: "0000000000036babee3ba7654cddb29a9fe5e85c9fbeb44bb53d5ffb694b9670",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266452,
- hash: "00000000502c3ab1490e0839780a4b441bbe21507c454545941e6adcde73c2ff",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1266336,
- hash: "000000001c9a0b7cd9eb2210f69d5a9a3f4546ba3707deb40993d729190582d7",
- branchlen: 10,
- status: "headers-only"
- },
- {
- height: 1266097,
- hash: "000000000028ac0fbd18afe6f001f70cb7549bd2b3082d754dde88ee236368a2",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1265522,
- hash: "00000000000000c6df7a2063030e6ce51399e470cc46e4bf6d67aa3f0feca98d",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1265470,
- hash: "0000000000168e6442a595a02340fccf8dc2b0e8912c632d39e1f870685f6d7c",
- branchlen: 2,
- status: "valid-fork"
- },
- {
- height: 1265275,
- hash: "000000008bc2b37ae6af1b886b52e7e1c1122c12badc4ae6c13df64f789267cf",
- branchlen: 11027,
- status: "headers-only"
- },
- {
- height: 1265257,
- hash: "00000000005bc3e9973d7273211eab02ae02549c7ebae48764c0bd648d4d7bbe",
- branchlen: 114,
- status: "valid-fork"
- },
- {
- height: 1265254,
- hash: "0000000000e5b909d3541857315e9ee103b042d9ba661f25cc3e8fb25a96c8ce",
- branchlen: 111,
- status: "valid-fork"
- },
- {
- height: 1265245,
- hash: "000000000066eb8832f6f990baceb379536f437216e22475a6c1b9133d250cb8",
- branchlen: 102,
- status: "valid-fork"
- },
- {
- height: 1264455,
- hash: "00000000000001befc1bb17a23208d0b77b2449e37093ce8fbb5e346b19cafcc",
- branchlen: 1,
- status: "valid-headers"
- },
- {
- height: 1264373,
- hash: "00000000000001ed3747e04fb95054cac0358fb4d8009d1999fc3ea34413e84a",
- branchlen: 175,
- status: "valid-fork"
- },
- {
- height: 1263912,
- hash: "00000000000004635aecbcb97edcd6f5396483338838cb40da804eb354c68bde",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1262906,
- hash: "00000000b31643d92a3e7c38e9755844fc8607e3f1055580a8ff28854e8a8ece",
- branchlen: 1,
- status: "valid-fork"
- },
- {
- height: 1255749,
- hash: "000000001dde5b015a99137f4cba87871370f4b6fcfbcc8b126547e6c33177da",
- branchlen: 129,
- status: "headers-only"
- },
- {
- height: 1188789,
- hash: "00000000af942ce4eb60b3213cbcb7c98a7330f1f8f1adb4b6376f5e822e15b2",
- branchlen: 92,
- status: "headers-only"
- }
-]
-
-const mockMempoolInfo = {
- size: 87,
- bytes: 16816,
- usage: 66408,
- maxmempool: 300000000,
- mempoolminfee: 0
-}
-
-const mockRawMempool = [
- "db045bc3bd1088fa91f5ebb05c35cb9e2a91a22377f79b465cc6920b9893123c",
- "6b3df7febf2b9834f1409155f88b866dd516b36376eae00e2b455df82e290405"
-]
-
-const mockBlockHeaderConcise =
- "0000ff7f7d217c9b7845ea8b50d620c59a1bf7c276566406e9b7bc7e463e0000000000006d70322c0b697c1c81d2744f87f09f1e9780ba5d30338952e2cdc64e60456f8423bb0a5ceafa091a3e843526"
-
-const mockBlockHeader = {
- hash: "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900",
- confirmations: 7,
- height: 1272859,
- version: 2147418112,
- versionHex: "7fff0000",
- merkleroot:
- "846f45604ec6cde2528933305dba80971e9ff0874f74d2811c7c690b2c32706d",
- time: 1544207139,
- mediantime: 1544202884,
- nonce: 641041470,
- bits: "1a09faea",
- difficulty: 1681035.704111868,
- chainwork: "00000000000000000000000000000000000000000000003fc4752e608403be04",
- previousblockhash:
- "0000000000003e467ebcb7e906645676c2f71b9ac520d6508bea45789b7c217d",
- nextblockhash:
- "00000000000006899041cdfd6c0b73a97730c362346dde479b77414ad7f25ace"
-}
-
-const mockTxOut = {
- bestblock: "00000000003a7f19730dd9f172d7466658a5c8833dd03ed8f4ba36e3d857b5e7",
- confirmations: 10,
- value: 0.0001,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 0ee020c07f39526ac5505c54fa1ab98490979b83 OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a9140ee020c07f39526ac5505c54fa1ab98490979b8388ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: ["bchtest:qq8wqgxq0uu4y6k92pw9f7s6hxzfp9umsvtg39pzqf"]
- },
- coinbase: false
-}
-
-const mockTxOutProof =
- "000000200798039affceb7a381e15dc62443c286efe7cae852393b656807000000000000cf9a7d6c654fd1c4558229a619a550ff749b373fa0f0027eed68b1abf6175d5c07c50f5cffff001d0452403b34000000070d0765da76980d542b5670d27ccda9e717073270f8921ad017deb7ee83fe6c4c22830a48cc8392197f1742a3d81805bd2aa4eb7469f38c74f674429d682cb87efcff1713fd0c388a50f0d11adf05363397ef79d16cdb786d47c941c2cb89f2588f42aced9c05f4203b4440616a9e4266ec47909b9580a643f402b5d4e82cc3cddd73df05a33abf6af3975d973d3033d10c4168a73d58d01f685a96d5a2519cd0de9c77faf3f8725ddf155cbdc8ab8102f173e2d0a0d74767f3bff22f588158d6d5bc71c079c7659cc864819c43877635007650502eb4060fcc9feec3280a41d602ad0a"
-
-module.exports = {
- mockBlockHash,
- mockBlockchainInfo,
- mockChainTips,
- mockMempoolInfo,
- mockRawMempool,
- mockBlockHeaderConcise,
- mockBlockHeader,
- mockTxOut,
- mockTxOutProof
-}
diff --git a/test/v2/mocks/control-mock.js b/test/v2/mocks/control-mock.js
deleted file mode 100644
index cca9338..0000000
--- a/test/v2/mocks/control-mock.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockGetInfo = {
- version: 170200,
- protocolversion: 70015,
- walletversion: 160300,
- balance: 0,
- blocks: 1266726,
- timeoffset: 0,
- connections: 8,
- proxy: "",
- difficulty: 1,
- testnet: true,
- keypoololdest: 1536331195,
- keypoolsize: 2000,
- paytxfee: 0,
- relayfee: 0.00001,
- errors: "Warning: unknown new rules activated (versionbit 28)"
-}
-
-module.exports = {
- mockGetInfo
-}
diff --git a/test/v2/mocks/express-mocks.js b/test/v2/mocks/express-mocks.js
deleted file mode 100644
index fcb545f..0000000
--- a/test/v2/mocks/express-mocks.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- Contains mocks of Express req and res objects.
-*/
-
-"use strict"
-
-const sinon = require("sinon")
-
-// Inspect JS Objects.
-const util = require("util")
-util.inspect.defaultOptions = {
- showHidden: true,
- colors: true
-}
-
-// mock for res.send()
-function fakeSend(arg) {
- //console.log(`res.send: ${util.inspect(arg)}`);
- mockRes.output = arg
- return arg
-}
-
-// mock for res.json()
-function fakeJson(arg) {
- //console.log(`res.json: ${util.inspect(arg)}`);
- mockRes.output = arg
- return arg
-}
-
-// mock for res.setStatus(num)
-const setStatusCode = arg => {
- mockRes.statusCode = arg
-}
-
-const mockReq = {
- accepts: sinon.stub().returns({}),
- acceptsCharsets: sinon.stub().returns({}),
- acceptsEncodings: sinon.stub().returns({}),
- acceptsLanguages: sinon.stub().returns({}),
- body: {},
- flash: sinon.stub().returns({}),
- get: sinon.stub().returns({}),
- is: sinon.stub().returns({}),
- params: {},
- query: {},
- session: {},
- locals: {},
- headers: {}
-}
-
-const mockRes = {
- append: sinon.stub().returns({}),
- attachement: sinon.stub().returns({}),
- clearCookie: sinon.stub().returns({}),
- cookie: sinon.stub().returns({}),
- download: sinon.stub().returns({}),
- end: sinon.stub().returns({}),
- format: {},
- get: sinon.stub().returns({}),
- headersSent: sinon.stub().returns({}),
- json: sinon.stub().callsFake(fakeJson),
- jsonp: sinon.stub().returns({}),
- links: sinon.stub().returns({}),
- locals: {},
- location: sinon.stub().returns({}),
- output: null, // Used for retrieving output data.
- redirect: sinon.stub().returns({}),
- render: sinon.stub().returns({}),
- send: sinon.stub().callsFake(fakeSend),
- sendFile: sinon.stub().returns({}),
- sendStatus: sinon.stub().returns({}),
- set: sinon.stub().returns({}),
- status: sinon.stub().callsFake(setStatusCode),
- statusCode: null, // Default value before calling stats();
- type: sinon.stub().returns({}),
- vary: sinon.stub().returns({}),
- write: sinon.stub().returns({}),
- setHeader: sinon.stub().returns({}),
- format: sinon.stub().returns({})
-}
-
-const mockNext = sinon.stub().returns()
-
-module.exports = {
- mockReq,
- mockRes,
- mockNext
-}
diff --git a/test/v2/mocks/mining-mocks.js b/test/v2/mocks/mining-mocks.js
deleted file mode 100644
index 8ef8ada..0000000
--- a/test/v2/mocks/mining-mocks.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockMiningInfo = {
- blocks: 1270185,
- currentblocksize: 0,
- currentblocktx: 0,
- difficulty: 1,
- blockprioritypercentage: 5,
- errors:
- "Warning: Unknown block versions being mined! It's possible unknown rules are in effect",
- networkhashps: 517410290.9365583,
- pooledtx: 5,
- chain: "test"
-}
-
-module.exports = {
- mockMiningInfo
-}
diff --git a/test/v2/mocks/raw-transactions-mocks.js b/test/v2/mocks/raw-transactions-mocks.js
deleted file mode 100644
index 08620a3..0000000
--- a/test/v2/mocks/raw-transactions-mocks.js
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- This library contains mocking data for running unit tests.
-*/
-
-"use strict"
-
-const mockDecodeRawTransaction = {
- txid: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988",
- hash: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988",
- size: 226,
- version: 2,
- locktime: 0,
- vin: [
- {
- txid: "21cced645eab150585ed7ca7c96edebab5793cc0a3b3b286c42fd7d6d798b5b9",
- vout: 1,
- scriptSig: {
- asm:
- "3045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd41390[ALL|FORKID] 0360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d",
- hex:
- "483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d"
- },
- sequence: 4294967295
- }
- ],
- vout: [
- {
- value: 0.0001,
- n: 0,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: [Array]
- }
- },
- {
- value: 0.09989752,
- n: 1,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: [Array]
- }
- }
- ]
-}
-
-const mockDecodeScript = {
- asm:
- "0 0 -57 OP_NOP6 OP_LSHIFT OP_UNKNOWN OP_UNKNOWN OP_UNKNOWN c486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa OP_2OVER OP_NUMEQUALVERIFY OP_OR OP_INVERT OP_UNKNOWN OP_UNKNOWN 2ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab 67c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b [error]",
- type: "nonstandard",
- p2sh: "bchtest:pzy6dwfy6yf373w0dr05a6flfqksurjhwcl3awhdvm"
-}
-
-const mockRawTransactionConcise =
- "02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000"
-
-const mockRawTransactionVerbose = {
- hex:
- "02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000",
- txid: "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971",
- hash: "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971",
- size: 225,
- version: 2,
- locktime: 0,
- vin: [
- {
- txid: "7d989ee50977b289f88915fceffc4a0f4f27fb0558b81503c3b1100150526b4e",
- vout: 0,
- scriptSig: {
- asm:
- "3044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7[ALL|FORKID] 03c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792",
- hex:
- "473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792"
- },
- sequence: 4294967295
- }
- ],
- vout: [
- {
- value: 454.58880465,
- n: 0,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 36d2f27bbd826a86db1e93618ce3de89ef331693 OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: ["bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35"]
- }
- },
- {
- value: 0.1,
- n: 1,
- scriptPubKey: {
- asm:
- "OP_DUP OP_HASH160 152ea3cd65f18cb8fa9146c84ea1a97af8f051de OP_EQUALVERIFY OP_CHECKSIG",
- hex: "76a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac",
- reqSigs: 1,
- type: "pubkeyhash",
- addresses: ["bchtest:qq2jag7dvhccew86j9rvsn4p49a03uz3mcpw3d6aca"]
- }
- }
- ],
- blockhash: "000000000000026fa244de975ca89ea08008aa566564ce2e8ebb3144361b601b",
- confirmations: 125,
- time: 1542646373,
- blocktime: 1542646373
-}
-
-const mockWHDecode = {
- txid: "f8a9857fe3b8a288b5fcafb1b0fc196731f433add6d962f77acd7c10b970ff89",
- fee: "500",
- sendingaddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
- referenceaddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
- ismine: false,
- version: 0,
- type_int: 0,
- type: "Simple Send",
- propertyid: 368,
- precision: "8",
- amount: "10.00000000",
- valid: true,
- blockhash: "0000000046ba0bcef78caaa4492622176bbc563cf249ab52340a0449bc8e26f6",
- blocktime: 1542814183,
- positioninblock: 57,
- block: 1269008,
- confirmations: 2
-}
-
-const mockWHCreateInput = {
- txid: "f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2",
- vout: 1,
- scriptPubKey: "76a914a4b98b0c118de83e7d39c834445f51dce62425f588ac",
- amount: 0.09984138,
- satoshis: 9984138,
- height: 1269011,
- confirmations: 4,
- legacyAddress: "mvXwPH74hW2yVTWwDwzsjGoaUAqJvWk7ZJ",
- cashAddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
- value: 0.09984138
-}
-
-module.exports = {
- mockDecodeRawTransaction,
- mockDecodeScript,
- mockRawTransactionConcise,
- mockRawTransactionVerbose,
- mockWHDecode,
- mockWHCreateInput
-}
diff --git a/test/v2/mocks/slp-mocks.js b/test/v2/mocks/slp-mocks.js
deleted file mode 100644
index 1d70df0..0000000
--- a/test/v2/mocks/slp-mocks.js
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- This library contains mocking data for running unit tests.
-*/
-
-"use strict"
-
-const mockList = {
- t: [
- {
- tokenDetails: {
- tokenIdHex:
- "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
- documentUri: "",
- documentSha256: "",
- symbol: "NAKAMOTO",
- name: "NAKAMOTO",
- decimals: 8
- },
- tokenStats: {
- qty_valid_txns_since_genesis: 241,
- qty_valid_token_utxos: 151,
- qty_valid_token_addresses: 113,
- qty_token_circulating_supply: "20995990",
- qty_token_burned: "4010",
- qty_token_minted: "21000000",
- qty_satoshis_locked_up: 81900
- }
- }
- ]
-}
-
-const mockSingleToken = {
- t: [
- {
- tokenDetails: {
- decimals: 8,
- tokenIdHex:
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a",
- timestamp: "2018-08-26 07:06",
- transactionType: "GENESIS",
- versionType: 1,
- documentUri: "",
- documentSha256Hex: null,
- symbol: "",
- name: "TESTYCOIN",
- batonVout: null,
- containsBaton: false,
- genesisOrMintQuantity: "9999",
- sendOutputs: null
- },
- tokenStats: {
- block_created: 1253802,
- block_last_active_send: 1253802,
- block_last_active_mint: null,
- qty_valid_txns_since_genesis: 2,
- qty_valid_token_utxos: 0,
- qty_valid_token_addresses: 0,
- qty_token_minted: "9999",
- qty_token_burned: "9999",
- qty_token_circulating_supply: "0",
- qty_satoshis_locked_up: 0,
- minting_baton_status: "NEVER_CREATED"
- }
- }
- ]
-}
-
-const mockSingleTokenError = {
- t: []
-}
-
-const mockSingleAddress = {
- a: [
- {
- _id: "5c93ed62a19119333d1595bc",
- tokenDetails: {
- tokenIdHex:
- "6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29"
- },
- address: "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7",
- satoshis_balance: 546,
- token_balance: "4616984"
- }
- ],
- t: [
- {
- tokenDetails: {
- decimals: 8,
- tokenIdHex:
- "6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29",
- timestamp: "2019-02-25 10:05",
- transactionType: "GENESIS",
- versionType: 1,
- documentUri: "https://developer.bitcoin.com",
- documentSha256Hex: "",
- symbol: "DEV",
- name: "DEVCOIN",
- batonVout: 2,
- containsBaton: true,
- genesisOrMintQuantity: "500000000",
- sendOutputs: null
- },
- tokenStats: {
- block_created: 571272,
- block_last_active_send: 574758,
- block_last_active_mint: 571272,
- qty_valid_txns_since_genesis: 172,
- qty_valid_token_utxos: 170,
- qty_valid_token_addresses: 170,
- qty_token_minted: "1000000000",
- qty_token_burned: "4.99999995",
- qty_token_circulating_supply: "999999995.00000005",
- qty_satoshis_locked_up: 92820,
- minting_baton_status: "ALIVE"
- }
- }
- ]
-}
-
-const mockTx = {
- txid: "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457822d446",
- version: 2,
- locktime: 0,
- vin: [
- {
- txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
- vout: 2,
- sequence: 4294967295,
- n: 0,
- scriptSig: {
- hex:
- "4730440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
- asm:
- "30440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
- },
- value: 546,
- legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
- cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
- },
- {
- txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
- vout: 1,
- sequence: 4294967295,
- n: 1,
- scriptSig: {
- hex:
- "483045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
- asm:
- "3045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
- },
- value: 546,
- legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
- cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
- },
- {
- txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
- vout: 3,
- sequence: 4294967295,
- n: 2,
- scriptSig: {
- hex:
- "483045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
- asm:
- "3045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
- },
- value: 9997521,
- legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
- cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
- }
- ],
- vout: [
- {
- value: "0.00000000",
- n: 0,
- scriptPubKey: {
- hex:
- "6a04534c500001010453454e44207ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796080000000049504f80080000001c71e64280",
- asm:
- "OP_RETURN 5262419 1 1145980243 7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796 0000000049504f80 0000001c71e64280"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.00000546",
- n: 1,
- scriptPubKey: {
- hex: "76a914396b8e57ad0cb58d30e2992f22047b3c20377aa688ac",
- asm:
- "OP_DUP OP_HASH160 396b8e57ad0cb58d30e2992f22047b3c20377aa6 OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["mkkZf7T3fU3vHSzNPy51HBmM46ghN1gnN9"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.00000546",
- n: 2,
- scriptPubKey: {
- hex: "76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac",
- asm:
- "OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.09996891",
- n: 3,
- scriptPubKey: {
- hex: "76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac",
- asm:
- "OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG",
- addresses: ["mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL"],
- type: "pubkeyhash"
- },
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- }
- ],
- blockhash: "000000000000ce978accc64a6bb567acf0c653c202309a0f8e220149bf0c6968",
- blockheight: 1287490,
- confirmations: 746,
- time: 1550855104,
- blocktime: 1550855104,
- valueOut: 0.09997983,
- size: 628,
- valueIn: 0.09998613,
- fees: 0.0000063,
- tokenInfo: {
- versionType: 1,
- transactionType: "SEND",
- tokenIdHex:
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796",
- sendOutputs: ["0", "1230000000", "122170000000"]
- },
- tokenIsValid: true
-}
-
-const mockConvert = {
- slpAddress: "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5",
- cashAddress: "bchtest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2svtllzmlf",
- legacyAddress: "mvQPGnzRT6gMWASZBMg7NcT3vmvsSKSQtf"
-}
-
-const mockTokenDetails = {
- tokenIdHex:
- "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
- documentUri: "",
- symbol: "NAKAMOTO",
- name: "NAKAMOTO",
- decimals: 8,
- timestamp: "",
- containsBaton: true,
- versionType: 1
-}
-
-const mockTokenStats = {
- qty_valid_txns_since_genesis: 241,
- qty_valid_token_utxos: 151,
- qty_valid_token_addresses: 113,
- qty_token_circulating_supply: "20995990",
- qty_token_burned: "4010",
- qty_token_minted: "21000000",
- qty_satoshis_locked_up: 81900
-}
-
-const mockBalance = {
- slpAddress: "simpleledger:qp9d8mn8ypryfvea2mev0ggc3wg6plpn4suuaeuss3",
- satoshis_balance: 546,
- token_balance: "1000"
-}
-
-const mockTransactions = [
- {
- txid: "a302f045be8efa1cd982833a7f187ff4fac8baac36da0c887eb2787d8b45e2af",
- tokenDetails: {
- valid: true,
- detail: {
- decimals: null,
- tokenIdHex:
- "495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a",
- timestamp: null,
- transactionType: "MINT",
- versionType: 1,
- documentUri: null,
- documentSha256Hex: null,
- symbol: null,
- name: null,
- batonVout: 2,
- containsBaton: true,
- genesisOrMintQuantity: {
- $numberDecimal: "1000"
- },
- sendOutputs: null
- },
- invalidReason: null,
- schema_version: 30
- }
- }
-]
-
-const mockFoobar = {
- c: [],
- u: []
-}
-
-module.exports = {
- mockList,
- mockSingleToken,
- mockConvert,
- mockTokenDetails,
- mockTokenStats,
- mockTx,
- mockBalance,
- mockTransactions,
- mockSingleTokenError,
- mockSingleAddress,
- mockFoobar
-}
diff --git a/test/v2/mocks/slpjs-mocks.js b/test/v2/mocks/slpjs-mocks.js
deleted file mode 100644
index c130935..0000000
--- a/test/v2/mocks/slpjs-mocks.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- Mocks used for unit tests that interact with slpjs.
-*/
-
-"use strict"
-
-const sinon = require("sinon")
-const proxyquire = require("proxyquire")
-const BigNumber = require("bignumber.js")
-const slpMocks = require("./slp-mocks")
-
-// Mock the BitboxNetwork class.
-class BitboxNetwork {
- constructor() {}
-
- async getAllSlpBalancesAndUtxos(address) {
- return {
- satoshis_available_bch: 9996891,
- satoshis_in_slp_baton: 546,
- satoshis_in_slp_token: 546,
- satoshis_in_invalid_token_dag: 0,
- satoshis_in_invalid_baton_dag: 0,
- slpTokenBalances: {
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": new BigNumber(
- 123400000000
- )
- },
- slpTokenUtxos: {
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": []
- },
- slpBatonUtxos: {
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": []
- },
- nonSlpUtxos: [{}],
- invalidTokenUtxos: [],
- invalidBatonUtxos: []
- }
- }
-
- async getTokenInformation(txid) {
- BigNumber.set({ DECIMAL_PLACES: 8, ROUNDING_MODE: 4 })
-
- const obj = {
- versionType: 1,
- transactionType: 0,
- symbol: "SLPSDK",
- name: "SLP SDK example using BITBOX",
- documentUri: "developer.bitcoin.com",
- documentSha256: null,
- decimals: 8,
- batonVout: 2,
- containsBaton: true,
- genesisOrMintQuantity: new BigNumber(123400000000)
- }
-
- return obj
- }
-
- async getTransactionDetails(txid) {
- return slpMocks.mockTx
- }
-}
-
-// Mock the slpjs library.
-const slpjs = {
- BitboxNetwork,
- slp: {},
- validator: {}
-}
-
-module.exports = slpjs
diff --git a/test/v2/mocks/transaction-mocks.js b/test/v2/mocks/transaction-mocks.js
deleted file mode 100644
index a8d22e2..0000000
--- a/test/v2/mocks/transaction-mocks.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-/*
-const mockDetails = {
- txid: "6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40",
- version: 2,
- locktime: 0,
- vin: [Array],
- vout: [Array],
- blockhash: "00000000e7232ff12462dedf9c11985f5b54202515277c337ccc59812758f28b",
- blockheight: 1270188,
- confirmations: 2,
- time: 1543436253,
- blocktime: 1543436253,
- valueOut: 450.78867333,
- size: 226,
- valueIn: 450.78867559,
- fees: 0.00000226
-}
-*/
-
-const mockDetails = {
- txid: "6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40",
- version: 2,
- locktime: 0,
- vin: [
- {
- txid: "273d616d1c48f4b075c497f36ffdc79da5c8d6ed75485808b3599aac504f8525",
- vout: 0,
- sequence: 4294967295,
- n: 0,
- scriptSig: [{}],
- addr: "bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35",
- valueSat: 45078867559,
- value: 450.78867559,
- doubleSpentTxID: null
- }
- ],
- vout: [
- {
- value: "450.68867333",
- n: 0,
- scriptPubKey: [{}],
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- },
- {
- value: "0.10000000",
- n: 1,
- scriptPubKey: [{}],
- spentTxId: null,
- spentIndex: null,
- spentHeight: null
- }
- ],
- blockhash: "00000000e7232ff12462dedf9c11985f5b54202515277c337ccc59812758f28b",
- blockheight: 1270188,
- confirmations: 3,
- time: 1543436253,
- blocktime: 1543436253,
- valueOut: 450.78867333,
- size: 226,
- valueIn: 450.78867559,
- fees: 0.00000226
-}
-
-module.exports = {
- mockDetails
-}
diff --git a/test/v2/mocks/util-mocks.js b/test/v2/mocks/util-mocks.js
deleted file mode 100644
index 4118358..0000000
--- a/test/v2/mocks/util-mocks.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- This library contains mocking data for running unit tests on the address route.
-*/
-
-"use strict"
-
-const mockAddress = {
- isvalid: true,
- address: "bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y",
- scriptPubKey: "76a914016a935f87e8deeab04501889b22d87e4e52db0988ac",
- ismine: false,
- iswatchonly: false,
- isscript: false
-}
-
-module.exports = {
- mockAddress
-}
diff --git a/test/v2/rate-limits.js b/test/v2/rate-limits.js
deleted file mode 100644
index 030fa64..0000000
--- a/test/v2/rate-limits.js
+++ /dev/null
@@ -1,166 +0,0 @@
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-// Mocking data.
-const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
-
-// Libraries under test
-const rateLimitMiddleware = require("../../src/middleware/route-ratelimit")
-const controlRoute = require("../../src/routes/v2/control")
-
-let req, res, next
-let originalEnvVars // Used during transition from integration to unit tests.
-
-describe("#route-ratelimits", () => {
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
- next = mockNext
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
- })
-
- describe("#routeRateLimit", () => {
- const routeRateLimit = rateLimitMiddleware.routeRateLimit
- const getInfo = controlRoute.testableComponents.getInfo
- /*
- it("should pass through rate-limit middleware", async () => {
- req.baseUrl = "/v2"
- req.path = "/control/getInfo"
- req.method = "GET"
-
- await routeRateLimit(req, res, next)
-
- // next() will be called if rate-limit is not triggered
- assert.equal(next.called, true)
- })
-
- it("should trigger rate-limit handler if rate limits exceeds 60 request per minute", async () => {
- req.baseUrl = "/v2"
- req.path = "/control/getInfo"
- req.method = "GET"
-
- for (let i = 0; i < 65; i++) {
- next.reset() // reset the stubbed next() function.
-
- await routeRateLimit(req, res, next)
- //console.log(`next() called: ${next.called}`)
- }
-
- // Note: next() will be called unless the rate-limit kicks in.
- assert.equal(
- next.called,
- false,
- `next should not be called if rate limit was triggered.`
- )
- })
- */
- /*
- it("should NOT trigger rate-limit handler for pro-tier at 65 RPM", async () => {
- // Clear the require cache before running this test.
- delete require.cache[
- require.resolve("../../dist/middleware/route-ratelimit")
- ]
- rateLimitMiddleware = require("../../dist/middleware/route-ratelimit")
- routeRateLimit = rateLimitMiddleware.routeRateLimit
-
- req.baseUrl = "/v2"
- req.path = "/control/getInfo"
- req.method = "GET"
-
- req.locals.proLimit = true
-
- //console.log(`req.locals before test: ${util.inspect(req.locals)}`)
-
- // Prepare the authorization header
- //req.headers.authorization = generateAuthHeader("BITBOX")
-
- for (let i = 0; i < 65; i++) {
- next.reset() // reset the stubbed next() function.
-
- await routeRateLimit(req, res, next)
- //console.log(`next() called: ${next.called}`)
- }
-
- //console.log(`req.locals after test: ${util.inspect(req.locals)}`)
-
- // Note: next() will be called unless the rate-limit kicks in.
- assert.equal(
- next.called,
- true,
- `next should be called if rate limit was not triggered.`
- )
- })
-
- it("rate-limiting should still kick in at a higher RPM for pro-tier", async () => {
- // Clear the require cache before running this test.
- delete require.cache[
- require.resolve("../../dist/middleware/route-ratelimit")
- ]
- rateLimitMiddleware = require("../../dist/middleware/route-ratelimit")
- routeRateLimit = rateLimitMiddleware.routeRateLimit
-
- req.baseUrl = "/v2"
- req.path = "/control/getInfo"
- req.method = "GET"
-
- req.locals.proLimit = true
-
- //console.log(`req.locals before test: ${util.inspect(req.locals)}`)
-
- // Prepare the authorization header
- //req.headers.authorization = generateAuthHeader("BITBOX")
-
- for (let i = 0; i < 650; i++) {
- next.reset() // reset the stubbed next() function.
-
- await routeRateLimit(req, res, next)
- //console.log(`next() called: ${next.called}`)
- }
-
- //console.log(`req.locals after test: ${util.inspect(req.locals)}`)
-
- // Note: next() will be called unless the rate-limit kicks in.
- assert.equal(
- next.called,
- false,
- `next should NOT be called if rate limit was triggered.`
- )
- })
- */
- })
-})
-
-// Generates a Basic authorization header.
-function generateAuthHeader(pass) {
- // https://en.wikipedia.org/wiki/Basic_access_authentication
- const username = "BITBOX"
- const combined = `${username}:${pass}`
-
- var base64Credential = Buffer.from(combined).toString("base64")
- var readyCredential = `Basic ${base64Credential}`
-
- return readyCredential
-}
diff --git a/test/v2/raw-transactions.js b/test/v2/raw-transactions.js
deleted file mode 100644
index bd20bcc..0000000
--- a/test/v2/raw-transactions.js
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- TESTS FOR THE RAWTRANSACTIONS.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- TODO:
- -Create e2e test for sendRawTransaction.
-
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const rawtransactions = require("../../src/routes/v2/rawtransactions")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-//delete require.cache[require.resolve("./mocks/express-mocks")] // Fixes bug
-const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
-const mockData = require("./mocks/raw-transactions-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 5 }
-
-describe("#Raw-Transactions", () => {
- let req, res, next
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
- next = mockNext
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
- req.locals = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = rawtransactions.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "rawtransactions", "Returns static string")
- })
- })
-
- describe("decodeRawTransactionSingle()", () => {
- // block route handler.
- const decodeRawTransaction =
- rawtransactions.testableComponents.decodeRawTransactionSingle
-
- it("should throw error if hex is missing", async () => {
- const result = await decodeRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hex can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.hex =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET /decodeRawTransaction", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockDecodeRawTransaction })
- }
-
- req.params.hex =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout"
- ])
- assert.isArray(result.vin)
- assert.isArray(result.vout)
- })
- })
-
- describe("decodeRawTransactionBulk()", () => {
- const decodeRawTransactionBulk =
- rawtransactions.testableComponents.decodeRawTransactionBulk
-
- it("should throw 400 error if hexes array is missing", async () => {
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hexes must be an array")
- })
-
- it("should throw 400 error if hexes array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hexes = testArray
-
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 error if hexes is empty", async () => {
- req.body.hexes = [""]
-
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Encountered empty hex")
- })
-
- it("should error on non-array single hex", async () => {
- req.body.hexes =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeRawTransactionBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hexes must be an array",
- "Proper error message"
- )
- })
-
- it("should decode an array with a single hex", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockDecodeRawTransaction })
- }
-
- req.body.hexes = [
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
- ]
-
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout"
- ])
- assert.isArray(result[0].vin)
- assert.isArray(result[0].vout)
- })
-
- it("should decode an array with multiple hexes", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockDecodeRawTransaction })
- }
-
- req.body.hexes = [
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000",
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
- ]
-
- const result = await decodeRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout"
- ])
- assert.isArray(result[0].vin)
- assert.isArray(result[0].vout)
- })
- })
-
- describe("decodeScriptSingle()", () => {
- // block route handler.
- const decodeScriptSingle =
- rawtransactions.testableComponents.decodeScriptSingle
-
- it("should throw error if hex is missing", async () => {
- const result = await decodeScriptSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hex can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.hex =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeScriptSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET /decodeScriptSingle", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockDecodeScript })
- }
-
- req.params.hex =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeScriptSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["asm", "type", "p2sh"])
- })
- })
-
- describe("decodeScriptBulk()", () => {
- const decodeScriptBulk = rawtransactions.testableComponents.decodeScriptBulk
-
- it("should throw 400 error if hexes array is missing", async () => {
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hexes must be an array")
- })
-
- it("should throw 400 error if hexes array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hexes = testArray
-
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 error if hexes is empty", async () => {
- req.body.hexes = [""]
-
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Encountered empty hex")
- })
-
- it("should error on non-array single hex", async () => {
- req.body.hexes =
- "0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
-
- const result = await decodeScriptBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hexes must be an array",
- "Proper error message"
- )
- })
-
- it("should decode an array with a single hex", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockDecodeScript })
- }
-
- req.body.hexes = [
- "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
- ]
-
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["asm", "type", "p2sh"])
- })
-
- it("should decode an array with a multiple hexes", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockDecodeScript })
- }
-
- req.body.hexes = [
- "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16",
- "4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
- ]
-
- const result = await decodeScriptBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2)
- assert.hasAllKeys(result[0], ["asm", "type", "p2sh"])
- })
- })
-
- describe("getRawTransactionBulk()", () => {
- // block route handler.
- const getRawTransactionBulk =
- rawtransactions.testableComponents.getRawTransactionBulk
-
- it("should throw 400 error if txids array is missing", async () => {
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txids must be an array")
- })
-
- it("should throw 400 error if txids array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.txids = testArray
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 error if txid is empty", async () => {
- req.body.txids = [""]
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Encountered empty TXID")
- })
-
- it("should throw 400 error if txid is invalid", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: { message: "parameter 1 must be of length 64 (not 6)" }
- })
- }
-
- req.body.txids = ["abc123"]
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "parameter 1 must be of length 64 (not 6)")
- })
-
- it("should get concise transaction data", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawTransactionConcise })
- }
-
- req.body.txids = [
- "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
- ]
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.isString(result[0])
- })
-
- it("should get verbose transaction data", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawTransactionVerbose })
- }
-
- req.body.txids = [
- "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
- ]
- req.body.verbose = true
-
- const result = await getRawTransactionBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "hex",
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "confirmations",
- "time",
- "blocktime"
- ])
- assert.isArray(result[0].vin)
- assert.isArray(result[0].vout)
- })
- })
-
- describe("getRawTransactionSingle()", () => {
- // block route handler.
- const getRawTransactionSingle =
- rawtransactions.testableComponents.getRawTransactionSingle
-
- it("should throw 400 error if txid is missing", async () => {
- const result = await getRawTransactionSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 400 error if txid is invalid", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: { message: "parameter 1 must be of length 64 (not 6)" }
- })
- }
-
- req.params.txid = "abc123"
-
- const result = await getRawTransactionSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "parameter 1 must be of length 64 (not 6)")
- })
-
- it("should get concise transaction data", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawTransactionConcise })
- }
-
- req.params.txid =
- "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
-
- const result = await getRawTransactionSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isString(result)
- })
-
- it("should get verbose transaction data", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockRawTransactionVerbose })
- }
-
- req.params.txid =
- "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971"
- req.query.verbose = "true"
-
- const result = await getRawTransactionSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hex",
- "txid",
- "hash",
- "size",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "confirmations",
- "time",
- "blocktime"
- ])
- assert.isArray(result.vin)
- assert.isArray(result.vout)
- })
- })
-
- describe("sendRawTransactionBulk()", () => {
- const sendRawTransaction =
- rawtransactions.testableComponents.sendRawTransactionBulk
-
- it("should throw 400 error if hexs array is missing", async () => {
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "hex must be an array")
- })
-
- it("should throw 400 error if hexs array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hexes = testArray
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 error if hex array element is empty", async () => {
- req.body.hexes = [""]
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Encountered empty hex")
- })
-
- it("should throw 500 error if hex is invalid", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: { message: "TX decode failed" }
- })
- }
-
- req.body.hexes = ["abc123"]
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "TX decode failed")
- })
-
- it("should submit hex encoded transaction", async () => {
- // This is a difficult test to run as transaction hex is invalid after a
- // block confirmation. So the unit tests simulates what the output 'should'
- // be, but the integration asserts an expected failure.
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, {
- result:
- "aef8848396e67532b42008b9d75b5a5a3459a6717740f31f0553b74102b4b118"
- })
- }
-
- req.body.hexes = [
- "0200000001189f7cf4303e2e0bcc5af4be323b9b397dd4104ca2de09528eb90a1450b8a999010000006a4730440220212ec2ffce136a30cec1bc86a40b08a2afdeb6f8dbd652d7bcb07b1aad6dfa8c022041f59585273b89d88879a9a531ba3272dc953f48ff57dad955b2dee70e76c0624121030143ffd18f1c4add75c86b2f930d9551d51f7a6bd786314247022b7afc45d231ffffffff0230d39700000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac58c20000000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac00000000"
- ]
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- if (process.env.TEST === "unit") {
- assert.isArray(result)
- assert.isString(result[0])
-
- // Integration test
- } else {
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "transaction already in block chain")
- }
- })
- })
-
- describe("sendRawTransactionSingle()", () => {
- // block route handler.
- const sendRawTransaction =
- rawtransactions.testableComponents.sendRawTransactionSingle
-
- it("should throw an error for an empty hex", async () => {
- req.params.hex = ""
-
- const result = await sendRawTransaction(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Encountered empty hex",
- "Proper error message"
- )
- })
-
- it("should throw an error for a non-string", async () => {
- req.params.hex = 456
-
- const result = await sendRawTransaction(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hex must be a string",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.hex =
- "0200000001189f7cf4303e2e0bcc5af4be323b9b397dd4104ca2de09528eb90a1450b8a999010000006a4730440220212ec2ffce136a30cec1bc86a40b08a2afdeb6f8dbd652d7bcb07b1aad6dfa8c022041f59585273b89d88879a9a531ba3272dc953f48ff57dad955b2dee70e76c0624121030143ffd18f1c4add75c86b2f930d9551d51f7a6bd786314247022b7afc45d231ffffffff0230d39700000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac58c20000000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac00000000"
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or great expected."
- )
- })
-
- it("should throw an error for invalid hex", async () => {
- req.params.hex = "abc123"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(500, {
- error: { message: "TX decode failed" }
- })
- }
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "TX decode failed")
- })
-
- it("should GET /sendRawTransaction/:hex", async () => {
- // This is a difficult test to run as transaction hex is invalid after a
- // block confirmation. So the unit tests simulates what the output 'should'
- // be, but the integration asserts an expected failure.
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, {
- result:
- "aef8848396e67532b42008b9d75b5a5a3459a6717740f31f0553b74102b4b118"
- })
- }
-
- req.params.hex =
- "0200000001189f7cf4303e2e0bcc5af4be323b9b397dd4104ca2de09528eb90a1450b8a999010000006a4730440220212ec2ffce136a30cec1bc86a40b08a2afdeb6f8dbd652d7bcb07b1aad6dfa8c022041f59585273b89d88879a9a531ba3272dc953f48ff57dad955b2dee70e76c0624121030143ffd18f1c4add75c86b2f930d9551d51f7a6bd786314247022b7afc45d231ffffffff0230d39700000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac58c20000000000001976a914af64a026e06910c59463b000d18c3d125d7e951a88ac00000000"
-
- const result = await sendRawTransaction(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- if (process.env.TEST === "unit") {
- assert.isString(result)
-
- // Integration test
- } else {
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "transaction already in block chain")
- }
- })
- })
-})
diff --git a/test/v2/slp.js b/test/v2/slp.js
deleted file mode 100644
index 2049a77..0000000
--- a/test/v2/slp.js
+++ /dev/null
@@ -1,971 +0,0 @@
-/*
- TESTS FOR THE SLP.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- TODO:
- -See listSingleToken() tests.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-const sinon = require("sinon")
-const proxyquire = require("proxyquire").noPreserveCache()
-
-// Prepare the slpRoute for stubbing dependcies on slpjs.
-const slpRoute = require("../../src/routes/v2/slp")
-const pathStub = {} // Used to stub methods within slpjs.
-const slpRouteStub = proxyquire("../../src/routes/v2/slp", { slpjs: pathStub })
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/slp-mocks")
-const slpjsMock = require("./mocks/slpjs-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#SLP", () => {
- let req, res, mockServerUrl
- let sandbox
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITDB_URL: process.env.BITDB_URL,
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- SLPDB_URL: process.env.SLPDB_URL
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
-
- // Block network connections for unit tests.
- if (process.env.TEST === "unit") {
- process.env.BITDB_URL = "http://fakeurl/"
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/"
- process.env.SLPDB_URL = "http://fakeurl/"
- mockServerUrl = `http://fakeurl`
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- //req.params = {}
- req.body = {}
- req.query = {}
- req.locals = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
-
- sandbox = sinon.createSandbox()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
-
- sandbox.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITDB_URL = originalEnvVars.BITDB_URL
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.SLPDB_URL = originalEnvVars.SLPDB_URL
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = slpRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "slp", "Returns static string")
- })
- })
-
- describe("list()", () => {
- // list route handler
- const list = slpRoute.testableComponents.list
-
- it("should throw 500 when network issues", async () => {
- // Save the existing SLPDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- const result = await list(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should GET list", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- const b64 = `eyJ2IjozLCJxIjp7ImRiIjpbInQiXSwiZmluZCI6eyIkcXVlcnkiOnt9fSwicHJvamVjdCI6eyJ0b2tlbkRldGFpbHMiOjEsInRva2VuU3RhdHMiOjEsIl9pZCI6MH0sImxpbWl0IjoxMDB9fQ==`
-
- nock(process.env.SLPDB_URL)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockList)
- }
-
- const result = await list(req, res)
- // console.log(`test result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "id",
- "timestamp",
- "symbol",
- "name",
- "documentUri",
- "documentHash",
- "decimals",
- "initialTokenQty"
- ])
- })
- })
-
- describe("listSingleToken()", () => {
- const listSingleToken = slpRoute.testableComponents.listSingleToken
-
- it("should throw 400 if tokenId is empty", async () => {
- const result = await listSingleToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing BITDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- req.params.tokenId =
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
-
- const result = await listSingleToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should return 'not found' for mainnet txid on testnet", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockSingleToken)
- }
-
- req.params.tokenId =
- // testnet
- //"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
- // mainnet
- "259908ae44f46ef585edef4bcc1e50dc06e4c391ac4be929fae27235b8158cf1"
-
- const result = await listSingleToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["id"])
- assert.include(result.id, "not found")
- })
-
- it("should get token information", async () => {
- // testnet
- const tokenIdToTest =
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockSingleToken)
- }
-
- req.params.tokenId = tokenIdToTest
-
- const result = await listSingleToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "id",
- "blockCreated",
- "blockLastActiveMint",
- "blockLastActiveSend",
- "circulatingSupply",
- "containsBaton",
- "mintingBatonStatus",
- "txnsSinceGenesis",
- "versionType",
- "timestamp",
- "symbol",
- "name",
- "documentUri",
- "documentHash",
- "decimals",
- "initialTokenQty",
- "totalBurned",
- "totalMinted",
- "validAddresses"
- ])
- })
- })
-
- describe("listBulkToken()", () => {
- const listBulkToken = slpRoute.testableComponents.listBulkToken
-
- it("should throw 400 if tokenIds array is empty", async () => {
- const result = await listBulkToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenIds needs to be an array")
- assert.equal(res.statusCode, 400)
- })
-
- it("should throw 400 error if array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.tokenIds = testArray
-
- const result = await listBulkToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw 400 if tokenId is empty", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockEmptyTokenId)
- }
- req.body.tokenIds = ""
-
- const result = await listBulkToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(
- result.error,
- "tokenIds needs to be an array. Use GET for single tokenId."
- )
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing BITDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- req.body.tokenIds = [
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
- ]
-
- const result = await listBulkToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should return 'not found' for mainnet txid on testnet", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockSingleTokenError)
- }
-
- req.body.tokenIds =
- // testnet
- //"650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
- // mainnet
- ["0b314bc2b2905b8844222871c6b665ae3494117c83b11302824561bb904efb6b"]
-
- const result = await listBulkToken(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["id", "valid"])
- assert.strictEqual(result[0].valid, false)
- })
-
- it("should get token information for single token ID", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockSingleToken)
- }
-
- req.body.tokenIds =
- // testnet
- ["650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"]
-
- const result = await listBulkToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "blockCreated",
- "blockLastActiveMint",
- "blockLastActiveSend",
- "circulatingSupply",
- "containsBaton",
- "mintingBatonStatus",
- "txnsSinceGenesis",
- "versionType",
- "timestamp",
- "symbol",
- "name",
- "documentUri",
- "documentHash",
- "decimals",
- "initialTokenQty",
- "id",
- "totalBurned",
- "totalMinted",
- "validAddresses"
- ])
- })
-
- it("should get token information for multiple token IDs", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockSingleToken)
- }
-
- req.body.tokenIds =
- // testnet
- [
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a",
- "c35a87afad11c8d086c1449ffd8b0a84324e72b15b1bcfdf166a493551b4eea6"
- ]
-
- const result = await listBulkToken(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "blockCreated",
- "blockLastActiveMint",
- "blockLastActiveSend",
- "circulatingSupply",
- "containsBaton",
- "mintingBatonStatus",
- "txnsSinceGenesis",
- "versionType",
- "timestamp",
- "symbol",
- "name",
- "documentUri",
- "documentHash",
- "decimals",
- "initialTokenQty",
- "id",
- "totalBurned",
- "totalMinted",
- "validAddresses"
- ])
- })
- })
-
- describe("balancesForAddress()", () => {
- const balancesForAddress = slpRoute.testableComponents.balancesForAddress
-
- it("should throw 400 if address is empty", async () => {
- const result = await balancesForAddress(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should throw 400 if address is invalid", async () => {
- req.params.address = "badAddress"
-
- const result = await balancesForAddress(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Invalid BCH address.")
- })
-
- it("should throw 400 if address network mismatch", async () => {
- req.params.address =
- "simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk"
-
- const result = await balancesForAddress(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Invalid")
- })
-
- it("should throw 5XX error when network issues", async () => {
- // Save the existing SLPDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- req.params.address = "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5"
-
- const result = await balancesForAddress(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- })
-
- it("should get token balance for an address", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockSingleAddress)
- }
-
- req.params.address = "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7"
-
- const result = await balancesForAddress(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "tokenId",
- "balance",
- "slpAddress",
- "decimalCount"
- ])
- })
- })
-
- describe("balancesForAddressByTokenID()", () => {
- const balancesForAddressByTokenID =
- slpRoute.testableComponents.balancesForAddressByTokenID
-
- it("should throw 400 if address is empty", async () => {
- req.params.address = ""
- req.params.tokenId =
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
- const result = await balancesForAddressByTokenID(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should throw 400 if tokenId is empty", async () => {
- req.params.address =
- "simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk"
- req.params.tokenId = ""
- const result = await balancesForAddressByTokenID(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
-
- it("should throw 400 if address is invalid", async () => {
- req.params.address = "badAddress"
- req.params.tokenId =
- "650dea14c77f4d749608e36e375450c9ac91deb8b1b53e50cb0de2059a52d19a"
-
- const result = await balancesForAddressByTokenID(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Invalid BCH address.")
- })
-
- it("should throw 400 if address network mismatch", async () => {
- req.params.address =
- "simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk"
-
- const result = await balancesForAddressByTokenID(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Invalid")
- })
-
- it("should throw 5XX error when network issues", async () => {
- // Save the existing SLPDB_URL.
- const savedUrl2 = process.env.SLPDB_URL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.SLPDB_URL = "http://fakeurl/api/"
-
- req.params.address = "slptest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvxu67w0ac"
- req.params.tokenId =
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796"
-
- const result = await balancesForAddressByTokenID(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.SLPDB_URL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- })
-
- it("should get token information", async () => {
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockSingleAddress)
- }
-
- req.params.address = "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7"
- req.params.tokenId =
- "6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29"
-
- const result = await balancesForAddressByTokenID(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // TODO - add decimalCount
- // assert.hasAllKeys(result, ["tokenId", "balance", "decimalCount"])
- assert.hasAllKeys(result, ["tokenId", "balance"])
- })
- })
-
- describe("convertAddressSingle()", () => {
- const convertAddressSingle =
- slpRoute.testableComponents.convertAddressSingle
-
- it("should throw 400 if address is empty", async () => {
- req.params.address = ""
- const result = await convertAddressSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
- //
- it("should convert address", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.SLPDB_URL}`)
- .post(``)
- .reply(200, { result: mockData.mockConvert })
- }
-
- req.params.address = "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5"
-
- const result = await convertAddressSingle(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["cashAddress", "legacyAddress", "slpAddress"])
- })
- })
-
- describe("convertAddressBulk()", () => {
- const convertAddressBulk = slpRoute.testableComponents.convertAddressBulk
-
- it("should throw 400 if addresses array is empty", async () => {
- const result = await convertAddressBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "addresses needs to be an array")
- assert.equal(res.statusCode, 400)
- })
-
- it("should throw 400 error if array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await convertAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should error on malformed address", async () => {
- try {
- req.body.addresses = ["bitcoincash:qzs02v05l7qs5s5dwuj0cx5ehjm2c"]
-
- await convertAddressBulk(req, res)
-
- assert.equal(true, false, "Unsupported address format")
- } catch (err) {
- // console.log(`err.message: ${util.inspect(err.message)}`)
-
- assert.include(err.message, `Unsupported address format`)
- }
- })
-
- it("should validate array with single element", async () => {
- req.body.addresses = [
- "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
- ]
-
- const result = await convertAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "slpAddress",
- "cashAddress",
- "legacyAddress"
- ])
- })
-
- it("should validate array with multiple elements", async () => {
- req.body.addresses = [
- "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c",
- "bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0"
- ]
-
- const result = await convertAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "slpAddress",
- "cashAddress",
- "legacyAddress"
- ])
- })
- })
-
- describe("validateBulk()", () => {
- const validateBulk = slpRoute.testableComponents.validateBulk
-
- it("should throw 400 if txid array is empty", async () => {
- const result = await validateBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txids needs to be an array")
- assert.equal(res.statusCode, 400)
- })
-
- it("should throw 400 error if array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.txids = testArray
-
- const result = await validateBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should validate array with single element", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- sandbox
- .stub(slpRoute.testableComponents, "isValidSlpTxid")
- .resolves(true)
- }
-
- req.body.txids = [
- "78d57a82a0dd9930cc17843d9d06677f267777dd6b25055bad0ae43f1b884091"
- ]
-
- const result = await validateBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["txid", "valid"])
- })
-
- it("should validate array with two elements", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- sandbox
- .stub(slpRoute.testableComponents, "isValidSlpTxid")
- .resolves(true)
- }
-
- req.body.txids = [
- "78d57a82a0dd9930cc17843d9d06677f267777dd6b25055bad0ae43f1b884091",
- "82d996847a861b08b1601284ef7d40a1777d019154a6c4ed11571609dd3555ac"
- ]
-
- const result = await validateBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["txid", "valid"])
- assert.equal(result.length, 2)
- })
- })
-
- describe("tokenStatsSingle()", () => {
- const tokenStatsSingle = slpRoute.testableComponents.tokenStats
-
- it("should throw 400 if tokenID is empty", async () => {
- req.params.tokenId = ""
- const result = await tokenStatsSingle(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
- //
- it("should get token stats for tokenId", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.SLPDB_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, {
- t: [
- {
- tokenDetails: mockData.mockTokenDetails,
- tokenStats: mockData.mockTokenStats
- }
- ]
- })
- }
-
- req.params.tokenId =
- "37279c7dc81ceb34d12f03344b601c582e931e05d0e552c29c428bfa39d39af3"
-
- const result = await tokenStatsSingle(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "blockCreated",
- "blockLastActiveMint",
- "blockLastActiveSend",
- "containsBaton",
- "initialTokenQty",
- "mintingBatonStatus",
- "circulatingSupply",
- "decimals",
- "documentHash",
- "versionType",
- "timestamp",
- "documentUri",
- "name",
- "symbol",
- "id",
- "totalBurned",
- "totalMinted",
- "txnsSinceGenesis",
- "validAddresses"
- ])
- })
- })
-
- describe("balancesForTokenSingle()", () => {
- const balancesForTokenSingle =
- slpRoute.testableComponents.balancesForTokenSingle
-
- it("should throw 400 if tokenID is empty", async () => {
- req.params.tokenId = ""
- const result = await balancesForTokenSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
- //
- it("should get balances for tokenId", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.SLPDB_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, {
- a: [mockData.mockBalance]
- })
- }
-
- req.params.tokenId =
- "37279c7dc81ceb34d12f03344b601c582e931e05d0e552c29c428bfa39d39af3"
-
- const result = await balancesForTokenSingle(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result[0], ["tokenId", "slpAddress", "tokenBalance"])
- })
- })
-
- describe("txDetails()", () => {
- let txDetails = slpRoute.testableComponents.txDetails
-
- it("should throw 400 if txid is empty", async () => {
- const result = await txDetails(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should throw 400 for malformed txid", async () => {
- req.params.txid =
- "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457"
-
- const result = await txDetails(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "This is not a txid")
- })
-
- it("should throw 400 for non-existant txid", async () => {
- // Integration test
- if (process.env.TEST !== "unit") {
- req.params.txid =
- "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b94578223333"
-
- const result = await txDetails(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "TXID not found")
- }
- })
-
- it("should get tx details with token info", async () => {
- if (process.env.TEST === "unit") {
- // Mock the slpjs library for unit tests.
- pathStub.BitboxNetwork = slpjsMock.BitboxNetwork
- txDetails = slpRouteStub.testableComponents.txDetails
- }
-
- req.params.txid =
- "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457822d446"
-
- const result = await txDetails(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.hasAnyKeys(result, ["tokenIsValid", "tokenInfo"])
- })
- })
-
- describe("txsTokenIdAddressSingle()", () => {
- const txsTokenIdAddressSingle =
- slpRoute.testableComponents.txsTokenIdAddressSingle
-
- it("should throw 400 if tokenId is empty", async () => {
- req.params.tokenId = ""
- const result = await txsTokenIdAddressSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "tokenId can not be empty")
- })
-
- it("should throw 400 if address is empty", async () => {
- req.params.tokenId =
- "495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a"
- req.params.address = ""
- const result = await txsTokenIdAddressSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
- /*
- it("should get tx details with tokenId and address", async () => {
- if (process.env.TEST === "unit") {
- nock(`${process.env.SLPDB_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, {
- c: mockData.mockTransactions
- })
- }
-
- //req.params.tokenId =
- // "37279c7dc81ceb34d12f03344b601c582e931e05d0e552c29c428bfa39d39af3"
- //req.params.address = "slptest:qr83cu3p7yg9yac7qthwm0nul2ev2kukvsqmes3vl0"
-
- req.params.tokenId =
- "7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796"
- req.params.address = "slptest:qpwa35xq0q0cnmdu0rwzkct369hddzsqpsqdzw6h9h"
-
-
- const result = await txsTokenIdAddressSingle(req, res)
- console.log(`result: ${JSON.stringify(result, null, 2)}`)
-
- assert.hasAnyKeys(result[0], ["txid", "tokenDetails"])
- })
-*/
- })
-})
diff --git a/test/v2/transaction.js b/test/v2/transaction.js
deleted file mode 100644
index 4eb1bdc..0000000
--- a/test/v2/transaction.js
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- TESTS FOR THE TRANSACTION.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- TODO:
- -See "should throw an error for an invalid txid" for detailsSingle:
- --The error handler should be refactored to return an intelligent error message,
- instead of the 503 error it is returning now.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const transactionRoute = require("../../src/routes/v2/transaction")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/transaction-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Transactions", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = transactionRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "transaction", "Returns static string")
- })
- })
-
- describe("#detailsBulk", async () => {
- const detailsBulk = transactionRoute.testableComponents.detailsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body = {
- txids: `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid txid", async () => {
- const fakeTXID = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${fakeTXID}`)
- .reply(400, {
- result: { error: "parameter 1 must be hexadecimal string" }
- })
- }
-
- req.body = {
- txids: [fakeTXID]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should process a single txid", async () => {
- const txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid}`)
- .reply(200, mockData.mockDetails)
- }
-
- req.body = {
- txids: [txid]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- })
-
- it("should process a multiple txids", async () => {
- const txid1 = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
- const txid2 = `8d4fd4dcaa9d8051dc7d862dc23d8aa23e20b77b9c928c49380685459caa7043`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid1}`)
- .reply(200, mockData.mockDetails)
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid2}`)
- .reply(200, mockData.mockDetails)
- }
-
- req.body = {
- txids: [txid1, txid2]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- })
- })
-
- describe("#detailsSingle", () => {
- // details route handler.
- const detailsSingle = transactionRoute.testableComponents.detailsSingle
-
- it("should throw 400 if txid is empty", async () => {
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.txid = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txid can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid txid", async () => {
- if (process.env.TEST !== "unit") {
- req.params.txid = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // The error handling code should probably be updated to respond with a better
- // error message.
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "parameter 1 must be hexadecimal string",
- "Proper error message"
- )
- }
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- const txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
- req.params.txid = txid
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid}`)
- .reply(200, mockData.mockDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.hasAllKeys(result, [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- assert.isArray(result.vin)
- assert.isArray(result.vout)
- })
- })
-})
diff --git a/test/v2/util.js b/test/v2/util.js
deleted file mode 100644
index e550f14..0000000
--- a/test/v2/util.js
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- TESTS FOR THE UTIL.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const utilRoute = require("../../src/routes/v2/util")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/util-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Util", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = utilRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "util", "Returns static string")
- })
- })
-
- describe("#validateAddressSingle", async () => {
- const validateAddress = utilRoute.testableComponents.validateAddressSingle
-
- it("should throw an error for an empty address", async () => {
- const result = await validateAddress(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
-
- const result = await validateAddress(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- })
-
- it("should validate address", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockAddress })
- }
-
- req.params.address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
-
- const result = await validateAddress(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, [
- "isvalid",
- "address",
- "scriptPubKey",
- "ismine",
- "iswatchonly",
- "isscript"
- ])
- })
- })
-
- describe("#validateAddressBulk", async () => {
- const validateAddressBulk = utilRoute.testableComponents.validateAddressBulk
-
- it("should throw an error for an empty body", async () => {
- const result = await validateAddressBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array. Use GET for single address.",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- addresses: `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
- }
-
- const result = await validateAddressBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array. Use GET for single address.",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await validateAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should error on invalid address", async () => {
- req.body = {
- addresses: [`bchtest:qqqk4y6lsl5da64sg5qc3xezmpl`]
- }
-
- const result = await validateAddressBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address. Double check your address is valid",
- "Proper error message"
- )
- })
-
- it("should error on mainnet address when using testnet", async () => {
- req.body = {
- addresses: [`bitcoincash:qrcc3jsqpgwqcdru70sk54sd0g3l04q7c53ycm6ucj`]
- }
-
- const result = await validateAddressBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid network. Trying to use a testnet address on mainnet, or vice versa.",
- "Proper error message"
- )
- })
-
- it("should throw 503 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.body.addresses = [
- `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
- ]
-
- const result = await validateAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- })
-
- it("should validate a single address", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .reply(200, { result: mockData.mockAddress })
- }
-
- req.body.addresses = [
- `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
- ]
-
- const result = await validateAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "isvalid",
- "address",
- "scriptPubKey",
- "ismine",
- "iswatchonly",
- "isscript"
- ])
- })
-
- it("should validate a multiple addresses", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(``)
- .times(2)
- .reply(200, { result: mockData.mockAddress })
- }
-
- req.body.addresses = [
- `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`,
- `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
- ]
-
- const result = await validateAddressBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], [
- "isvalid",
- "address",
- "scriptPubKey",
- "ismine",
- "iswatchonly",
- "isscript"
- ])
- })
- })
-})
diff --git a/test/v3/block.js b/test/v3/block.js
deleted file mode 100644
index 26477f4..0000000
--- a/test/v3/block.js
+++ /dev/null
@@ -1,611 +0,0 @@
-"use strict"
-
-const blockRoute = require("../../src/routes/v3/insight/block")
-const chai = require("chai")
-const assert = chai.assert
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/block-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Block", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", () => {
- // root route handler.
- const root = blockRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "block", "Returns static string")
- })
- })
-
- describe("#detailsByHashSingle", () => {
- const detailsByHash = blockRoute.testableComponents.detailsByHashSingle
-
- it("should throw an error for an empty hash", async () => {
- req.params.hash = ""
-
- const result = await detailsByHash(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hash must not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 50X when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- req.params.hash = "abc123"
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 50X expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should throw an error for invalid hash", async () => {
- req.params.hash = "abc123"
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.params.hash}`)
- .reply(404, "Not found")
- }
-
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.include(result.error, "Not found", "Proper error message")
- })
-
- it("should GET /detailsByHash/:hash", async () => {
- req.params.hash =
- "0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086"
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.params.hash}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- const result = await detailsByHash(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hash",
- "size",
- "height",
- "version",
- "merkleroot",
- "tx",
- "time",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "confirmations",
- "previousblockhash",
- "nextblockhash",
- "reward",
- "isMainChain",
- "poolInfo"
- ])
- assert.isArray(result.tx)
- })
- })
-
- describe("#detailsByHashBulk", () => {
- // details route handler.
- const detailsByHashBulk = blockRoute.testableComponents.detailsByHashBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsByHashBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- hashes:
- "0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086"
- }
-
- const result = await detailsByHashBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "hashes needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.hashes = testArray
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid hash", async () => {
- req.body = {
- hashes: [`abc123`]
- }
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid hash", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- hashes: [
- "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
- ]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsByHashBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single hash", async () => {
- req.body = {
- hashes: [
- "0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086"
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "bits",
- "chainwork",
- "confirmations",
- "difficulty",
- "hash",
- "height",
- "isMainChain",
- "merkleroot",
- "nextblockhash",
- "nonce",
- "poolInfo",
- "previousblockhash",
- "reward",
- "size",
- "time",
- "tx",
- "version"
- ])
- })
-
- it("should get details for multiple hashes", async () => {
- req.body = {
- hashes: [
- `0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086`,
- `0000000000000000009ff8b38118d540e33c262bf6f78fc6863cc444526dc086`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- .reply(200, mockData.mockBlockDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[1]}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
-
- it("should throw an error if hash not found", async () => {
- req.body = {
- hashes: [
- `00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44abcdef`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${req.body.hashes[0]}`)
- //.reply(404, { error: { message: "Not Found" } })
- .reply(404, "Not found")
- }
-
- const result = await detailsByHashBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 404, "HTTP status code 404 expected.")
- assert.include(result.error, "Not found", "Proper error message")
- })
- })
-
- describe("Block Details By Height", () => {
- // block route handler.
- const detailsByHeight = blockRoute.testableComponents.detailsByHeightSingle
-
- it("should throw an error for an empty height", async () => {
- req.params.height = ""
-
- const result = await detailsByHeight(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "height must not be empty",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- // Save the existing RPC URL.
- const savedUrl = process.env.BITCOINCOM_BASEURL
- const savedUrl2 = process.env.RPC_BASEURL
-
- // Manipulate the URL to cause a 500 network error.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api/"
-
- req.params.height = "abc123"
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- process.env.RPC_BASEURL = savedUrl2
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or great expected."
- )
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- })
-
- it("should throw an error for invalid height", async () => {
- req.params.height = "abc123"
-
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- console.log(`process.env.RPC_BASEURL: ${process.env.RPC_BASEURL}`)
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .reply(500, {
- error: {
- code: -1,
- message: "JSON value is not an integer as expected"
- }
- })
- }
-
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "JSON value is not an integer as expected",
- "Proper error message"
- )
- })
-
- it("should GET /detailsByHeight/:height", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .reply(200, { result: mockData.mockBlockHash })
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(
- `/block/00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79`
- )
- .reply(200, mockData.mockBlockDetails)
- }
-
- req.params.height = 500000
-
- const result = await detailsByHeight(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAnyKeys(result, [
- "hash",
- "size",
- "height",
- "version",
- "merkleroot",
- "tx",
- "time",
- "nonce",
- "bits",
- "difficulty",
- "chainwork",
- "confirmations",
- "previousblockhash",
- "nextblockhash",
- "reward",
- "isMainChain",
- "poolInfo"
- ])
- assert.isArray(result.tx)
- })
- })
-
- describe("#detailsByHeightBulk", () => {
- // details route handler.
- const detailsByHeightBulk =
- blockRoute.testableComponents.detailsByHeightBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsByHeightBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "heights needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single height", async () => {
- req.body = {
- heights: 500000
- }
-
- const result = await detailsByHeightBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "heights needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.heights = testArray
-
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw error for an invalid height", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .reply(500, {
- error: {
- code: -1,
- message: "JSON value is not an integer as expected"
- }
- })
- }
-
- req.body.heights = [`abc123`]
-
- const result = await detailsByHeightBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body.heights = [`500000`]
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsByHeightBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single height", async () => {
- req.body.heights = [`500000`]
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .reply(200, { result: mockData.mockBlockHash })
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${mockData.mockBlockHash}`)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "bits",
- "chainwork",
- "confirmations",
- "difficulty",
- "hash",
- "height",
- "isMainChain",
- "merkleroot",
- "nextblockhash",
- "nonce",
- "poolInfo",
- "previousblockhash",
- "reward",
- "size",
- "time",
- "tx",
- "version"
- ])
- })
-
- it("should get details for multiple block heights", async () => {
- req.body = {
- heights: [`500000`, `500001`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.RPC_BASEURL}`)
- .post(uri => uri.includes("/"))
- .times(2)
- .reply(200, { result: mockData.mockBlockHash })
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/block/${mockData.mockBlockHash}`)
- .times(2)
- .reply(200, mockData.mockBlockDetails)
- }
-
- // Call the details API.
- const result = await detailsByHeightBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-})
diff --git a/test/v3/blockchain.js b/test/v3/blockchain.js
index 2101961..503e08a 100644
--- a/test/v3/blockchain.js
+++ b/test/v3/blockchain.js
@@ -11,7 +11,7 @@
const chai = require("chai")
const assert = chai.assert
const nock = require("nock") // HTTP mocking
-const blockchainRoute = require("../../src/routes/v3/blockchain")
+const blockchainRoute = require("../../src/routes/v3/full-node/blockchain")
const util = require("util")
util.inspect.defaultOptions = { depth: 1 }
@@ -107,7 +107,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -149,7 +149,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -201,7 +201,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -252,7 +252,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Network error: Could not communicate with full node",
@@ -499,7 +499,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -540,7 +540,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -580,7 +580,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -626,7 +626,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -678,7 +678,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -823,7 +823,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -840,11 +840,12 @@ describe("#BlockchainRouter", () => {
.reply(200, { result: mockData.mockTxOut })
}
- req.params.txid = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
- req.params.n = 1
+ req.params.txid = `197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d`
+ req.params.n = 0
+ req.query.include_mempool = "true"
const result = await getTxOut(req, res)
- //console.log(`result: ${JSON.stringify(result, null, 2)}`)
+ // console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"bestblock",
@@ -890,7 +891,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
@@ -1027,7 +1028,7 @@ describe("#BlockchainRouter", () => {
// Restore the saved URL.
process.env.RPC_BASEURL = savedUrl2
- assert.equal(res.statusCode, 503, "HTTP status code 503 expected.")
+ assert.isAbove(res.statusCode, 499, "HTTP status code 503 expected.")
assert.include(
result.error,
"Could not communicate with full node",
diff --git a/test/v3/control.js b/test/v3/control.js
index dd2d799..e651b26 100644
--- a/test/v3/control.js
+++ b/test/v3/control.js
@@ -11,7 +11,7 @@
const chai = require("chai")
const assert = chai.assert
-const controlRoute = require("../../src/routes/v3/control")
+const controlRoute = require("../../src/routes/v3/full-node/control")
const nock = require("nock") // HTTP mocking
let originalEnvVars // Used during transition from integration to unit tests.
diff --git a/test/v3/insight-address.js b/test/v3/insight-address.js
deleted file mode 100644
index e5a280b..0000000
--- a/test/v3/insight-address.js
+++ /dev/null
@@ -1,1348 +0,0 @@
-/*
- TESTS FOR THE ADDRESS.JS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- To-Do:
- -/details/:address
- --Verify to/from query options work correctly.
- -GET /unconfirmed/:address & POST /unconfirmed
- --Should initiate a transfer of BCH to verify unconfirmed TX.
- ---This would be more of an e2e test.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const addressRoute = require("../../src/routes/v3/insight/address")
-const nock = require("nock") // HTTP mocking
-
-let originalUrl // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/address-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Insight Address", () => {
- let req, res
-
- before(() => {
- originalUrl = process.env.BITCOINCOM_BASEURL
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit")
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- // console.log(`Testing type is: ${process.env.TEST}`)
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- process.env.BITCOINCOM_BASEURL = originalUrl
- })
-
- describe("#root", () => {
- // root route handler.
- const root = addressRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "address", "Returns static string")
- })
- })
-
- describe("#AddressDetailsBulk", () => {
- // details route handler.
- const detailsBulk = addressRoute.testableComponents.detailsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsBulk(req, res)
- //console.log(`network issue result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 500 expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page defaults to 0
- assert.equal(result[0].currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`],
- page: 5
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page is same as requested
- assert.equal(result[0].currentPage, 5)
- })
-
- it("should calculate the total number of pages", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result[0].pagesTotal, 1)
- })
-
- it("should get details for a single address", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.equal(result.length, 1, "Array with one entry")
- assert.hasAllKeys(result[0], [
- "balance",
- "balanceSat",
- "totalReceived",
- "totalReceivedSat",
- "totalSent",
- "totalSentSat",
- "unconfirmedBalance",
- "unconfirmedBalanceSat",
- "unconfirmedTxApperances",
- "txApperances",
- "transactions",
- "legacyAddress",
- "cashAddress",
- "currentPage",
- "pagesTotal"
- ])
- })
-
- it("should get details for multiple addresses", async () => {
- req.body = {
- addresses: [
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`,
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-
- describe("#AddressDetailsSingle", () => {
- // details route handler.
- const detailsSingle = addressRoute.testableComponents.detailsSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert current page defaults to 0
- assert.equal(result.currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- req.query.page = 5
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
-
- // Assert current page is same as requested
- assert.equal(result.currentPage, 5)
- })
-
- it("should calculate the total number of pages", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
-
- assert.equal(result.pagesTotal, 1)
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockAddressDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.hasAllKeys(result, [
- "balance",
- "balanceSat",
- "totalReceived",
- "totalReceivedSat",
- "totalSent",
- "totalSentSat",
- "unconfirmedBalance",
- "unconfirmedBalanceSat",
- "unconfirmedTxApperances",
- "txApperances",
- "transactions",
- "legacyAddress",
- "cashAddress",
- "currentPage",
- "pagesTotal"
- ])
- })
- })
-
- describe("#AddressUtxoBulk", () => {
- // utxo route handler.
- const utxoBulk = addressRoute.testableComponents.utxoBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- const result = await utxoBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await utxoBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get utxos for a single address", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result, "result should be an array")
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result[0], [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- // Validate the UTXO data structure.
- assert.hasAnyKeys(result[0].utxos[0], [
- "txid",
- "vout",
- "amount",
- "satoshis",
- "height",
- "confirmations"
- ])
- })
-
- it("should get utxos for mulitple addresses", async () => {
- req.body = {
- addresses: [
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`,
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await utxoBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
- })
-
- describe("#AddressUtxoSingle", () => {
- // details route handler.
- const utxoSingle = addressRoute.testableComponents.utxoSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await utxoSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- const result = await utxoSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await utxoSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await utxoSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result, [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- // Validate the UTXO data structure.
- assert.hasAnyKeys(result.utxos[0], [
- "txid",
- "vout",
- "amount",
- "satoshis",
- "height",
- "confirmations"
- ])
- })
- })
-
- describe("#AddressUnconfirmedBulk", () => {
- // unconfirmed route handler.
- const unconfirmedBulk = addressRoute.testableComponents.unconfirmedBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await unconfirmedBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- const result = await unconfirmedBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await unconfirmedBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get unconfirmed data for a single address", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
- //console.log(`result[0].utxos: ${util.inspect(result[0].utxos)}`)
-
- assert.isArray(result, "result should be an array")
-
- // Dev note: Unconfirmed TXs are hard to test in an integration test because
- // the nature of an unconfirmed transation is transient. It quickly becomes
- // confirmed and thus should not show up.
- })
-
- it("should get unconfirmed data for an array of addresses", async () => {
- req.body = {
- addresses: [
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`,
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
-
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedBulk(req, res)
-
- assert.isArray(result)
- })
- })
-
- describe("#AddressUnconfirmedSingle", () => {
- // details route handler.
- const unconfirmedSingle = addressRoute.testableComponents.unconfirmedSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await unconfirmedSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- const result = await unconfirmedSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await unconfirmedSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxoDetails)
- }
-
- // Call the details API.
- const result = await unconfirmedSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Each element should have these primary properties.
- assert.hasAllKeys(result, [
- "utxos",
- "legacyAddress",
- "cashAddress",
- "scriptPubKey"
- ])
-
- assert.isArray(result.utxos)
- })
- })
-
- describe("#AddressTransactionsBulk", () => {
- // unconfirmed route handler.
- const transactionsBulk = addressRoute.testableComponents.transactionsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await transactionsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- const result = await transactionsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api"
-
- const result = await transactionsBulk(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsBulk(req, res)
-
- // Assert current page defaults to 0
- assert.equal(result[0].currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`],
- page: 5
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsBulk(req, res)
-
- // Assert current page is same as requested
- assert.equal(result[0].currentPage, 5)
- })
-
- it("should get transactions for a single address", async () => {
- req.body = {
- addresses: [`bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsBulk(req, res)
-
- assert.isArray(result, "result should be an array")
-
- assert.exists(result[0].pagesTotal)
- assert.exists(result[0].currentPage)
- assert.exists(result[0].txs)
- assert.isArray(result[0].txs)
- assert.exists(result[0].legacyAddress)
- assert.exists(result[0].cashAddress)
- })
-
- it("should get transactions for an array of addresses", async () => {
- req.body = {
- addresses: [
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`,
- `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsBulk(req, res)
-
- assert.isArray(result, "result should be an array")
-
- assert.equal(result.length, 2, "Array should have 2 elements")
- })
- })
-
- describe("#AddressTransactionsSingle", () => {
- // details route handler.
- const transactionsSingle =
- addressRoute.testableComponents.transactionsSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await transactionsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- const result = await transactionsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await transactionsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should default to page 0", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsSingle(req, res)
-
- // Assert current page defaults to 0
- assert.equal(result.currentPage, 0)
- })
-
- it("should process the requested page", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
- req.query.page = 5
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the endpoint
- const result = await transactionsSingle(req, res)
-
- // Assert current page is same as requested
- assert.equal(result.currentPage, 5)
- })
-
- it("should get details for a single address", async () => {
- req.params.address = `bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockTransactions)
- }
-
- // Call the details API.
- const result = await transactionsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.exists(result.pagesTotal)
- assert.exists(result.currentPage)
- assert.exists(result.txs)
- assert.isArray(result.txs)
- assert.exists(result.legacyAddress)
- assert.exists(result.cashAddress)
- })
- })
-
- describe("#AddressFromXPubSingle", () => {
- // details route handler.
- const fromXPubSingle = addressRoute.testableComponents.fromXPubSingle
-
- it("should throw 400 if xpub is empty", async () => {
- const result = await fromXPubSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "xpub can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.xpub = [
- `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
- ]
-
- const result = await fromXPubSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "xpub can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.xpub = `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await fromXPubSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should create an address from xpub", async () => {
- req.params.xpub = `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
-
- // Mock the Insight URL for unit tests.
- // TODO add unit test
- // if (process.env.TEST === "unit") {
- // nock(`${process.env.BITCOINCOM_BASEURL}`)
- // .get(
- // `/txs/?address=bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4&pageNum=0`
- // )
- // .reply(200, mockData.mockTransactions)
- // }
-
- // Call the details API.
- const result = await fromXPubSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.exists(result.legacyAddress)
- assert.exists(result.cashAddress)
- })
- })
-})
diff --git a/test/v3/integration/bitcore.js b/test/v3/integration/bitcore.js
deleted file mode 100644
index fd6cf67..0000000
--- a/test/v3/integration/bitcore.js
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- TESTS FOR THE BITCORE.JS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- To-Do:
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const bitcoreRoute = require("../../src/routes/v3/bitcore")
-const nock = require("nock") // HTTP mocking
-
-let originalUrl // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/bitcore-mock")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Bitcore Router", () => {
- let req, res, mockServerUrl
-
- before(() => {
- originalUrl = process.env.BITCORE_URL
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCORE_URL = "http://fakeurl/api/"
- mockServerUrl = `http://fakeurl`
- }
- // console.log(`Testing type is: ${process.env.TEST}`)
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- process.env.BITCORE_URL = originalUrl
- })
-
- describe("#root", () => {
- // root route handler.
- const root = bitcoreRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
-
- assert.equal(result.status, "address", "Returns static string")
- })
- })
-
- describe("#Balance Single", () => {
- // details route handler.
- const balanceSingle = bitcoreRoute.testableComponents.balanceSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await balanceSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await balanceSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await balanceSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await balanceSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCORE_URL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCORE_URL = "http://fakeurl/api/"
-
- const result = await balanceSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCORE_URL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCORE_URL = savedUrl
- }
- })
-
- it("should get balance for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCORE_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockBalance)
- }
-
- // Call the details API.
- const result = await balanceSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["confirmed", "unconfirmed", "balance"])
- assert.isNumber(result.confirmed)
- assert.isNumber(result.unconfirmed)
- assert.isNumber(result.balance)
- })
- })
-
- describe("#Balance Bulk", () => {
- // details route handler.
- const balanceBulk = bitcoreRoute.testableComponents.balanceBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await balanceBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await balanceBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await balanceBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await balanceBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await balanceBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await balanceBulk(req, res)
- //console.log(`network issue result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 500 expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockBalance)
- }
-
- // Call the details API.
- const result = await balanceBulk(req, res)
- // console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAllKeys(result[0], ["confirmed", "unconfirmed", "balance"])
- assert.isNumber(result[0].confirmed)
- assert.isNumber(result[0].unconfirmed)
- assert.isNumber(result[0].balance)
- })
-
- it("should get details for multiple addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockBalance)
- }
-
- // Call the details API.
- const result = await balanceBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.equal(result.length, 2, "2 outputs for 2 inputs")
- })
- })
-
- describe("#UTXOs Single", () => {
- // details route handler.
- const utxosSingle = bitcoreRoute.testableComponents.utxosSingle
-
- it("should throw 400 if address is empty", async () => {
- const result = await utxosSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "address can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.address = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await utxosSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "address can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.params.address = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await utxosSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should detect a network mismatch", async () => {
- req.params.address = `bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`
-
- const result = await utxosSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCORE_URL
-
- try {
- req.params.address = `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCORE_URL = "http://fakeurl/api/"
-
- const result = await utxosSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCORE_URL = savedUrl
-
- assert.equal(res.statusCode, 500, "HTTP status code 500 expected.")
- assert.include(result.error, "ENOTFOUND", "Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCORE_URL = savedUrl
- }
- })
-
- it("should get utxos for a single address", async () => {
- req.params.address = `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCORE_URL}`)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxos)
- }
-
- // Call the details API.
- const result = await utxosSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "_id",
- "chain",
- "network",
- "coinbase",
- "mintIndex",
- "spentTxid",
- "mintTxid",
- "mintHeight",
- "spentHeight",
- "address",
- "script",
- "value",
- "confirmations"
- ])
- })
- })
-
- describe("#UTXO Bulk", () => {
- // details route handler.
- const utxosBulk = bitcoreRoute.testableComponents.utxosBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single address", async () => {
- req.body = {
- address: `qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
- }
-
- const result = await utxosBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "addresses needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid address", async () => {
- req.body = {
- addresses: [`02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
- }
-
- const result = await utxosBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "Invalid BCH address",
- "Proper error message"
- )
- })
-
- it("should throw 400 error if addresses array is too large", async () => {
- const testArray = []
- for (var i = 0; i < 25; i++) testArray.push("")
-
- req.body.addresses = testArray
-
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "Array too large")
- })
-
- it("should detect a network mismatch", async () => {
- req.body = {
- addresses: [`bitcoincash:qqqvv56zepke5k0xeaehlmjtmkv9ly2uzgkxpajdx3`]
- }
-
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(result.error, "Invalid network", "Proper error message")
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await utxosBulk(req, res)
- //console.log(`network issue result: ${util.inspect(result)}`)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(res.statusCode, 499, "HTTP status code 500 expected.")
- //assert.include(result.error, "ENOTFOUND", "Error message expected")
- assert.include(
- result.error,
- "Network error: Could not communicate",
- "Error message expected"
- )
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single address", async () => {
- req.body = {
- addresses: [`bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .reply(200, mockData.mockUtxos)
- }
-
- // Call the details API.
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.isArray(result[0])
- assert.hasAnyKeys(result[0][0], [
- "_id",
- "chain",
- "network",
- "coinbase",
- "mintIndex",
- "spentTxid",
- "mintTxid",
- "mintHeight",
- "spentHeight",
- "address",
- "script",
- "value",
- "confirmations"
- ])
- })
-
- it("should get details for multiple addresses", async () => {
- req.body = {
- addresses: [
- `bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4`,
- `bchtest:qzknfggae0av6yvxk77gmyq7syc67yux6sk80haqyr`
- ]
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(mockServerUrl)
- .get(uri => uri.includes("/"))
- .times(2)
- .reply(200, mockData.mockUtxos)
- }
-
- // Call the details API.
- const result = await utxosBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.isArray(result[0])
- assert.hasAnyKeys(result[0][0], [
- "_id",
- "chain",
- "network",
- "coinbase",
- "mintIndex",
- "spentTxid",
- "mintTxid",
- "mintHeight",
- "spentHeight",
- "address",
- "script",
- "value",
- "confirmations"
- ])
- })
- })
-})
diff --git a/test/v3/integration/rate-limits.js b/test/v3/integration/rate-limits.js
index e487d2d..99ba139 100644
--- a/test/v3/integration/rate-limits.js
+++ b/test/v3/integration/rate-limits.js
@@ -14,8 +14,11 @@ const axios = require("axios")
const util = require("util")
util.inspect.defaultOptions = { depth: 1 }
-const SERVER = `http://192.168.0.36:12400/v3/`
-//const SERVER = `http://localhost:3000/v2/`
+// const SERVER = `http://192.168.0.36:12400/v3/`
+const SERVER = `http://localhost:3000/v3/`
+
+const TEST_JWT =
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYTc5ZDk4OTYyMjRjNjM2MmQwYzkwMiIsImlhdCI6MTU3MTUzOTU1MSwiZXhwIjoxNTc0MTMxNTUxfQ.PfPW_Z2NYT1O2zUHXopcz2aLGHSGudaKOIGnt7SuAi4"
describe("#rate limits", () => {
it("should get control/getNetworkInfo() with no auth", async () => {
@@ -26,7 +29,7 @@ describe("#rate limits", () => {
const result = await axios(options)
//console.log(`result.status: ${result.status}`)
- //console.log(`result.data: ${util.inspect(result.data)}`)
+ // console.log(`result.data: ${util.inspect(result.data)}`)
assert.equal(result.status, 200)
assert.hasAnyKeys(result.data, ["version"])
@@ -130,4 +133,33 @@ describe("#rate limits", () => {
assert.include(err.response.data.error, "Too many requests")
}
})
+
+ it("should unlock pro-tier for a valid JWT token", async () => {
+ try {
+ // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
+ const options = {
+ method: "GET",
+ url: `${SERVER}control/`,
+ headers: {
+ Authorization: `Token ${TEST_JWT}`
+ }
+ }
+
+ const promises = []
+ for (let i = 0; i < 60; i++) {
+ const promise = axios(options)
+ promises.push(promise)
+ }
+
+ await Promise.all(promises)
+
+ //assert.equal(true, false, "Unexpected result!")
+ assert.equal(true, true, "Not throwing an error is a pass!")
+ } catch (err) {
+ console.log(`err.response: ${util.inspect(err.response)}`)
+
+ assert.equal(true, false, "Unexpected result!")
+ }
+ // Override default timeout for this test.
+ }).timeout(20000)
})
diff --git a/test/v3/mining.js b/test/v3/mining.js
index e9a8b65..7ba81c4 100644
--- a/test/v3/mining.js
+++ b/test/v3/mining.js
@@ -10,7 +10,7 @@
const chai = require("chai")
const assert = chai.assert
-const miningRoute = require("../../src/routes/v3/mining")
+const miningRoute = require("../../src/routes/v3/full-node/mining")
const nock = require("nock") // HTTP mocking
let originalEnvVars // Used during transition from integration to unit tests.
diff --git a/test/v3/rate-limits.js b/test/v3/rate-limits.js
index 4ccb978..50d7ca6 100644
--- a/test/v3/rate-limits.js
+++ b/test/v3/rate-limits.js
@@ -13,12 +13,16 @@ const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
// Libraries under test
let rateLimitMiddleware = require("../../src/middleware/route-ratelimit")
-const controlRoute = require("../../src/routes/v3/control")
+const controlRoute = require("../../src/routes/v3/full-node/control")
+const jwtAuth = require("../../src/middleware/jwt-auth")
let req, res, next
let originalEnvVars // Used during transition from integration to unit tests.
-describe("#route-ratelimits", () => {
+// JWT token used in tests.
+const jwt = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWRlM2Y1NzM5ZTZjMGZmMDM0YjlhMSIsImlhdCI6MTU3MTY3NzQ1MCwiZXhwIjoxNTc0MjY5NDUwfQ.SSz7F7ETyBB3eoNG2VKCzPOhddtB-vrtmEoj7PxicrQ`
+
+describe("#route-ratelimits & jwt-auth", () => {
before(() => {
// Save existing environment variables.
originalEnvVars = {
@@ -27,13 +31,16 @@ describe("#route-ratelimits", () => {
RPC_USERNAME: process.env.RPC_USERNAME,
RPC_PASSWORD: process.env.RPC_PASSWORD
}
+
+ if (!process.env.JWT_AUTH_SERVER)
+ process.env.JWT_AUTH_SERVER = `http://fakeurl.com/`
})
// Setup the mocks before each test.
beforeEach(() => {
// Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
+ req = Object.assign({}, mockReq)
+ res = Object.assign({}, mockRes)
next = mockNext
// Explicitly reset the parmas and body.
@@ -42,6 +49,104 @@ describe("#route-ratelimits", () => {
req.query = {}
})
+ describe("#jwt-auth.js", () => {
+ describe("#getTokenFromHeaders", () => {
+ it(`should populate the req.locals object correctly`, () => {
+ // Initialize req.locals
+ req.locals = {
+ proLimit: false,
+ apiLevel: 0
+ }
+
+ const header = `Token ${jwt}`
+ req.headers.authorization = header
+
+ jwtAuth.getTokenFromHeaders(req, res, next)
+
+ // console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
+
+ assert.property(req.locals, "proLimit")
+ assert.property(req.locals, "apiLevel")
+ assert.property(req.locals, "jwtToken")
+ assert.equal(req.locals.jwtToken, jwt)
+ })
+ })
+
+ // TODO: This code has been refactored and these unit tests no longer apply.
+ // I think I forgot to create new unit tests to reflect the change in code though.
+ /*
+ describe("#routeAccess", () => {
+ it("should do nothing if req.locals.jwtToken is undefined", () => {
+ // Initialize req.locals
+ req.locals = {
+ proLimit: false,
+ apiLevel: 0
+ }
+ req.url = "/insight/address/details"
+
+ // Reset the history of the stub and assert it has not been called.
+ res.status.resetHistory()
+ assert.equal(res.status.called, false, "stub history reset")
+
+ jwtAuth.routeAccess(req, res, next)
+
+ // console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
+ assert.equal(
+ res.status.called,
+ false,
+ "stub should NOT have been called."
+ )
+ })
+
+ it("should throw error if full-node tier tries to access indexer", () => {
+ // Initialize req.locals
+ req.locals = {
+ proLimit: true,
+ apiLevel: 10,
+ jwtToken: jwt
+ }
+ req.url = "/insight/address/details"
+
+ try {
+ res.status.resetHistory()
+ assert.equal(res.status.called, false, "stub history reset")
+
+ jwtAuth.routeAccess(req, res, next)
+
+ assert.equal(res.status.called, true, "stub should have been called.")
+ } catch (err) {
+ console.log(`caught error: `, err)
+ }
+ })
+
+ it("should allow indexer tier tries access indexer endpoints", () => {
+ // Initialize req.locals
+ req.locals = {
+ proLimit: true,
+ apiLevel: 20,
+ jwtToken: jwt
+ }
+ req.url = "/insight/address/details"
+
+ try {
+ res.status.resetHistory()
+ assert.equal(res.status.called, false, "stub history reset")
+
+ jwtAuth.routeAccess(req, res, next)
+
+ assert.equal(
+ res.status.called,
+ false,
+ "stub should NOT have been called."
+ )
+ } catch (err) {
+ console.log(`caught error: `, err)
+ }
+ })
+ })
+ */
+ })
+
describe("#routeRateLimit", () => {
let routeRateLimit = rateLimitMiddleware.routeRateLimit
const getInfo = controlRoute.testableComponents.getInfo
@@ -59,12 +164,67 @@ describe("#route-ratelimits", () => {
assert.equal(next.called, true)
})
- it("should trigger rate-limit handler if rate limits exceeds 25 request per minute", async () => {
+ it("should trigger rate-limit handler if rate limits exceeds 5 request per minute", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
- for (let i = 0; i < 35; i++) {
+ for (let i = 0; i < 5; i++) {
+ next.reset() // reset the stubbed next() function.
+
+ await routeRateLimit(req, res, next)
+ //console.log(`next() called: ${next.called}`)
+ }
+
+ // Note: next() will be called unless the rate-limit kicks in.
+ assert.equal(
+ next.called,
+ false,
+ `next should not be called if rate limit was triggered.`
+ )
+ })
+
+ it("should NOT trigger rate-limit for free-tier at 5 RPM", async () => {
+ // Clear the require cache before running this test.
+ delete require.cache[
+ require.resolve("../../src/middleware/route-ratelimit")
+ ]
+ rateLimitMiddleware = require("../../src/middleware/route-ratelimit")
+ routeRateLimit = rateLimitMiddleware.routeRateLimit
+
+ req.baseUrl = "/v3"
+ req.path = "/control/getNetworkInfo"
+ req.method = "GET"
+
+ req.locals.proLimit = true
+ req.locals.apiLevel = 0
+
+ for (let i = 0; i < 5; i++) {
+ next.reset() // reset the stubbed next() function.
+
+ await routeRateLimit(req, res, next)
+ //console.log(`next() called: ${next.called}`)
+ }
+
+ //console.log(`req.locals after test: ${util.inspect(req.locals)}`)
+
+ // Note: next() will be called unless the rate-limit kicks in.
+ assert.equal(
+ next.called,
+ true,
+ `next should be called if rate limit was not triggered.`
+ )
+ })
+
+ it("should trigger rate-limit for free tier 10 RPM", async () => {
+ req.baseUrl = "/v3"
+ req.path = "/control/getNetworkInfo"
+ req.method = "GET"
+
+ req.locals.proLimit = true
+ req.locals.apiLevel = 0
+
+ for (let i = 0; i < 12; i++) {
next.reset() // reset the stubbed next() function.
await routeRateLimit(req, res, next)
@@ -92,11 +252,7 @@ describe("#route-ratelimits", () => {
req.method = "GET"
req.locals.proLimit = true
-
- //console.log(`req.locals before test: ${util.inspect(req.locals)}`)
-
- // Prepare the authorization header
- //req.headers.authorization = generateAuthHeader("BITBOX")
+ req.locals.apiLevel = 10
for (let i = 0; i < 25; i++) {
next.reset() // reset the stubbed next() function.
@@ -128,13 +284,9 @@ describe("#route-ratelimits", () => {
req.method = "GET"
req.locals.proLimit = true
+ req.locals.apiLevel = 10
- //console.log(`req.locals before test: ${util.inspect(req.locals)}`)
-
- // Prepare the authorization header
- //req.headers.authorization = generateAuthHeader("BITBOX")
-
- for (let i = 0; i < 400; i++) {
+ for (let i = 0; i < 150; i++) {
next.reset() // reset the stubbed next() function.
await routeRateLimit(req, res, next)
diff --git a/test/v3/raw-transactions.js b/test/v3/raw-transactions.js
index c6af05e..014f9b5 100644
--- a/test/v3/raw-transactions.js
+++ b/test/v3/raw-transactions.js
@@ -14,7 +14,7 @@
const chai = require("chai")
const assert = chai.assert
-const rawtransactions = require("../../src/routes/v3/rawtransactions")
+const rawtransactions = require("../../src/routes/v3/full-node/rawtransactions")
const nock = require("nock") // HTTP mocking
let originalEnvVars // Used during transition from integration to unit tests.
@@ -692,7 +692,7 @@ describe("#Raw-Transactions", () => {
// Integration test
} else {
assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "transaction already in block chain")
+ assert.include(result.error, "Missing inputs")
}
})
})
@@ -800,7 +800,7 @@ describe("#Raw-Transactions", () => {
// Integration test
} else {
assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "transaction already in block chain")
+ assert.include(result.error, "Missing inputs")
}
})
})
diff --git a/test/v3/slp.js b/test/v3/slp.js
index 3592ae9..88f70ae 100644
--- a/test/v3/slp.js
+++ b/test/v3/slp.js
@@ -429,7 +429,7 @@ describe("#SLP", () => {
])
})
})
-
+*/
describe("balancesForAddress()", () => {
const balancesForAddress = slpRoute.testableComponents.balancesForAddress
@@ -599,7 +599,7 @@ describe("#SLP", () => {
})
}
})
-
+ /*
describe("balancesForAddressByTokenID()", () => {
const balancesForAddressByTokenID =
slpRoute.testableComponents.balancesForAddressByTokenID
diff --git a/test/v3/transaction.js b/test/v3/transaction.js
deleted file mode 100644
index 2450134..0000000
--- a/test/v3/transaction.js
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- TESTS FOR THE TRANSACTION.TS LIBRARY
-
- This test file uses the environment variable TEST to switch between unit
- and integration tests. By default, TEST is set to 'unit'. Set this variable
- to 'integration' to run the tests against BCH mainnet.
-
- TODO:
- -See "should throw an error for an invalid txid" for detailsSingle:
- --The error handler should be refactored to return an intelligent error message,
- instead of the 503 error it is returning now.
-*/
-
-"use strict"
-
-const chai = require("chai")
-const assert = chai.assert
-const transactionRoute = require("../../src/routes/v3/insight/transaction")
-const nock = require("nock") // HTTP mocking
-
-let originalEnvVars // Used during transition from integration to unit tests.
-
-// Mocking data.
-const { mockReq, mockRes } = require("./mocks/express-mocks")
-const mockData = require("./mocks/transaction-mocks")
-
-// Used for debugging.
-const util = require("util")
-util.inspect.defaultOptions = { depth: 1 }
-
-describe("#Transactions", () => {
- let req, res
-
- before(() => {
- // Save existing environment variables.
- originalEnvVars = {
- BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
- RPC_BASEURL: process.env.RPC_BASEURL,
- RPC_USERNAME: process.env.RPC_USERNAME,
- RPC_PASSWORD: process.env.RPC_PASSWORD
- }
-
- // Set default environment variables for unit tests.
- if (!process.env.TEST) process.env.TEST = "unit"
- if (process.env.TEST === "unit") {
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
- process.env.RPC_BASEURL = "http://fakeurl/api"
- process.env.RPC_USERNAME = "fakeusername"
- process.env.RPC_PASSWORD = "fakepassword"
- }
- })
-
- // Setup the mocks before each test.
- beforeEach(() => {
- // Mock the req and res objects used by Express routes.
- req = mockReq
- res = mockRes
-
- // Explicitly reset the parmas and body.
- req.params = {}
- req.body = {}
- req.query = {}
-
- // Activate nock if it's inactive.
- if (!nock.isActive()) nock.activate()
- })
-
- afterEach(() => {
- // Clean up HTTP mocks.
- nock.cleanAll() // clear interceptor list.
- nock.restore()
- })
-
- after(() => {
- // Restore any pre-existing environment variables.
- process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
- process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
- process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
- process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
- })
-
- describe("#root", async () => {
- // root route handler.
- const root = transactionRoute.testableComponents.root
-
- it("should respond to GET for base route", async () => {
- const result = root(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(result.status, "transaction", "Returns static string")
- })
- })
-
- describe("#detailsBulk", async () => {
- const detailsBulk = transactionRoute.testableComponents.detailsBulk
-
- it("should throw an error for an empty body", async () => {
- req.body = {}
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should error on non-array single txid", async () => {
- req.body = {
- txids: `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
- }
-
- const result = await detailsBulk(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txids needs to be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid txid", async () => {
- const fakeTXID = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${fakeTXID}`)
- .reply(400, {
- result: { error: "parameter 1 must be hexadecimal string" }
- })
- }
-
- req.body = {
- txids: [fakeTXID]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- })
-
- it("should process a single txid", async () => {
- const txid = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid}`)
- .reply(200, mockData.mockDetails)
- }
-
- req.body = {
- txids: [txid]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- })
-
- it("should process a multiple txids", async () => {
- const txid1 = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
- const txid2 = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid1}`)
- .reply(200, mockData.mockDetails)
- }
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid2}`)
- .reply(200, mockData.mockDetails)
- }
-
- req.body = {
- txids: [txid1, txid2]
- }
-
- const result = await detailsBulk(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.isArray(result)
- assert.hasAnyKeys(result[0], [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- })
- })
-
- describe("#detailsSingle", () => {
- // details route handler.
- const detailsSingle = transactionRoute.testableComponents.detailsSingle
-
- it("should throw 400 if txid is empty", async () => {
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- assert.hasAllKeys(result, ["error"])
- assert.include(result.error, "txid can not be empty")
- })
-
- it("should error on an array", async () => {
- req.params.txid = [`qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`]
-
- const result = await detailsSingle(req, res)
-
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "txid can not be an array",
- "Proper error message"
- )
- })
-
- it("should throw an error for an invalid txid", async () => {
- if (process.env.TEST !== "unit") {
- req.params.txid = `02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c`
-
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // The error handling code should probably be updated to respond with a better
- // error message.
- assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
- assert.include(
- result.error,
- "parameter 1 must be hexadecimal string",
- "Proper error message"
- )
- }
- })
-
- it("should throw 500 when network issues", async () => {
- const savedUrl = process.env.BITCOINCOM_BASEURL
-
- try {
- req.params.txid = `6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40`
-
- // Switch the Insight URL to something that will error out.
- process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
-
- const result = await detailsSingle(req, res)
-
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
-
- assert.isAbove(
- res.statusCode,
- 499,
- "HTTP status code 500 or greater expected."
- )
- //assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
- } catch (err) {
- // Restore the saved URL.
- process.env.BITCOINCOM_BASEURL = savedUrl
- }
- })
-
- it("should get details for a single txid", async () => {
- const txid = `2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266`
- req.params.txid = txid
-
- // Mock the Insight URL for unit tests.
- if (process.env.TEST === "unit") {
- nock(`${process.env.BITCOINCOM_BASEURL}`)
- .get(`/tx/${txid}`)
- .reply(200, mockData.mockDetails)
- }
-
- // Call the details API.
- const result = await detailsSingle(req, res)
- //console.log(`result: ${util.inspect(result)}`)
-
- // Assert that required fields exist in the returned object.
- assert.hasAllKeys(result, [
- "txid",
- "version",
- "locktime",
- "vin",
- "vout",
- "blockhash",
- "blockheight",
- "confirmations",
- "time",
- "blocktime",
- "valueOut",
- "size",
- "valueIn",
- "fees"
- ])
- assert.isArray(result.vin)
- assert.isArray(result.vout)
- })
- })
-})
diff --git a/test/v3/util.js b/test/v3/util.js
index b35686f..9028d23 100644
--- a/test/v3/util.js
+++ b/test/v3/util.js
@@ -350,9 +350,11 @@ describe("#Util", () => {
)
})
- it("should generate transaction for valid token sweep", async () => {
- // Mock the RPC call for unit tests.
- if (process.env.TEST === "unit") {
+ // Unit test only.
+ if (process.env.TEST === "unit") {
+ it("should generate transaction for valid token sweep", async () => {
+ // Mock the RPC call for unit tests.
+
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
@@ -370,24 +372,24 @@ describe("#Util", () => {
sandbox
.stub(utilRouteInst.bchjs.SLP.Utils, "tokenUtxoDetails")
.resolves(mockData.mockIsTokenUtxos)
- }
- // Mock sendRawTransaction() so that the hex does not actually get broadcast
- // to the network.
- sandbox
- .stub(utilRouteInst.bchjs.RawTransactions, "sendRawTransaction")
- .resolves("test-txid")
+ // Mock sendRawTransaction() so that the hex does not actually get broadcast
+ // to the network.
+ sandbox
+ .stub(utilRouteInst.bchjs.RawTransactions, "sendRawTransaction")
+ .resolves("test-txid")
- req.body = {
- wif: "L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt",
- toAddr: "bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p"
- }
+ req.body = {
+ wif: "L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt",
+ toAddr: "bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p"
+ }
- const result = await utilRouteInst.sweepWif(req, res)
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
+ const result = await utilRouteInst.sweepWif(req, res)
+ // console.log(`result: ${JSON.stringify(result, null, 2)}`)
- assert.equal(result, "test-txid")
- })
+ assert.equal(result, "test-txid")
+ })
+ }
it("should return balance if balance-only is true", async () => {
// Mock the RPC call for unit tests.