feat(v4): Deleting all v4 routes and tests

This commit is contained in:
Chris Troutner
2022-03-13 07:59:42 -07:00
parent b472d15848
commit 29b51e9437
52 changed files with 5 additions and 21082 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-164
View File
@@ -1,164 +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/v4/full-node/control')
const uut = new ControlRoute()
const sinon = require('sinon')
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
let sandbox
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.
})
// 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 = {}
sandbox = sinon.createSandbox()
})
afterEach(() => {
// Restore Sandbox
sandbox.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 = uut.root(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(result.status, 'control', 'Returns static string')
})
})
describe('#GetNetworkInfo', () => {
// const getNetworkInfo = controlRoute.testableComponents.getNetworkInfo
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/'
await uut.getNetworkInfo(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('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
const result = await uut.getNetworkInfo(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('returns proper error when downstream service is down', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNREFUSED' })
const result = await uut.getNetworkInfo(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('should get info on the full node', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockGetNetworkInfo } })
}
const result = await uut.getNetworkInfo(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
'version',
'subversion',
'protocolversion',
'localservices',
'localrelay',
'timeoffset',
'networkactive',
'connections',
'networks',
'relayfee',
'excessutxocharge',
'localaddresses',
'warnings'
])
})
})
})
-60
View File
@@ -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
}
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]
}
}
await rp(options)
// console.log(`result.body: ${JSON.stringify(result.body, null, 2)}`)
} catch (err) {
// console.log(`Error: `, err)
}
}
testDoubleUnconfirmed()
-146
View File
@@ -1,146 +0,0 @@
/*
TESTS FOR THE ENCRYPTION.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 sinon = require('sinon')
// Set default environment variables for unit tests.
if (!process.env.TEST) process.env.TEST = 'unit'
// Only load blockbook library after setting BLOCKBOOK_URL env var.
const EncryptionRoute = require('../../src/routes/v4/encryption')
const encryptionRoute = new EncryptionRoute()
// Mocking data.
const { mockReq, mockRes } = require('./mocks/express-mocks')
const mockData = require('./mocks/encryption-mocks')
// Used for debugging.
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
describe('#Encryption Router', () => {
let req, res
let sandbox
before(() => {
// console.log(`Testing type is: ${process.env.TEST}`)
if (!process.env.NETWORK) process.env.NETWORK = 'testnet'
})
// 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 = {}
sandbox = sinon.createSandbox()
})
afterEach(() => {
sandbox.restore()
})
after(() => {})
describe('#root', () => {
// root route handler.
const root = encryptionRoute.root
it('should respond to GET for base route', async () => {
const result = root(req, res)
assert.equal(result.status, 'encryption', 'Returns static string')
})
})
describe('#getPublicKey', () => {
it('should get public key from blockchain', async () => {
req.params.address =
'bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0'
// Mock the Insight URL for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(encryptionRoute.bchjs.Electrumx, 'transactions')
.resolves(mockData.mockFulcrumTxHistory)
sandbox
.stub(encryptionRoute.bchjs.RawTransactions, 'getRawTransaction')
.resolves([mockData.mockTxDetails2])
}
const result = await encryptionRoute.getPublicKey(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'publicKey')
assert.equal(
result.publicKey,
'044eb40b025df18409f2a5197b010dd62a9e65d9a74e415e5b10367721a9c4baa7ebfee22d14b8ece1c9bd70c0d9e5e8b00b61b81b88a1b5ce6f24eac6b8a34b2c'
)
})
it('should return false for address with no tx history', async () => {
req.params.address =
'bitcoincash:qqwfpk04ecf69wuprj9yjys9rla5mk7rj5j8uthqel'
// Mock the Insight URL for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(encryptionRoute.bchjs.Electrumx, 'transactions')
.resolves(mockData.mockFulcrumNoTxHistory)
}
const result = await encryptionRoute.getPublicKey(req, res)
console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, false)
assert.property(result, 'error')
assert.include(result.error, 'No transaction history')
})
it('should return false for address with no send history', async () => {
req.params.address =
'bitcoincash:qq78nwj5x97yh6wtlfd27dtlwjuh70vkjc59h8tgtg'
// Mock the Insight URL for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(encryptionRoute.bchjs.Electrumx, 'transactions')
.resolves(mockData.mockFulcrumNoSendBalance)
sandbox
.stub(encryptionRoute.bchjs.RawTransactions, 'getRawTransaction')
.resolves([mockData.mockNoSendTx])
}
const result = await encryptionRoute.getPublicKey(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, false)
assert.property(result, 'publicKey')
assert.include(result.publicKey, 'not found')
})
})
})
-29
View File
@@ -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
}
-7
View File
@@ -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.
-114
View File
@@ -1,114 +0,0 @@
/*
These integration tests need to be run against a live SLPDB. They query
against a live SLPDB and test the results against known token stats.
*/
'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 }
// Exit if SLPDB URL is not defined.
if (!process.env.SLPDB_URL) {
throw new Error(
'SLPDB_URL and SLPDB_PASS must be defined in order to run these tests.'
)
}
const SLP = require('../../../src/routes/v4/slp')
const slp = new SLP()
const { mockReq, mockRes } = require('../mocks/express-mocks')
describe('#nft', () => {
let req, res
beforeEach(() => {
// Mock the req and res objects used by Express routes.
req = mockReq
res = mockRes
})
describe('#getNftChildren', () => {
it('should return error on non-existing NFT group token', async () => {
req.params.tokenId =
'68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0b'
const result = await slp.getNftChildren(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.include(
result.error,
'NFT group does not exists',
'Error message expected'
)
})
it('should return error on non-group NFT token', async () => {
req.params.tokenId =
'45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9'
const result = await slp.getNftChildren(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.include(
result.error,
'NFT group does not exists',
'Error message expected'
)
})
it('should get NFT children list', async () => {
req.params.tokenId =
'68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a'
const result = await slp.getNftChildren(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result.nftChildren)
assert.equal(result.nftChildren.length, 2)
assert.equal(
result.nftChildren[0],
'45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9'
)
assert.equal(
result.nftChildren[1],
'928ce61fe1006b1325a0ba0dce700bf83986a6f0691ba26e121c9ac035d12a55'
)
})
})
describe('#getNftGroup', () => {
it('should return error on non-existing NFT child token', async () => {
req.params.tokenId =
'45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a8'
const result = await slp.getNftGroup(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.include(
result.error,
'NFT child does not exists',
'Error message expected'
)
})
it('should get NFT group token info', async () => {
req.params.tokenId =
'45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9'
// req.params.tokenId = '928ce61fe1006b1325a0ba0dce700bf83986a6f0691ba26e121c9ac035d12a55'
const result = await slp.getNftGroup(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.property(result, 'nftGroup')
assert.property(result.nftGroup, 'id')
assert.property(result.nftGroup, 'versionType')
assert.property(result.nftGroup, 'symbol')
assert.equal(
result.nftGroup.id,
'68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a'
)
assert.equal(result.nftGroup.versionType, 129)
assert.equal(result.nftGroup.symbol, 'PSF.TEST.GROUP')
})
})
})
-53
View File
@@ -1,53 +0,0 @@
/*
Integration tests for the price library.
*/
'use strict'
const assert = require('chai').assert
// const axios = require('axios')
// Used for debugging.
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const Price = require('../../../src/routes/v4/price')
const price = new Price()
const { mockReq, mockRes } = require('../mocks/express-mocks')
describe('#price', () => {
let req, res
beforeEach(() => {
// Mock the req and res objects used by Express routes.
req = mockReq
res = mockRes
})
describe('#getUSD', () => {
it('should get the USD price', async () => {
const result = await price.getUSD(req, res)
console.log(`result: ${util.inspect(result)}`)
assert.isNumber(result.usd)
})
})
describe('#getBCHAUSD', () => {
it('should get the USD price of BCHA', async () => {
const result = await price.getBCHAUSD(req, res)
console.log(`result: ${util.inspect(result)}`)
assert.isNumber(result.usd)
})
})
describe('#getBCHUSD', () => {
it('should get the USD price of BCH', async () => {
const result = await price.getBCHUSD(req, res)
console.log(`result: ${util.inspect(result)}`)
assert.isNumber(result.usd)
})
})
})
-164
View File
@@ -1,164 +0,0 @@
/*
These tests have been deprecated. To test bch-api rate limits, run the e2e
tests in the bch-js repository.
*/
'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 = `http://192.168.0.36:12400/v4/`
const SERVER = 'http://localhost:3000/v4/'
// const SERVER = 'https://api.fullstack.cash/v4/'
//
// const TEST_JWT =
// 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMDYyODk1MSwiZXhwIjoxNjAzMjIwOTUxfQ.JPXDJQsxJFtCGZjHOd-hRfJuY41Ef_FQ4ET06CtYdNk'
describe('#JWT rate limits', () => {
it('should get control/getNetworkInfo() with no auth', async () => {
const options = {
method: 'GET',
url: `${SERVER}control/getNetworkInfo`
}
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 20 request per minute', async () => {
try {
const options = {
method: 'GET',
url: `${SERVER}control/getNetworkInfo`
}
const promises = []
for (let i = 0; i < 30; i++) {
const promise = axios(options)
promises.push(promise)
}
await Promise.all(promises)
assert.fail('Unexpected result!')
} catch (err) {
console.log('err: ', err)
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/getNetworkInfo`,
// headers: { Authorization: readyCredential }
// }
//
// const promises = []
// for (let i = 0; i < 30; 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?'
// )
// }
// })
// it('should trigger rate-limit handler if rate limits exceeds pro-tier limit', 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}`
//
// // Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
// const options = {
// method: 'GET',
// url: `${SERVER}control/getNetworkInfo`,
// headers: { Authorization: readyCredential }
// }
//
// const promises = []
// for (let i = 0; i < 80; 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 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)
})
-193
View File
@@ -1,193 +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.
- Replace request-promise with axios.
*/
'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)
})
})
})
*/
-461
View File
@@ -1,461 +0,0 @@
/*
These integration tests need to be run against a live SLPDB. They query
against a live SLPDB and test the results against known token stats.
*/
'use strict'
const assert = require('chai').assert
// const axios = require('axios')
// Used for debugging.
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
// Exit if SLPDB URL is not defined.
if (!process.env.SLPDB_URL) {
throw new Error(
'SLPDB_URL and SLPDB_PASS must be defined in order to run these tests.'
)
}
const SLP = require('../../../src/routes/v4/slp')
const slp = new SLP()
const BCHJS = require('@psf/bch-js')
const bchjs = new BCHJS()
const { mockReq, mockRes } = require('../mocks/express-mocks')
describe('#slp', () => {
let req, res
beforeEach(() => {
// Mock the req and res objects used by Express routes.
req = mockReq
res = mockRes
})
describe('#tokenStats', () => {
it('should get token stats for token with no mint baton', async () => {
req.params.tokenId =
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
// 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
const result = await slp.tokenStats(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Assert that expected properties exist.
assert.property(result, 'decimals')
assert.property(result, 'timestamp')
assert.property(result, 'versionType')
assert.property(result, 'documentUri')
assert.property(result, 'symbol')
assert.property(result, 'name')
assert.property(result, 'containsBaton')
assert.property(result, 'id')
assert.property(result, 'documentHash')
assert.property(result, 'initialTokenQty')
assert.property(result, 'blockCreated')
assert.property(result, 'blockLastActiveSend')
assert.property(result, 'blockLastActiveMint')
assert.property(result, 'txnsSinceGenesis')
assert.property(result, 'validAddresses')
assert.property(result, 'mintingBatonStatus')
assert.property(result, 'timestampUnix')
assert.property(result, 'totalMinted')
assert.property(result, 'totalBurned')
assert.property(result, 'circulatingSupply')
// baton was never created.
assert.equal(result.containsBaton, false)
})
it('should get token stats for token with a mint baton', async () => {
req.params.tokenId =
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
const result = await slp.tokenStats(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Assert that expected properties exist.
assert.property(result, 'decimals')
assert.property(result, 'timestamp')
assert.property(result, 'versionType')
assert.property(result, 'documentUri')
assert.property(result, 'symbol')
assert.property(result, 'name')
assert.property(result, 'containsBaton')
assert.property(result, 'id')
assert.property(result, 'documentHash')
assert.property(result, 'initialTokenQty')
assert.property(result, 'blockCreated')
assert.property(result, 'blockLastActiveSend')
assert.property(result, 'blockLastActiveMint')
assert.property(result, 'txnsSinceGenesis')
assert.property(result, 'validAddresses')
assert.property(result, 'mintingBatonStatus')
assert.property(result, 'timestampUnix')
assert.property(result, 'totalMinted')
assert.property(result, 'totalBurned')
assert.property(result, 'circulatingSupply')
// baton was created.
assert.equal(result.containsBaton, true)
})
})
describe('#generateSendOpReturn', () => {
it('should return OP_RETURN script', async () => {
req.body.tokenUtxos = [
{
tokenId:
'38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
decimals: 8,
tokenQty: 2
}
]
req.body.sendQty = 1.5
const result = await slp.generateSendOpReturn(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['script', 'outputs'])
assert.isNumber(result.outputs)
})
})
describe('#hydrateUtxos', () => {
it('should return utxo details', async () => {
const utxos = [
{
utxos: [
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
confirmations: 13,
satoshis: 6816
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
confirmations: 13,
satoshis: 546
}
]
}
]
req.body.utxos = utxos
const result = await slp.hydrateUtxos(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Test the general structure of the output.
assert.isArray(result.slpUtxos)
assert.equal(result.slpUtxos.length, 1)
assert.equal(result.slpUtxos[0].utxos.length, 2)
// Test the non-slp UTXO.
assert.property(result.slpUtxos[0].utxos[0], 'txid')
assert.property(result.slpUtxos[0].utxos[0], 'vout')
assert.property(result.slpUtxos[0].utxos[0], 'value')
assert.property(result.slpUtxos[0].utxos[0], 'height')
assert.property(result.slpUtxos[0].utxos[0], 'confirmations')
assert.property(result.slpUtxos[0].utxos[0], 'satoshis')
assert.property(result.slpUtxos[0].utxos[0], 'isValid')
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
// Test the slp UTXO.
assert.property(result.slpUtxos[0].utxos[1], 'txid')
assert.property(result.slpUtxos[0].utxos[1], 'vout')
assert.property(result.slpUtxos[0].utxos[1], 'value')
assert.property(result.slpUtxos[0].utxos[1], 'height')
assert.property(result.slpUtxos[0].utxos[1], 'confirmations')
assert.property(result.slpUtxos[0].utxos[1], 'satoshis')
assert.property(result.slpUtxos[0].utxos[1], 'isValid')
assert.equal(result.slpUtxos[0].utxos[1].isValid, true)
assert.property(result.slpUtxos[0].utxos[1], 'transactionType')
assert.property(result.slpUtxos[0].utxos[1], 'tokenId')
assert.property(result.slpUtxos[0].utxos[1], 'tokenTicker')
assert.property(result.slpUtxos[0].utxos[1], 'tokenName')
assert.property(result.slpUtxos[0].utxos[1], 'tokenDocumentUrl')
assert.property(result.slpUtxos[0].utxos[1], 'tokenDocumentHash')
assert.property(result.slpUtxos[0].utxos[1], 'decimals')
assert.property(result.slpUtxos[0].utxos[1], 'tokenType')
assert.property(result.slpUtxos[0].utxos[1], 'tokenQty')
})
it('should process data directly from Electrumx', async () => {
const addrs = [
'bitcoincash:qq6mvsm7l92d77zpymmltvaw09p5uzghyuyx7spygg',
'bitcoincash:qpjdrs8qruzh8xvusdfmutjx62awcepnhyperm3g89',
'bitcoincash:qzygn28zpgeemnptkn26xzyuzzfu9l8f9vfvq7kptk'
]
const utxos = await bchjs.Electrumx.utxo(addrs)
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
req.body.utxos = utxos.utxos
const result = await slp.hydrateUtxos(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Test the general structure of the output.
assert.isArray(result.slpUtxos)
assert.equal(result.slpUtxos.length, 3)
assert.equal(result.slpUtxos[0].utxos.length, 1)
assert.equal(result.slpUtxos[1].utxos.length, 1)
assert.equal(result.slpUtxos[2].utxos.length, 2)
})
})
describe('#hydrateUtxosWL', () => {
it('should return utxo details', async () => {
const utxos = [
{
utxos: [
{
tx_hash:
'89b3f0c84efe8b01b24e2d7ac08636de5781f31dbb84478e3de868ca0a7ed93a',
tx_pos: 1,
value: 546
}
]
}
]
req.body.utxos = utxos
const result = await slp.hydrateUtxosWL(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Test the general structure of the output.
assert.isArray(result.slpUtxos)
assert.equal(result.slpUtxos.length, 1)
assert.equal(result.slpUtxos[0].utxos.length, 1)
// Test the non-slp UTXO.
assert.property(result.slpUtxos[0].utxos[0], 'tx_hash')
assert.property(result.slpUtxos[0].utxos[0], 'tx_pos')
assert.property(result.slpUtxos[0].utxos[0], 'value')
assert.property(result.slpUtxos[0].utxos[0], 'isValid')
assert.equal(result.slpUtxos[0].utxos[0].isValid, true)
})
})
describe('#validate2Single', () => {
it('should invalidate a known invalid TXID', async () => {
const txid =
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
req.params.txid = txid
const result = await slp.validate2Single(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.txid, txid)
assert.equal(result.isValid, false)
})
it('should validate a known valid TXID', async () => {
const txid =
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
req.params.txid = txid
const result = await slp.validate2Single(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.txid, txid)
assert.equal(result.isValid, true)
})
// CT 10-11-2020: This test is valid, but because of the cacheing built
// into slp-validate, it will not consistently pass or fail. To manually
// Run this test, re-start slp-api or find a token txid with a long DAG.
// it('should cancel if validation takes too long', async () => {
// const txid =
// 'eacb1085dfa296fef6d4ae2c0f4529a1bef096dd2325bdcc6dcb5241b3bdb579'
//
// req.params.txid = txid
// const result = await slp.validate2Single(req, res)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
// assert.include(
// result.error,
// 'Could not communicate with full node',
// 'Error message expected'
// )
// })
})
describe('#validateBulk', () => {
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
const txids = [
// Malformed SLP tx
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
// Normal TX (non-SLP)
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
// Valid PSF SLP tx
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
// Valid SLP token not in whitelist
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
// Token send on BCHN network.
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
// Token send on ABC network.
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
// Known invalid SLP token send of PSF tokens.
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74'
]
req.body.txids = txids
const result = await slp.validateBulk(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// BCHN expected results
if (process.env.ISBCHN) {
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, true)
// Note: This should change from null to true once SLPDB finishes indexing.
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, null)
assert.equal(result[5].txid, txids[5])
assert.equal(result[5].valid, null)
assert.equal(result[6].txid, txids[6])
assert.equal(result[6].valid, false)
assert.include(
result[6].invalidReason,
'Token outputs are greater than valid token inputs'
)
} else {
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, true)
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, null)
assert.equal(result[5].txid, txids[5])
assert.equal(result[5].valid, true)
assert.equal(result[6].txid, txids[6])
assert.equal(result[6].valid, false)
assert.include(
result[6].invalidReason,
'Token outputs are greater than valid token inputs'
)
}
})
})
describe('#validate3Bulk', () => {
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
const txids = [
// Malformed SLP tx
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
// Normal TX (non-SLP)
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
// Valid PSF SLP tx
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
// Valid SLP token not in whitelist
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
// Token send on BCHN network.
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
// Token send on ABC network.
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
// Known invalid SLP token send of PSF tokens.
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74'
]
req.body.txids = txids
const result = await slp.validate3Bulk(req, res)
console.log(`result: ${JSON.stringify(result, null, 2)}`)
// BCHN expected results
if (process.env.ISBCHN) {
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, null)
// Note: This should change from null to true once SLPDB finishes indexing.
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, null)
assert.equal(result[5].txid, txids[5])
assert.equal(result[5].valid, null)
assert.equal(result[6].txid, txids[6])
assert.equal(result[6].valid, false)
assert.include(
result[6].invalidReason,
'Token outputs are greater than valid token inputs'
)
} else {
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, true)
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, null)
assert.equal(result[5].txid, txids[5])
assert.equal(result[5].valid, true)
assert.equal(result[6].txid, txids[6])
assert.equal(result[6].valid, false)
assert.include(
result[6].invalidReason,
'Token outputs are greater than valid token inputs'
)
}
})
})
describe('#getStatus', () => {
it('should get the SLPDB status', async () => {
const result = await slp.getStatus(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'bchBlockHeight')
})
})
})
-31
View File
@@ -1,31 +0,0 @@
/*
These integration tests need to be run against a live SLPDB. They query
against a live SLPDB and test the results against known token stats.
*/
'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 }
// Exit if SLPDB URL is not defined.
if (!process.env.SLPDB_URL) {
throw new Error('SLPDB_URL and SLPDB_PASS must be defined in order to run these tests.')
}
const SLPDB = require('../../../src/routes/v4/services/slpdb')
const slpdb = new SLPDB()
describe('#slpdb', () => {
describe('#getTotalCirculating', () => {
it('should get circulating supply', async () => {
const result = await slpdb.getTotalCirculating('b10677aef051b73e6b170c1c0824da33a3e0680ab5a01cd8d76aa77840fccfb4')
console.log('result: ', result)
})
})
})
-224
View File
@@ -1,224 +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/v4/full-node/mining')
const uut = new MiningRoute()
// const nock = require('nock') // HTTP mocking
const sinon = require('sinon')
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
let sandbox
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 = {}
sandbox = sinon.createSandbox()
})
afterEach(() => {
// Restore Sandbox
sandbox.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.
it('should respond to GET for base route', async () => {
const result = uut.root(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(result.status, 'mining', 'Returns static string')
})
})
describe('#getMiningInfo', async () => {
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/'
await uut.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('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
const result = await uut.getMiningInfo(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('returns proper error when downstream service is down', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNREFUSED' })
const result = await uut.getMiningInfo(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.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') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockMiningInfo } })
}
const result = await uut.getMiningInfo(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.property(result, 'blocks')
assert.property(result, 'difficulty')
assert.property(result, 'networkhashps')
assert.property(result, 'pooledtx')
assert.property(result, 'chain')
assert.property(result, 'warnings')
})
})
describe('#getNetworkHashPS', async () => {
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/'
await uut.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('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
const result = await uut.getNetworkHashPS(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('returns proper error when downstream service is down', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNREFUSED' })
const result = await uut.getNetworkHashPS(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.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') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: 517604755.6648782 } })
}
const result = await uut.getNetworkHashPS(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isNumber(result)
})
})
})
-160
View File
@@ -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
}
-35
View File
@@ -1,35 +0,0 @@
/*
This library contains mocking data for running unit tests on the bitcore route.
*/
'use strict'
const mockBalance = {
confirmed: 10000000,
unconfirmed: 0,
balance: 10000000
}
const mockUtxos = [
{
_id: '5cf2c31a33bd46a95ec7e730',
chain: 'BCH',
network: 'testnet',
coinbase: false,
mintIndex: 1,
spentTxid: '',
mintTxid:
'5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392',
mintHeight: 1265275,
spentHeight: -2,
address: 'qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4',
script: '76a9140e5b4ad9008bb9a027b7e2d0ef958914e12db20788ac',
value: 10000000,
confirmations: -1
}
]
module.exports = {
mockBalance,
mockUtxos
}
-42
View File
@@ -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
}
-75
View File
@@ -1,75 +0,0 @@
/*
This library contains mocking data for running unit tests on the blockbook route.
*/
'use strict'
const mockBalance = {
page: 1,
totalPages: 1,
itemsOnPage: 1000,
address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
balance: '10000000',
totalReceived: '10000000',
totalSent: '0',
unconfirmedBalance: '0',
unconfirmedTxs: 0,
txs: 1,
txids: ['5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392']
}
const mockUtxos = [
{
txid: '5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392',
vout: 1,
value: '10000000',
height: 1265275,
confirmations: 42704
}
]
const mockTx = {
txid: '5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392',
version: 2,
vin: [
{
txid: '85ddb8215fc3701a493cf1c450644c5ef32c55aaa2f48ae2d008944394f3e4d3',
sequence: 4294967295,
n: 0,
addresses: ['bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35'],
value: '16983000648',
hex:
'47304402202378e55f4d02bb932498deef22dfc1f7a4984858c3b55017e225dd567172252e0220373d27710b5d42a72ac9725959f1605a912fee0ae86a7ad36e7d6d796f14ca29412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792'
}
],
vout: [
{
value: '16973000422',
n: 0,
spent: true,
hex: '76a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac',
addresses: ['bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35']
},
{
value: '10000000',
n: 1,
hex: '76a9140e5b4ad9008bb9a027b7e2d0ef958914e12db20788ac',
addresses: ['bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4']
}
],
blockHash: '00000000005242edac4635ac2375a454e801cc1be8b131b622328089731e5e30',
blockHeight: 1265275,
confirmations: 65402,
blockTime: 1540912733,
value: '16983000422',
valueIn: '16983000648',
fees: '226',
hex:
'0200000001d3e4f394439408d0e28af4a2aa552cf35e4c6450c4f13c491a70c35f21b8dd85000000006a47304402202378e55f4d02bb932498deef22dfc1f7a4984858c3b55017e225dd567172252e0220373d27710b5d42a72ac9725959f1605a912fee0ae86a7ad36e7d6d796f14ca29412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02e66eabf3030000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a9140e5b4ad9008bb9a027b7e2d0ef958914e12db20788ac00000000'
}
module.exports = {
mockBalance,
mockUtxos,
mockTx
}
-380
View File
@@ -1,380 +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 =
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c'
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',
nTx: 'some value'
}
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'
const mockAncestors = [
'070504de968fba8a23a1362fd7fc0546a420663f2bcc18099d894a41ecf9cce5',
'20af6b7fcd21a3f38bb65d32fe2d66fb1ae554ed9c00eaf1b17d7e81362381a9',
'227e08663a812cf44d91106b09fc8493fe1a2b7c146f30ca09ebd86c9b84b2a5',
'228833be79d4a833165ea199be160efcaeb9325e71e9455f424b27abc9688ba8',
'2de27df02001e7243435cef6d41ea2312b94a5964912eb21466b936852c0b822',
'2ef76ae690d6f6c9559e20358a75a0ce02250b9b8e80e0aa6f782576239f292a',
'3e314678f52d52694726e6da88b94c9f0ea086d2f9af297b01d014b62247839f',
'4773f840d5255f16c0e5effce48316d8b8824a1d3ddd5da275c5fd99e7b3ee42',
'4804b97112da07e2c187516a915dd4cbd4a3814f3c900b8d08eb1d508ab0ac47',
'4ca69f31081a256cb4711315336fe4358d8f04b67792ca5ee17b5f4089a2446a',
'6ac17dce10ae3a3d1d8e6f42546ad9a4bb981e62cba8d48bab03e01b9ea38ae3',
'6ce71182ef341c481a90d8b081a99d9788bdd91a917f9a6594fdfad2c2024a14',
'8413343ac973fb0968ae1809faa8f0ddf18252975481daa683e88b04afa66ccd',
'9430300f3d7ecdabe39671b6fd0e9c36f763f01a202e619c070554ddc5e8713e',
'94f82b5a2cd1647d8168807ccfdebe41931ea1ab789a050d615f08000a63b624',
'9848db6a7d2835002ca7e1097a685d75eb629f44df94007674635b45d0e97199',
'98d809993353df6c4d55fda5e7b0ed2e383601cef1180a9aa9c87e67e8f4dd94',
'9f5513a35ae8fad3dd061865a97d8127c914e3464527641c089993c06d092535',
'a7201ac90abd2aa42112faa809181c45047b6988a2f649a70a1d5bfb95f46884',
'a9f1284710c655357412a062b01efaeb174820613784ccbfe44b33b86a8bdbc4',
'b814f44c9c8ee24a218b9f295a8c1831106b70c15ffe8aeb7534e10d99935fd0',
'e130ccdcc94dc5eaa4ae37fa50e3ee96283b0e157616bc6e28454b64bae34f48',
'e68dad4a7292105cfa84fcaef7f99e5d4f2ece9613ca625d4d2ebf61efa84118',
'fe94caf5da672be3772d2304a6272eb8bc3d3f5cb4a886f39b7981e1485cf74b'
]
const mockBlockInfo = {
verbosity0: '20000000',
verbosity1: {
hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09',
confirmations: 1,
size: 3725,
strippedsize: 3725,
weight: 3725,
height: 6725,
version: 1,
versionHex: '00000000',
merkleroot: 'xxxx',
tx: [
'2afb8264508e2bf3e5288ccad01ed2ab766745b6b9747666b519d59212012c01',
'18f40b1ae56bba3fa1934b737fbe46ed8d5ca40fa9aed95073eeb5a119530cd3',
'349720d878547752607a69eb19e330592fee271fb5376cdfd811bee423558ed8',
'35571c80e7d0e9247b467454ef147d1d5833c775bc2d4164b1bebd4c1f69164f',
'480937e8efacdafeeb97d401ff0dd9ea8e8ddb27244cefa67a03621315bdb0e6',
'523327469d0b90c0de9a905c2fe6e227278fc5b55b9d9911ca151e1c26647065',
'61de4af971d94dbc741762f21dcef08b74b62863a56a1cb3496becdd8d47a858',
'69f70a288403b5bba23030ccd05d2e5cb00394620fdae3b050cff9432cc590ce',
'94472a90fbdba2eb2cba68308415181faedf3585c66b89efcbdb927a0c10ba23',
'bc6f781f9e2f2df460f89995c5e1c7224e48ccbe1aa2a575961f3f5330259864',
'f2d945a79bec5454a9ab4d570a150d81124daa308f1c81106a977d6413476944'
],
time: 111,
mediantime: 111,
nonce: 111,
bits: '1d00ffff',
difficulty: 99.999,
chainwork: 'xxxx',
nTx: 1,
previousblockhash:
'00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09',
nextblockhash:
'00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09'
},
verbosity2: {
hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09',
confirmations: 1,
size: 3725,
strippedsize: 3725,
weight: 3725,
height: 6725,
version: 1,
versionHex: '00000000',
merkleroot: 'xxxx',
tx: [
{
hex:
'01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000',
txid:
'0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098',
hash:
'0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098',
size: 134,
version: 1,
locktime: 0,
vin: [],
vout: [],
blockhash:
'00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048',
confirmations: 581882,
time: 1231469665,
blocktime: 1231469665
}
],
time: 111,
mediantime: 111,
nonce: 111,
bits: '1d00ffff',
difficulty: 99.999,
chainwork: 'xxxx',
nTx: 1,
previousblockhash:
'00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09',
nextblockhash:
'00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09'
}
}
module.exports = {
mockBlockHash,
mockBlockchainInfo,
mockChainTips,
mockMempoolInfo,
mockRawMempool,
mockBlockHeaderConcise,
mockBlockHeader,
mockTxOut,
mockTxOutProof,
mockAncestors,
mockBlockInfo
}
-45
View File
@@ -1,45 +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)'
}
const mockGetNetworkInfo = {
version: 190700,
subversion: '/Bitcoin ABC:0.19.7(EB32.0)/',
protocolversion: 70015,
localservices: '0000000000000425',
localrelay: true,
timeoffset: 0,
networkactive: true,
connections: 23,
networks: [{}, {}, {}],
relayfee: 0.00001,
excessutxocharge: 0,
localaddresses: [],
warnings:
"Warning: Unknown block versions being mined! It's possible unknown rules are in effect"
}
module.exports = {
mockGetInfo,
mockGetNetworkInfo
}
-122
View File
@@ -1,122 +0,0 @@
/*
Mocking data for electrumx unit tests
*/
'use strict'
const utxos = [
{
height: 604392,
tx_hash: '7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41',
tx_pos: 0,
value: 1000
},
{
height: 630834,
tx_hash: '4fe60a51e0d8f5134bfd8e5f872d6e502d7f01b28a6afebb27f4438a4f638d53',
tx_pos: 0,
value: 6000
}
]
const balance = {
confirmed: 7000,
unconfirmed: 0
}
const txHistory = [
{
height: 601861,
tx_hash: '6181c669614fa18039a19b23eb06806bfece1f7514ab457c3bb82a40fe171a6d'
}
]
const mempool = [
{
tx_hash: '45381031132c57b2ff1cbe8d8d3920cf9ed25efd9a0beb764bdb2f24c7d1c7e3',
height: 0,
fee: 24310
}
]
const txDetails = {
blockhash: '0000000000000000002aaf94953da3b487317508ebd1003a1d75d6d6ec2e75cc',
blocktime: 1578327094,
confirmations: 31861,
hash: '4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
hex: '020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000',
locktime: 0,
size: 392,
time: 1578327094,
txid: '4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
version: 2,
vin: [
{
scriptSig: {
asm: 'dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e[ALL|FORKID] 020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309',
hex: '41dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309'
},
sequence: 4294967295,
txid: '6796672c8f0342770e3d4ac2a3b0e4494daeb7af7997f3518a0c8402f43ed165',
vout: 1
},
{
scriptSig: {
asm: '347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f77[ALL|FORKID] 028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954',
hex: '41347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954'
},
sequence: 4294967295,
txid: '6796672c8f0342770e3d4ac2a3b0e4494daeb7af7997f3518a0c8402f43ed165',
vout: 0
}
],
vout: [
{
n: 0,
scriptPubKey: {
addresses: ['bitcoincash: pqvfecpwxvj53ayqfwkxtjaxsgpvnklcyg8xewk9hl'],
asm: 'OP_HASH160 189ce02e332548f4804bac65cba68202c9dbf822 OP_EQUAL',
hex: 'a914189ce02e332548f4804bac65cba68202c9dbf82287',
reqSigs: 1,
type: 'scripthash'
},
value: 0.0562057
},
{
n: 1,
scriptPubKey: {
addresses: ['bitcoincash: qq59hv6s3qdjrtyfwfxxldkuj9xsjmx48vrz882knz'],
asm: 'OP_DUP OP_HASH160 285bb350881b21ac89724c6fb6dc914d096cd53b OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914285bb350881b21ac89724c6fb6dc914d096cd53b88ac',
reqSigs: 1,
type: 'pubkeyhash'
},
value: 0.00589197
},
{
n: 2,
scriptPubKey: {
addresses: ['bitcoincash: qpzlruwy4xu5rxjs3z37nsj29y7h59gwvsu4ddp0u4'],
asm: 'OP_DUP OP_HASH160 45f1f1c4a9b9419a5088a3e9c24a293d7a150e64 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac',
reqSigs: 1,
type: 'pubkeyhash'
},
value: 0.03272697
}
]
}
const blockHeaders = [
'010000008b52bbd72c2f49569059f559c1b1794de5192e4f7d6d2b03c7482bad0000000083e4f8a9d502ed0c419075c1abb5d56f878a2e9079e5612bfb76a2dc37d9c42741dd6849ffff001d2b909dd6',
'01000000f528fac1bcb685d0cd6c792320af0300a5ce15d687c7149548904e31000000004e8985a786d864f21e9cbb7cbdf4bc9265fe681b7a0893ac55a8e919ce035c2f85de6849ffff001d385ccb7c'
]
module.exports = {
utxos,
balance,
txHistory,
mempool,
txDetails,
blockHeaders
}
-195
View File
@@ -1,195 +0,0 @@
/*
Mock data for the encryption test library
*/
const mockNoSendTx = {
txid: 'a3b62cd4f4c56ba52139179db14bffd4ab22a2e077f3c62bd5cf0541bfcaf023',
hash: 'a3b62cd4f4c56ba52139179db14bffd4ab22a2e077f3c62bd5cf0541bfcaf023',
version: 2,
size: 226,
locktime: 0,
vin: [
{
txid: '681cc1d392975a7e78cbd490b8a940d7eb029c554f2cee332e3a7119d77fb189',
vout: 1,
scriptSig: {
asm:
'30450221008a7c86ce3a9f5765573440143a00631bb5afa9a58b24674a7fa794bb11ffffc30220397dd4c672c3e0dbe0c4eb6390b5727c5fdc3a42cf3ae275ac13b44d27bb234f[ALL|FORKID] 02bc9fc26ae2bd9a9a14e9baeda4b4fdd95a00bcbf375732c647488b3ce82a2fd7',
hex:
'4830450221008a7c86ce3a9f5765573440143a00631bb5afa9a58b24674a7fa794bb11ffffc30220397dd4c672c3e0dbe0c4eb6390b5727c5fdc3a42cf3ae275ac13b44d27bb234f412102bc9fc26ae2bd9a9a14e9baeda4b4fdd95a00bcbf375732c647488b3ce82a2fd7'
},
sequence: 4294967295
}
],
vout: [
{
value: 0.000006,
n: 0,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 3c79ba54317c4be9cbfa5aaf357f74b97f3d9696 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a9143c79ba54317c4be9cbfa5aaf357f74b97f3d969688ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qq78nwj5x97yh6wtlfd27dtlwjuh70vkjc59h8tgtg']
}
},
{
value: 0.00003664,
n: 1,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 58502a73888e0a386fc69b44850af4b2a86ac9a6 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a91458502a73888e0a386fc69b44850af4b2a86ac9a688ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qpv9q2nn3z8q5wr0c6d5fpg27je2s6kf5cavp4ney0']
}
}
],
hex:
'020000000189b17fd719713a2e33ee2c4f559c02ebd740a9b890d4cb787e5a9792d3c11c68010000006b4830450221008a7c86ce3a9f5765573440143a00631bb5afa9a58b24674a7fa794bb11ffffc30220397dd4c672c3e0dbe0c4eb6390b5727c5fdc3a42cf3ae275ac13b44d27bb234f412102bc9fc26ae2bd9a9a14e9baeda4b4fdd95a00bcbf375732c647488b3ce82a2fd7ffffffff0258020000000000001976a9143c79ba54317c4be9cbfa5aaf357f74b97f3d969688ac500e0000000000001976a91458502a73888e0a386fc69b44850af4b2a86ac9a688ac00000000'
}
const mockFulcrumTxHistory = {
success: true,
transactions: [
{
transactions: [
{
height: 511463,
tx_hash:
'eff00a9538487ff44243c75fb13de19b5783454c42c81b9aff9afbfd09cbaec3'
},
{
height: 511464,
tx_hash:
'7e9aa7a74de2b30200a2d6fc748ff35a0c753221444194f720bb7f61ef1d9153'
},
{
height: 513373,
tx_hash:
'6960255abe64893073921e96bf3c053c82686e0fc22a565494fbe2a31e766975'
},
{
height: 513373,
tx_hash:
'9ea667bcfc9cd337bd6c5583d8094c1b1942bd2015d95b54189deac5070eeff0'
},
{
height: 560481,
tx_hash:
'ecc1b51bac767880382bf3190ff17abf78d0936843a022a943d871116ed50368'
},
{
height: 560615,
tx_hash:
'b3792d28377b975560e1b6f09e48aeff8438d4c6969ca578bd406393bd50bd7d'
},
{
height: 561568,
tx_hash:
'8bc2134c7e48e56e1769b3d7c4c1e3a0acc68e1e58160eee6fa67f3208c07262'
},
{
height: 561569,
tx_hash:
'ceb0cab0e37b59caf3ca29e1a698d19ff47f2827dd09cb2f3b91b9100b1dad1c'
},
{
height: 561572,
tx_hash:
'0f9b49cafeb9ae1d741cdb12137c92816aa8470944c270a78ba2e610bd59190d'
},
{
height: 561582,
tx_hash:
'e4a0ac48ff3f42fc342717a2a3d34248e5e85bae79d59bd20e1b60e61b1c500f'
},
{
height: 562106,
tx_hash:
'1afcc63b244182647909539ebe3f4a44b8ea4120a95edb8d9eebe5347b9491bb'
},
{
height: 562106,
tx_hash:
'c42f8f16d3baa2ee343ea89ef110dfe094992379d08edd30887b8ca7ee671c9a'
}
]
}
]
}
const mockTxDetails2 = {
txid: '7e9aa7a74de2b30200a2d6fc748ff35a0c753221444194f720bb7f61ef1d9153',
hash: '7e9aa7a74de2b30200a2d6fc748ff35a0c753221444194f720bb7f61ef1d9153',
version: 1,
size: 221,
locktime: 0,
vin: [
{
txid: 'eff00a9538487ff44243c75fb13de19b5783454c42c81b9aff9afbfd09cbaec3',
vout: 0,
scriptSig: {
asm:
'30440220150e7c9b646fe1f7f576456c9808c89a710e8fbb753e9f5ca6ed2d39a0b69ba602202212968163d8dfe35eec5975fce38440082029cb2691a3e0ad1714f9c412c47a[ALL|FORKID] 044eb40b025df18409f2a5197b010dd62a9e65d9a74e415e5b10367721a9c4baa7ebfee22d14b8ece1c9bd70c0d9e5e8b00b61b81b88a1b5ce6f24eac6b8a34b2c',
hex:
'4730440220150e7c9b646fe1f7f576456c9808c89a710e8fbb753e9f5ca6ed2d39a0b69ba602202212968163d8dfe35eec5975fce38440082029cb2691a3e0ad1714f9c412c47a4141044eb40b025df18409f2a5197b010dd62a9e65d9a74e415e5b10367721a9c4baa7ebfee22d14b8ece1c9bd70c0d9e5e8b00b61b81b88a1b5ce6f24eac6b8a34b2c'
},
sequence: 4294967295
}
],
vout: [
{
value: 0.01266023,
n: 0,
scriptPubKey: {
asm: 'OP_HASH160 91bacd6785e3f8c78d5f29b4020b94c753444130 OP_EQUAL',
hex: 'a91491bacd6785e3f8c78d5f29b4020b94c75344413087',
reqSigs: 1,
type: 'scripthash',
addresses: ['bitcoincash:pzgm4nt8sh3l33udtu5mgqstjnr4x3zpxqrrrndnw5']
}
}
],
hex:
'0100000001c3aecb09fdfb9aff9a1bc8424c4583579be13db15fc74342f47f4838950af0ef000000008a4730440220150e7c9b646fe1f7f576456c9808c89a710e8fbb753e9f5ca6ed2d39a0b69ba602202212968163d8dfe35eec5975fce38440082029cb2691a3e0ad1714f9c412c47a4141044eb40b025df18409f2a5197b010dd62a9e65d9a74e415e5b10367721a9c4baa7ebfee22d14b8ece1c9bd70c0d9e5e8b00b61b81b88a1b5ce6f24eac6b8a34b2cffffffff01675113000000000017a91491bacd6785e3f8c78d5f29b4020b94c7534441308700000000',
blockhash: '000000000000000001aab6818b4ad0379a3f7a13940d9b3d4838b3dea1d0a083',
confirmations: 149222,
time: 1515088493,
blocktime: 1515088493
}
const mockFulcrumNoTxHistory = {
success: true,
transactions: [
{
transactions: [],
address: 'bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh'
}
]
}
const mockFulcrumNoSendBalance = {
success: true,
transactions: [
{
transactions: [
{
height: 633578,
tx_hash:
'a3b62cd4f4c56ba52139179db14bffd4ab22a2e077f3c62bd5cf0541bfcaf023'
}
]
}
]
}
module.exports = {
mockNoSendTx,
mockFulcrumTxHistory,
mockTxDetails2,
mockFulcrumNoTxHistory,
mockFulcrumNoSendBalance
}
-89
View File
@@ -1,89 +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({}),
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({})
}
// Dev-Note on Rate Limits: Since next() is mocked, I can call the Sinon untility
// functions on it, like called(), to see if this stub was called.
const mockNext = sinon.stub().returns()
module.exports = {
mockReq,
mockRes,
mockNext
}
-21
View File
@@ -1,21 +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,
warnings:
"Warning: Unknown block versions being mined! It's possible unknown rules are in effect",
networkhashps: 517410290.9365583,
pooledtx: 5,
chain: 'test'
}
module.exports = {
mockMiningInfo
}
-241
View File
@@ -1,241 +0,0 @@
/*
This library contains mocking data for running unit tests on the address route.
*/
'use strict'
const mockCoinbaseFeed = {
data: {
currency: 'BCH',
rates: {
AED: '918.11634',
AFN: '19208.6584998',
ALGO: '823.28722002635056355',
ALL: '26365.4673517',
AMD: '120379.9761886',
ANG: '448.6632494',
AOA: '162813.68075',
ARS: '19392.84240565',
ATOM: '45.3670932026499700525',
AUD: '354.4385981',
AWG: '449.91',
AZN: '425.539875',
BAL: '18.824215193276753072',
BAM: '415.45514235',
BAND: '40.7768732564399590085',
BAT: '1168.9711697428450012',
BBD: '499.9',
BCH: '1.0',
BDT: '21194.1523216',
BGN: '415.36691',
BHD: '94.2501462',
BIF: '483670.78174295',
BMD: '249.95',
BND: '339.227141',
BOB: '1725.8732563',
BRL: '1401.494645',
BSD: '249.95',
BSV: '1.567361207606150942625',
BTC: '0.021275',
BTN: '18323.91073475',
BWP: '2859.81217315',
BYN: '640.5913561',
BYR: '6405913.561',
BZD: '503.8107177',
CAD: '329.6765515',
CDF: '490377.5463717',
CGLD: '121.6805004503079241715',
CHF: '227.5939721',
CLF: '7.13432285',
CLP: '196860.63474705',
CNH: '1669.50978125',
CNY: '1670.21589',
COMP: '2.429765723728978241',
COP: '961722.29431455',
CRC: '150790.4338804',
CUC: '250.01273745',
CVE: '23620.275',
CZK: '5790.09175',
DAI: '247.842348666936355635',
DASH: '3.338230383973288798',
DJF: '44495.8985401',
DKK: '1580.608815',
DOP: '14597.4179324',
DZD: '32214.830745',
EEK: '3652.69206545',
EGP: '3924.839875',
EOS: '96.8423091824874092665',
ERN: '3749.25274945',
ETB: '9313.6508972',
ETC: '45.04821122825989111',
ETH: '0.658777328255340453815',
EUR: '212.33',
FJD: '534.9054975',
FKP: '193.01413945',
GBP: '193.115',
GEL: '807.3385',
GGP: '193.01413945',
GHS: '1453.70845015',
GIP: '193.01413945',
GMD: '12934.9125',
GNF: '2447970.79115335',
GTQ: '1944.576007',
GYD: '52260.2868518',
HKD: '1937.122498',
HNL: '6129.328889',
HRK: '1610.802775',
HTG: '15746.55080985',
HUF: '77512.6058777',
IDR: '3675351.03275',
ILS: '846.1232415',
IMP: '193.01413945',
INR: '18345.655135',
IQD: '298009.02802165',
ISK: '34745.5495',
JEP: '193.01413945',
JMD: '36409.6696094',
JOD: '177.21455',
JPY: '26360.601825',
KES: '27184.562',
KGS: '20308.0755724',
KHR: '1025880.7533059',
KMF: '105029.03124175',
KNC: '274.68542227594924615',
KRW: '284915.23080495',
KWD: '76.4532063',
KYD: '208.2943328',
KZT: '107014.42658325',
LAK: '2310183.71158185',
LBP: '378370.54450325',
LINK: '22.894634759817007489',
LKR: '46090.95971405',
LRC: '1457.8594342373869446',
LRD: '48852.72175115',
LSL: '4122.3008749',
LTC: '5.2062070401999589123',
LTL: '806.05000775',
LVL: '164.03243695',
LYD: '341.5926678',
MAD: '2298.47346335',
MDL: '4228.5806147',
MGA: '982179.7557538',
MKD: '13087.73767885',
MKR: '0.43764476902003812305',
MMK: '322679.7621378',
MNT: '709349.8756452',
MOP: '1995.2583685',
MRO: '89232.15',
MTL: '170.9003131',
MUR: '9974.21650765',
MVR: '3849.23',
MWK: '188665.67006785',
MXN: '5298.265135',
MYR: '1036.517655',
MZN: '18229.3548997',
NAD: '4134.173',
NGN: '95481.03472305',
NIO: '8698.6554209',
NMR: '8.624556609112112958',
NOK: '2334.203066',
NPR: '29318.1806909',
NZD: '379.2351378',
OMG: '74.464123456422320125',
OMR: '96.23549905',
OXT: '1033.27821413807369045',
PAB: '249.95',
PEN: '896.6071427',
PGK: '874.90073485',
PHP: '12136.85639315',
PKR: '40613.9575836',
PLN: '971.640633',
PYG: '1756126.21474795',
QAR: '910.1304375',
REN: '769.6689761354887733',
REP: '18.2912550311013566725',
REPV2: '18.1582473904586151205',
RON: '1035.54285',
RSD: '24943.76025',
RUB: '19402.093805',
RWF: '244237.3512583',
SAR: '937.65668115',
SBD: '2019.805958',
SCR: '4576.6749819',
SEK: '2207.698372',
SGD: '339.57582125',
SHP: '193.01413945',
SLL: '2490751.74625075',
SOS: '145044.39506805',
SRD: '3537.7923',
SSP: '32558.487',
STD: '5250063.0293496',
SVC: '2187.04525345',
SZL: '4118.75383445',
THB: '7800.314625',
TJS: '2579.48624955',
TMT: '874.825',
TND: '688.2998125',
TOP: '579.953986',
TRY: '1969.70598',
TTD: '1696.3476626',
TWD: '7179.16412995',
TZS: '579879.84308155',
UAH: '7090.3476468',
UGX: '935325.80066935',
UMA: '29.276720351390922145',
UNI: '78.76161966283282792',
USD: '249.95',
USDC: '249.95',
UYU: '10724.30446005',
UZS: '2592145.88136715',
VEF: '62109486.17813795',
VES: '113073216.80555545',
VND: '5792476.0820382',
VUV: '28582.2184128',
WST: '655.5403657',
XAF: '139318.05656485',
XAG: '10.233577875',
XAU: '0.1313462255',
XCD: '675.5023725',
XDR: '177.0940741',
XLM: '2935.3219224332811736',
XOF: '139318.05656485',
XPD: '0.1065011955',
XPF: '25344.75028595',
XPT: '0.290981792',
XRP: '1016.6768354687817832',
XTZ: '114.010080507218287957',
YER: '62574.97275195',
YFI: '0.0181099566723181033515',
ZAR: '4130.57372',
ZEC: '3.88966697790227161905',
ZMK: '1313006.15998725',
ZMW: '5048.6210738',
ZRX: '642.804422350408735165',
ZWL: '80483.9'
}
}
}
const mockCoinexFeed = {
code: 0,
data: {
date: 1605649499848,
ticker: {
vol: '26717.39062407',
low: '10.4000',
open: '11.8000',
high: '19.0029',
last: '18.5000',
buy: '18.0100',
buy_amount: '200.00000000',
sell: '18.5000',
sell_amount: '47.89580474'
}
},
message: 'OK'
}
module.exports = {
mockCoinbaseFeed,
mockCoinexFeed
}
-157
View File
@@ -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
}
File diff suppressed because it is too large Load Diff
-71
View File
@@ -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
-74
View File
@@ -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
}
-125
View File
@@ -1,125 +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
}
// const mockBalance = {
// page: 1,
// totalPages: 1,
// itemsOnPage: 1000,
// address: 'bitcoincash:qzp7gdl52edm24xlpkyqnza9rv43u3mdxyc77j3u6k',
// balance: '2546',
// totalReceived: '2546',
// totalSent: '0',
// unconfirmedBalance: '0',
// unconfirmedTxs: 0,
// txs: 2,
// txids: [
// 'e190d13b88578132608ab912a4d2be3e55aa2792d6042d481ae21d700639de56',
// '44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6'
// ]
// }
const mockBalance = {
confirmed: 2546,
unconfirmed: 0
}
const mockUtxos = [
{
tx_hash: 'e190d13b88578132608ab912a4d2be3e55aa2792d6042d481ae21d700639de56',
tx_pos: 0,
value: 2000,
height: 605873
},
{
tx_hash: '44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6',
tx_pos: 1,
value: 546,
height: 605873
}
]
const mockThreeUtxos = [
{
tx_hash: 'e190d13b88578132608ab912a4d2be3e55aa2792d6042d481ae21d700639de56',
tx_pos: 0,
value: 2000,
height: 605873
},
{
tx_hash: '44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6',
tx_pos: 1,
value: 546,
height: 605873
},
{
tx_hash: '44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6',
tx_pos: 1,
value: 546,
height: 605873
}
]
const mockIsTokenUtxos = [
false,
{
tx_hash: '44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6',
tx_out: 1,
value: 546,
height: 605873,
confirmations: 298,
satoshis: 546,
utxoType: 'token',
transactionType: 'send',
tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
tokenTicker: 'TOK-CH',
tokenName: 'TokyoCash',
tokenDocumentUrl: '',
tokenDocumentHash: '',
decimals: 8,
tokenQty: 2
}
]
const tapUtxo = {
txid: '2e030df12390186baf817fa2760540b886511e04bc520e88f6b4c2124cc2a7d4',
vout: 1,
value: '546',
height: 606564,
confirmations: 3,
satoshis: 546,
utxoType: 'token',
transactionType: 'send',
tokenId: 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d',
tokenTicker: 'TAP',
tokenName: 'Thoughts and Prayers',
tokenDocumentUrl: '',
tokenDocumentHash: '',
decimals: 0,
tokenQty: 1
}
const tokensOnly = [mockIsTokenUtxos[1], tapUtxo]
const multipleTokens = [false, mockIsTokenUtxos[1], tapUtxo]
module.exports = {
mockAddress,
mockBalance,
mockUtxos,
mockThreeUtxos,
mockIsTokenUtxos,
tokensOnly,
multipleTokens
}
-346
View File
@@ -1,346 +0,0 @@
/*
TESTS FOR THE PRICE.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 sinon = require('sinon')
const Price = require('../../src/routes/v4/price')
let uut
// Mocking data.
const { mockReq, mockRes } = require('./mocks/express-mocks')
const mockData = require('./mocks/price-mock')
// Used for debugging.
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
describe('#PriceRouter', () => {
let req, res
let sandbox
before(() => {
// Set default environment variables for unit tests.
if (!process.env.TEST) process.env.TEST = 'unit'
})
// 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 = {}
sandbox = sinon.createSandbox()
uut = new Price()
})
afterEach(() => {
// Restore Sandbox
sandbox.restore()
})
after(() => {})
describe('#root', async () => {
// root route handler.
// const root = controlRoute.testableComponents.root
it('should respond to GET for base route', async () => {
const result = uut.root(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(result.status, 'price', 'Returns static string')
})
})
describe('#getUSD', () => {
// const getNetworkInfo = controlRoute.testableComponents.getNetworkInfo
it('should throw 500 when network issues', async () => {
uut.priceUrl = 'http://fakeurl/api/'
await uut.getUSD(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isAbove(
res.statusCode,
499,
'HTTP status code 500 or greater expected.'
)
// console.log(res)
assert.include(
res.output.error,
'Network error: Could not communicate with full node or other external service'
)
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
const result = await uut.getUSD(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('returns proper error when downstream service is down', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNREFUSED' })
const result = await uut.getUSD(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('should get the USD price of BCH', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: mockData.mockCoinbaseFeed })
}
const result = await uut.getUSD(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isNumber(result.usd)
})
})
describe('#getBCHRate', () => {
it('should throw 500 when network issues', async () => {
uut.priceUrl = 'http://fakeurl/api/'
await uut.getBCHRate(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isAbove(
res.statusCode,
499,
'HTTP status code 500 or greater expected.'
)
// console.log(res)
assert.include(
res.output.error,
'Network error: Could not communicate with full node or other external service'
)
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
const result = await uut.getBCHRate(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('returns proper error when downstream service is down', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNREFUSED' })
const result = await uut.getBCHRate(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('should get several rates for BCH', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: mockData.mockCoinbaseFeed })
}
const result = await uut.getBCHRate(req, res)
// console.log(`result: ${util.inspect(result)}`)
// assert.isNumber(result)
assert.property(result, 'USD')
assert.property(result, 'CAD')
})
})
describe('#errorHandler', () => {
it('should handle unexpected errors', () => {
sandbox.stub(uut.routeUtils, 'decodeError').returns({ msg: false })
const result = uut.errorHandler(new Error('test error'), res)
// console.log('result: ', result)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.property(result, 'error')
})
})
describe('#getBCHAUSD', () => {
// const getNetworkInfo = controlRoute.testableComponents.getNetworkInfo
it('should throw 500 when network issues', async () => {
uut.coinexPriceUrl = 'http://fakeurl/api/'
await uut.getBCHAUSD(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isAbove(
res.statusCode,
499,
'HTTP status code 500 or greater expected.'
)
// console.log(res)
assert.include(
res.output.error,
'Network error: Could not communicate with full node or other external service'
)
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
const result = await uut.getBCHAUSD(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('returns proper error when downstream service is down', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNREFUSED' })
const result = await uut.getBCHAUSD(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('should get the USD price of BCH', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: mockData.mockCoinexFeed })
}
const result = await uut.getBCHAUSD(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isNumber(result.usd)
})
})
describe('#getBCHUSD', () => {
// const getNetworkInfo = controlRoute.testableComponents.getNetworkInfo
it('should throw 500 when network issues', async () => {
uut.bchCoinexPriceUrl = 'http://fakeurl/api/'
await uut.getBCHUSD(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isAbove(
res.statusCode,
499,
'HTTP status code 500 or greater expected.'
)
// console.log(res)
assert.include(
res.output.error,
'Network error: Could not communicate with full node or other external service'
)
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
const result = await uut.getBCHUSD(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('returns proper error when downstream service is down', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNREFUSED' })
const result = await uut.getBCHUSD(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isAbove(res.statusCode, 499, 'HTTP status code 503 expected.')
assert.include(
result.error,
'Could not communicate with full node',
'Error message expected'
)
})
it('should get the USD price of BCH', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: mockData.mockCoinexFeed })
}
const result = await uut.getBCHUSD(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isNumber(result.usd)
})
})
})
-506
View File
@@ -1,506 +0,0 @@
/*
Unit tests for the route-ratelimit2.js middleware.
*/
'use strict'
// Public npm libraries.
const assert = require('chai').assert
const sinon = require('sinon')
const cloneDeep = require('lodash.clonedeep')
const config = require('../../config')
// Mocking data.
const { mockReq, mockRes, mockNext } = require('./mocks/express-mocks')
// Libraries under test
const RateLimits = require('../../src/middleware/route-ratelimit')
let uut = new RateLimits()
let req, res, next
describe('#rate-routelimit', () => {
let sandbox
before(async () => {
if (!process.env.JWT_AUTH_SERVER) {
process.env.JWT_AUTH_SERVER = 'http://fakeurl.com/'
}
// Wipe the Redis DB, which prevents false negatives when running integration
// tests back-to-back.
await uut.wipeRedis()
})
// Setup the mocks before each test.
beforeEach(() => {
// Mock the req and res objects used by Express routes.
req = cloneDeep(mockReq)
res = cloneDeep(mockRes)
next = mockNext
// Explicitly reset the parmas and body.
req.params = {}
req.body = {}
req.query = {}
req.locals = {}
sandbox = sinon.createSandbox()
uut = new RateLimits()
})
afterEach(() => {
sandbox.restore()
})
after(() => {
uut.closeRedis()
})
describe('#checkInternalIp', () => {
it('should return true for a request from localhost', () => {
req.ip = '::ffff:127.0.0.1'
const result = uut.checkInternalIp(req)
assert.equal(result, true)
})
it('should return true for a request from a Docker container', () => {
req.ip = '172.17.0.3'
const result = uut.checkInternalIp(req)
assert.equal(result, true)
})
it('should return false for a random ip address', () => {
req.ip = '123.456.7.8'
const result = uut.checkInternalIp(req)
assert.equal(result, false)
})
it('should return false when an error is encountered', () => {
req.ip = 4
const result = uut.checkInternalIp(req)
assert.equal(result, false)
})
})
describe('#isInWhitelist', () => {
it('should return false when no argument is passed in', () => {
const result = uut.isInWhitelist()
assert.equal(result, false)
})
it('should return false when origin is not in the whitelist', () => {
req.origin = 'blah.com'
req.get = sandbox.stub().returns(req.origin)
const result = uut.isInWhitelist(req)
assert.equal(result, false)
// Used to appease linter. Remove these.
res.blah = 4
next()
})
it('should return true when origin is in the whitelist', () => {
req.origin = 'message.fullstack.cash'
req.get = sandbox.stub().returns(req.origin)
const result = uut.isInWhitelist(req)
assert.equal(result, true)
})
})
describe('#decodeJwtToken', () => {
it('should return the default JWT payload if decoding fails', () => {
const jwt =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYxNTE1NzA4NywiZXhwIjoxNjE3NzQ5MDg3fQ.RLNGuYAa-CcLdhTGD27tDeaxT6-GIdeR8T4JWZZLDZA'
const result = uut.decodeJwtToken(jwt)
// console.log('result: ', result)
assert.property(result, 'id')
// assert.equal(result.id, '123.456.789.10')
assert.property(result, 'email')
// assert.equal(result.email, 'test@bchtest.net')
// assert.property(result, 'pointsToConsume')
// assert.equal(result.pointsToConsume, config.anonRateLimit)
// assert.property(result, 'duration')
// assert.equal(result.duration, 30)
assert.property(result, 'exp')
})
it('should return the default JWT payload if no input is given', () => {
const result = uut.decodeJwtToken()
// console.log('result: ', result)
assert.property(result, 'id')
assert.equal(result.id, '123.456.789.10')
assert.property(result, 'email')
assert.equal(result.email, 'test@bchtest.net')
assert.property(result, 'pointsToConsume')
assert.equal(result.pointsToConsume, config.anonRateLimit)
assert.property(result, 'duration')
assert.equal(result.duration, 30)
assert.property(result, 'exp')
})
it('should correctly decode a JWT token', () => {
// Generate a new JWT token for the test.
const jwtPayload = {
id: '5dade3f5739e6c0ff034b9a1',
pointsToConsume: 10,
email: 'gooduser@test.com',
apiLevel: 40,
rateLimit: 100,
duration: 30
}
const jwtToken = uut.generateJwtToken(jwtPayload)
const result = uut.decodeJwtToken(jwtToken)
// console.log('result: ', result)
assert.property(result, 'id')
assert.equal(result.id, jwtPayload.id)
assert.property(result, 'email')
assert.equal(result.email, jwtPayload.email)
assert.property(result, 'pointsToConsume')
assert.equal(result.pointsToConsume, jwtPayload.pointsToConsume)
assert.property(result, 'duration')
assert.equal(result.duration, jwtPayload.duration)
assert.property(result, 'exp')
})
it('should return the default payload if there is an unhandled error', () => {
// Force an error.
sandbox.stub(uut, 'generateJwtToken').throws(new Error('test error'))
const result = uut.decodeJwtToken()
// console.log('result: ', result)
assert.property(result, 'id')
assert.equal(result.id, '123.456.789.10')
assert.property(result, 'email')
assert.equal(result.email, 'test@bchtest.net')
assert.property(result, 'pointsToConsume')
assert.equal(result.pointsToConsume, config.anonRateLimit)
assert.property(result, 'duration')
assert.equal(result.duration, 30)
assert.property(result, 'exp')
})
})
describe('#trackRateLimits', () => {
it('should apply anonymous rate limits if no JWT token is provided', async () => {
req.ip = '127.0.0.1'
const result = await uut.trackRateLimits(req, res)
// console.log(`result: `, result)
// console.log('res.locals.pointsToConsume: ', res.locals.pointsToConsume)
assert.equal(result, false, 'Rate limits not exceeded')
assert.equal(
res.locals.pointsToConsume,
config.anonRateLimit,
'Anonymous rate limits applied'
)
})
it('should apply 100 RPM rate limits when JWT token is provided', async () => {
// Generate a new JWT token for the test.
const jwtPayload = {
id: '5dade3f5739e6c0ff034b9a1',
pointsToConsume: 10
}
const jwtToken = uut.generateJwtToken(jwtPayload)
const result = await uut.trackRateLimits(req, res, jwtToken)
// console.log(`result: `, result)
// console.log('res.locals.pointsToConsume: ', res.locals.pointsToConsume)
assert.equal(result, false, 'Rate limits not exceeded')
assert.equal(res.locals.pointsToConsume, 10, '100 RPM limits applied')
})
})
describe('#applyRateLimits', () => {
it('should skip rate limits if basic auth token is used', async () => {
req.locals.proLimit = true
// console.log('next.callCount: ', next.callCount)
const startCallCount = next.callCount
await uut.applyRateLimits(req, res, next)
// console.log('next.callCount: ', next.callCount)
const endCallCount = next.callCount
assert.isAbove(
endCallCount,
startCallCount,
'Expecting next() to be called'
)
})
it('should skip rate limits if internal call passes basic auth token', async () => {
req.ip = '127.0.0.1'
req.body.usrObj = {
proLimit: true
}
// console.log('next.callCount: ', next.callCount)
const startCallCount = next.callCount
await uut.applyRateLimits(req, res, next)
// console.log('next.callCount: ', next.callCount)
const endCallCount = next.callCount
assert.isAbove(
endCallCount,
startCallCount,
'Expecting next() to be called'
)
})
it('should apply rate limits to anonymous users', async () => {
req.ip = '123.456.7.8'
// console.log('next.callCount: ', next.callCount)
const startCallCount = next.callCount
await uut.applyRateLimits(req, res, next)
// console.log('next.callCount: ', next.callCount)
const endCallCount = next.callCount
assert.isAbove(
endCallCount,
startCallCount,
'Expecting next() to be called'
)
assert.equal(
res.locals.pointsToConsume,
config.anonRateLimit,
'Anonymous rate limits applied'
)
})
it('should return 429 error when anonymous users exceed rate limit', async () => {
req.ip = '123.456.7.8'
// force req.locals.jwtToken to be empty.
req.locals.jwtToken = undefined
let val
for (let i = 0; i < 25; i++) {
// console.log('req.locals: ', req.locals)
val = await uut.applyRateLimits(req, res, next)
}
// console.log('val: ', val)
assert.property(val, 'error')
assert.include(
val.error,
'Too many requests. Your limits are currently 20 requests per minute.'
)
assert.equal(res.locals.rateLimitTriggered, true, 'Rate limits triggered')
assert.equal(
res.locals.pointsToConsume,
config.anonRateLimit,
'Anonymous rate limits applied'
)
})
it('should apply rate limits when JWT token is provided', async () => {
// Generate a new JWT token for the test.
const jwtPayload = {
id: '5dade3f5739e6c0ff034b9a1',
pointsToConsume: 10
}
const jwtToken = uut.generateJwtToken(jwtPayload)
req.ip = '123.456.7.8'
req.locals.jwtToken = jwtToken
// console.log('next.callCount: ', next.callCount)
const startCallCount = next.callCount
await uut.applyRateLimits(req, res, next)
// console.log('next.callCount: ', next.callCount)
const endCallCount = next.callCount
assert.isAbove(
endCallCount,
startCallCount,
'Expecting next() to be called'
)
assert.equal(
res.locals.pointsToConsume,
10,
'Anonymous rate limits applied'
)
})
it('should apply internal rate limits to internal calls', async () => {
req.ip = '127.0.0.1'
// console.log('next.callCount: ', next.callCount)
const startCallCount = next.callCount
await uut.applyRateLimits(req, res, next)
// console.log('next.callCount: ', next.callCount)
const endCallCount = next.callCount
assert.isAbove(
endCallCount,
startCallCount,
'Expecting next() to be called'
)
assert.equal(
res.locals.pointsToConsume,
10,
'Internal rate limits applied'
)
})
it('should return 429 error when internal calls exceed interal rate limit', async () => {
req.ip = '127.0.0.1'
let val
for (let i = 0; i < 1025; i++) {
val = await uut.applyRateLimits(req, res, next)
}
assert.property(val, 'error')
assert.include(
val.error,
'Too many requests. Your limits are currently 1000 requests per minute.'
)
assert.equal(res.locals.rateLimitTriggered, true, 'Rate limits triggered')
assert.equal(
res.locals.pointsToConsume,
10,
'Internal rate limits applied'
)
})
it('should apply JWT rate limits to internal calls when JWT passes through', async () => {
// Generate a new JWT token for the test.
const jwtPayload = {
id: '5dade3f5739e6c0ff034b9a1',
pointsToConsume: 10
}
const jwtToken = uut.generateJwtToken(jwtPayload)
req.ip = '127.0.0.1'
req.body.usrObj = {
jwtToken
}
// console.log('next.callCount: ', next.callCount)
const startCallCount = next.callCount
await uut.applyRateLimits(req, res, next)
// console.log('next.callCount: ', next.callCount)
const endCallCount = next.callCount
assert.isAbove(
endCallCount,
startCallCount,
'Expecting next() to be called'
)
assert.equal(
res.locals.pointsToConsume,
10,
'User JWT rate limits applied'
)
})
it('should return 429 error when internal calls using JWT pass-through exceeds rate limit', async () => {
// Generate a new JWT token for the test.
const jwtPayload = {
id: '5dade3f5739e6c0ff034b9a1',
pointsToConsume: 100
}
const jwtToken = uut.generateJwtToken(jwtPayload)
req.ip = '127.0.0.1'
req.body.usrObj = {
jwtToken
}
try {
let val
for (let i = 0; i < 120; i++) {
val = await uut.applyRateLimits(req, res, next)
}
// console.log('val: ', val)
assert.property(val, 'error')
assert.include(
val.error,
'Too many requests. Your limits are currently 100 requests per minute.'
)
assert.equal(
res.locals.pointsToConsume,
100,
'User JWT rate limits applied'
)
} catch (err) {
console.log('err: ', err)
assert.fail('Unexpected result')
}
})
it('should move to the next middleware when encountering an unexpected internal error', async () => {
// Force the creation of the res and req locals property. Covers an
// otherwise untested code path.
req.locals = undefined
res.locals = undefined
// Force an error
sandbox.stub(uut, 'checkInternalIp').throws(new Error('test error'))
// console.log('next.callCount: ', next.callCount)
const startCallCount = next.callCount
await uut.applyRateLimits(req, res, next)
// console.log('next.callCount: ', next.callCount)
const endCallCount = next.callCount
assert.isAbove(
endCallCount,
startCallCount,
'Expecting next() to be called'
)
})
})
})
File diff suppressed because it is too large Load Diff
-34
View File
@@ -1,34 +0,0 @@
/*
Unit tests for the route-utils.js library.
*/
const assert = require('chai').assert
const RouteUtils = require('../../src/util/route-utils.js')
describe('#route-utils', () => {
let uut
beforeEach(() => {
uut = new RouteUtils()
})
describe('#decodeError', () => {
it('should decode a 429 error from nginx', () => {
const err = {
error: '<html>\r\n<head><title>429 Too Many Requests</title></head>\r\n<body>\r\n<center><h1>429 Too Many Requests</h1></center>\r\n<hr><center>nginx/1.18.0 (Ubuntu)</center>\r\n</body>\r\n</html>\r\n',
level: 'error',
message: 'Error in slp.js/hydrateUtxos().',
timestamp: '2021-03-31T04:13:36.662Z'
}
const result = uut.decodeError(err)
// console.log('result: ', result)
assert.property(result, 'msg')
assert.equal(result.msg, '429 Too Many Requests')
assert.property(result, 'status')
assert.equal(result.status, 429)
})
})
})
-2538
View File
File diff suppressed because it is too large Load Diff
-532
View File
@@ -1,532 +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.
These tests use this private key:
L1wAGEN721LHDoiN8pLwwBb87bYrU6Gs21UPcCRR7LjKypQyVaCq
Which corresponds to this address:
bitcoincash:qp2g4cnekxsjspccmtvh5k73mczz6273js4mjr353r
*/
'use strict'
// Public npm libraries
const assert = require('chai').assert
const nock = require('nock') // HTTP mocking
const sinon = require('sinon')
// Local libraries
const Electrumx = require('../../src/routes/v4/electrumx')
const UtilRoute = require('../../src/routes/v4/util')
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')
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
// const UtilRoute = utilRoute.UtilRoute
// const electrumx = new Electrumx()
const utilRouteInst = new UtilRoute({ electrumx: {} })
describe('#Util', () => {
let req, res
let sandbox
let electrumx
let utilRoute
before(async () => {
// 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'
}
electrumx = new Electrumx()
// await electrumx.connect()
})
// 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()
sandbox = sinon.createSandbox()
utilRoute = new UtilRoute({ electrumx })
})
afterEach(() => {
// Clean up HTTP mocks.
nock.cleanAll() // clear interceptor list.
nock.restore()
sandbox.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 = utilRouteInst.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 = utilRouteInst.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'
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((uri) => uri.includes('/'))
.reply(200, { result: mockData.mockAddress })
}
req.params.address =
'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd'
const result = await validateAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
'isvalid',
'address',
'scriptPubKey',
'ismine',
'iswatchonly',
'isscript'
])
})
})
describe('#validateAddressBulk', async () => {
const validateAddressBulk = utilRouteInst.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 (let 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: ['bchtest:qrls6vzjkkxlds7aqv9075u0fttwc7u9jvczn5fdt9']
}
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 = [
'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd'
]
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((uri) => uri.includes('/'))
.reply(200, { result: mockData.mockAddress })
}
req.body.addresses = [
'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd'
]
const result = await validateAddressBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAnyKeys(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((uri) => uri.includes('/'))
.times(2)
.reply(200, { result: mockData.mockAddress })
}
req.body.addresses = [
'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd',
'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd'
]
const result = await validateAddressBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
'isvalid',
'address',
'scriptPubKey',
'ismine',
'iswatchonly',
'isscript'
])
})
})
describe('#sweepWif', () => {
it('should throw 400 if WIF is not included', async () => {
req.body = {}
const result = await utilRouteInst.sweepWif(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'WIF needs to a proper compressed WIF starting with K or L',
'Proper error message'
)
})
it('should throw 400 if WIF is malformed', async () => {
req.body = {
wif: 'abc123'
}
const result = await utilRouteInst.sweepWif(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'WIF needs to a proper compressed WIF starting with K or L',
'Proper error message'
)
})
it('should throw 400 if destination address is not included', async () => {
req.body = {
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt'
}
const result = await utilRouteInst.sweepWif(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'address can not be empty',
'Proper error message'
)
})
// 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(utilRoute.electrumx, '_balanceFromElectrumx')
.resolves(mockData.mockBalance)
sandbox
.stub(utilRoute.electrumx, '_utxosFromElectrumx')
.resolves(mockData.mockUtxos)
sandbox
.stub(utilRoute.bchjs.SLP.Utils, 'tokenUtxoDetails')
.resolves(mockData.mockIsTokenUtxos)
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRoute.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: 'L1wAGEN721LHDoiN8pLwwBb87bYrU6Gs21UPcCRR7LjKypQyVaCq',
toAddr: 'bitcoincash:qp2g4cnekxsjspccmtvh5k73mczz6273js4mjr353r'
}
const result = await utilRoute.sweepWif(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, 'test-txid')
})
it('should return balance if balance-only is true', async () => {
// Mock the RPC call for unit tests.
sandbox
.stub(utilRoute.electrumx, '_balanceFromElectrumx')
.resolves(mockData.mockBalance)
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRoute.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt',
balanceOnly: true
}
const result = await utilRoute.sweepWif(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isNumber(result)
})
it('should generate transaction for valid BCH-only sweep', async () => {
sandbox
.stub(utilRoute.electrumx, '_balanceFromElectrumx')
.resolves(mockData.mockBalance)
sandbox
.stub(utilRoute.electrumx, '_utxosFromElectrumx')
.resolves(mockData.mockUtxos)
// Force token utxo to appear as regular BCH utxo.
sandbox
.stub(utilRoute.bchjs.SLP.Utils, 'tokenUtxoDetails')
.resolves([false, false])
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRoute.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt',
toAddr: 'bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p'
}
const result = await utilRoute.sweepWif(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, 'test-txid')
})
it('should throw 422 error if no non-token UTXOs', async () => {
sandbox
.stub(utilRoute.electrumx, '_balanceFromElectrumx')
.resolves(mockData.mockBalance)
sandbox
.stub(utilRoute.electrumx, '_utxosFromElectrumx')
.resolves(mockData.mockUtxos)
// Force token utxo to appear as regular BCH utxo.
sandbox
.stub(utilRoute.bchjs.SLP.Utils, 'tokenUtxoDetails')
.resolves(mockData.tokensOnly)
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRoute.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt',
toAddr: 'bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p'
}
const result = await utilRoute.sweepWif(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(res.statusCode, 422)
assert.property(result, 'error')
assert.include(
result.error,
'Tokens found, but no BCH UTXOs found. Add BCH to wallet to move tokens'
)
})
it('should detect and throw error for multiple token classes', async () => {
sandbox
.stub(utilRoute.electrumx, '_balanceFromElectrumx')
.resolves(mockData.mockBalance)
sandbox
.stub(utilRoute.electrumx, '_utxosFromElectrumx')
.resolves(mockData.mockThreeUtxos)
// Force token utxo to appear as regular BCH utxo.
sandbox
.stub(utilRoute.bchjs.SLP.Utils, 'tokenUtxoDetails')
.resolves(mockData.multipleTokens)
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRoute.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt',
toAddr: 'bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p'
}
const result = await utilRoute.sweepWif(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(res.statusCode, 422)
assert.property(result, 'error')
assert.include(
result.error,
'Multiple token classes detected. This function only supports a single class of token'
)
})
}
})
})
-143
View File
@@ -1,143 +0,0 @@
/*
TESTS FOR THE XPUB.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 xpubRoute = require('../../src/routes/v4/xpub')
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('#XPUBRouter', () => {
let req, res
before(() => {
// 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
})
// 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 = xpubRoute.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('#FromXPubSingle', () => {
// details route handler.
const fromXPubSingle = xpubRoute.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)
})
})
})