Files
bch-api/test/v4/blockchain.js
T

2023 lines
71 KiB
JavaScript

/*
TODO:
-getRawMempool
--Add tests for 'verbose' input values
-getMempoolEntry & getMempoolEntryBulk
--Needs e2e test to create unconfirmed tx, for real-world test.
*/
'use strict'
const chai = require('chai')
const assert = chai.assert
const sinon = require('sinon')
const Blockchain = require('../../src/routes/v4/full-node/blockchain')
const uut = new Blockchain()
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
if (!process.env.TEST) process.env.TEST = 'unit'
// Mocking data.
const { mockReq, mockRes } = require('./mocks/express-mocks')
const mockData = require('./mocks/blockchain-mock')
let originalEnvVars // Used during transition from integration to unit tests.
describe('#BlockchainRouter', () => {
let req, res
let sandbox
// local node will be started in regtest mode on the port 48332
// before(panda.runLocalNode)
before(() => {
// Save existing environment variables.
originalEnvVars = {
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
RPC_BASEURL: process.env.RPC_BASEURL,
RPC_USERNAME: process.env.RPC_USERNAME,
RPC_PASSWORD: process.env.RPC_PASSWORD
}
// Set default environment variables for unit tests.
if (process.env.TEST === 'unit') {
process.env.BITCOINCOM_BASEURL = 'http://fakeurl/api/'
process.env.RPC_BASEURL = 'http://fakeurl/api'
process.env.RPC_USERNAME = 'fakeusername'
process.env.RPC_PASSWORD = 'fakepassword'
}
})
// Setup the mocks before each test.
beforeEach(() => {
// Mock the req and res objects used by Express routes.
req = mockReq
res = mockRes
// Explicitly reset the parmas and body.
req.params = {}
req.body = {}
sandbox = sinon.createSandbox()
})
afterEach(() => {
// Restore Sandbox
sandbox.restore()
})
after(() => {
// otherwise the panda will run forever
// process.exit()
// Restore any pre-existing environment variables.
process.env.BITCOINCOM_BASEURL = originalEnvVars.BITCOINCOM_BASEURL
process.env.RPC_BASEURL = originalEnvVars.RPC_BASEURL
process.env.RPC_USERNAME = originalEnvVars.RPC_USERNAME
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
})
describe('#root', () => {
it('should respond to GET for base route', async () => {
const result = uut.root(req, res)
assert.equal(result.status, 'blockchain', 'Returns static string')
})
})
describe('getBestBlockHash()', () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await uut.getBestBlockHash(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 503 expected.')
assert.include(
result.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.getBestBlockHash(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.getBestBlockHash(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 /getBestBlockHash', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockHash } })
}
const result = await uut.getBestBlockHash(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
assert.equal(result.length, 64, 'Hash string is fixed length')
})
})
describe('getBlockchainInfo()', () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await uut.getBlockchainInfo(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 503 expected.')
assert.include(
result.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.getBestBlockHash(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.getBestBlockHash(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 /getBlockchainInfo', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockchainInfo } })
}
const result = await uut.getBlockchainInfo(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
'chain',
'blocks',
'headers',
'bestblockhash',
'difficulty',
'mediantime',
'verificationprogress',
'chainwork',
'pruned',
'softforks',
'bip9_softforks'
])
})
})
describe('getBlockCount()', () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await uut.getBlockCount(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 503 expected.')
assert.include(
result.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.getBlockCount(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.getBlockCount(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 /getBlockCount', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: 126769 } })
}
const result = await uut.getBlockCount(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isNumber(result)
})
})
describe('getBlockHeaderSingle()', async () => {
it('should throw 400 error if hash is missing', async () => {
const result = await uut.getBlockHeaderSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'hash can not be empty')
})
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
req.params.hash =
'00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900'
const result = await uut.getBlockHeaderSingle(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 503 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' })
req.params.hash =
'00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900'
const result = await uut.getBlockHeaderSingle(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' })
req.params.hash =
'00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900'
const result = await uut.getBlockHeaderSingle(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 block header', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(uut.axios, 'request').resolves({
data: {
result:
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c'
}
})
}
req.params.hash =
'000000000000000002fa9d7851b284c53a5831651b04211c266badf2ad2d8ef0'
const result = await uut.getBlockHeaderSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isString(result)
assert.equal(
result,
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c'
)
})
it('should GET verbose block header', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockHeader } })
}
req.query.verbose = true
req.params.hash =
'000000000000000002fa9d7851b284c53a5831651b04211c266badf2ad2d8ef0'
const result = await uut.getBlockHeaderSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, [
'hash',
'confirmations',
'height',
'version',
'versionHex',
'merkleroot',
'time',
'mediantime',
'nonce',
'bits',
'difficulty',
'chainwork',
'previousblockhash',
'nextblockhash',
'nTx'
])
})
})
//
describe('#getBlockHeaderBulk', () => {
it('should throw an error for an empty body', async () => {
req.body = {}
const result = await uut.getBlockHeaderBulk(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'hashes needs to be an array',
'Proper error message'
)
})
it('should error on non-array single hash', async () => {
req.body.hashes =
'00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900'
const result = await uut.getBlockHeaderBulk(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'hashes needs to be an array',
'Proper error message'
)
})
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
req.body.hashes = testArray
const result = await uut.getBlockHeaderBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Array too large')
})
it('should throw a 400 error for an invalid hash', async () => {
req.body.hashes = ['badHash']
await uut.getBlockHeaderBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
})
it('should throw 500 when network issues', async () => {
const savedUrl = process.env.BITCOINCOM_BASEURL
try {
req.body.hashes = [
'00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900'
]
// Switch the Insight URL to something that will error out.
process.env.BITCOINCOM_BASEURL = 'http://fakeurl/api/'
const result = await uut.getBlockHeaderBulk(req, res)
// Restore the saved URL.
process.env.BITCOINCOM_BASEURL = savedUrl
assert.equal(res.statusCode, 500, 'HTTP status code 500 expected.')
assert.include(result.error, 'ENOTFOUND', 'Error message expected')
} catch (err) {
// Restore the saved URL.
process.env.BITCOINCOM_BASEURL = savedUrl
}
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
req.body.hashes = [
'000000000000000002fa9d7851b284c53a5831651b04211c266badf2ad2d8ef0'
]
const result = await uut.getBlockHeaderBulk(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' })
req.body.hashes = [
'000000000000000002fa9d7851b284c53a5831651b04211c266badf2ad2d8ef0'
]
const result = await uut.getBlockHeaderBulk(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 concise block header for a single hash', async () => {
req.body.hashes = [
'000000000000000002fa9d7851b284c53a5831651b04211c266badf2ad2d8ef0'
]
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockHeaderConcise } })
}
// Call the details API.
const result = await uut.getBlockHeaderBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Assert that required fields exist in the returned object.
assert.isArray(result)
assert.equal(
result[0],
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c'
)
})
it('should get verbose block header for a single hash', async () => {
req.body = {
hashes: [
'000000000000000002fa9d7851b284c53a5831651b04211c266badf2ad2d8ef0'
],
verbose: true
}
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockHeader } })
}
// Call the details API.
const result = await uut.getBlockHeaderBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Assert that required fields exist in the returned object.
assert.isArray(result)
assert.hasAllKeys(result[0], [
'hash',
'confirmations',
'height',
'version',
'versionHex',
'merkleroot',
'time',
'mediantime',
'nonce',
'bits',
'difficulty',
'chainwork',
'previousblockhash',
'nextblockhash',
'nTx'
])
})
it('should get details for multiple block heights', async () => {
req.body.hashes = [
'000000000000000002fa9d7851b284c53a5831651b04211c266badf2ad2d8ef0',
'000000000000000002fa9d7851b284c53a5831651b04211c266badf2ad2d8ef0'
]
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockHeaderConcise } })
}
// Call the details API.
const result = await uut.getBlockHeaderBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.equal(result.length, 2, '2 outputs for 2 inputs')
})
})
describe('getChainTips()', () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await uut.getChainTips(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 503 expected.')
assert.include(
result.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.getChainTips(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.getChainTips(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 /getChainTips', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockChainTips } })
}
const result = await uut.getChainTips(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], ['height', 'hash', 'branchlen', 'status'])
})
})
describe('getDifficulty()', () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await uut.getDifficulty(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 503 expected.')
assert.include(
result.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.getDifficulty(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.getDifficulty(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 /getDifficulty', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: 4049809.205246544 } })
}
const result = await uut.getDifficulty(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isNumber(result)
})
})
describe('getMempoolInfo()', () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await uut.getMempoolInfo(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 503 expected.')
assert.include(
result.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.getMempoolInfo(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.getMempoolInfo(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 /getMempoolInfo', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockMempoolInfo } })
}
const result = await uut.getMempoolInfo(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
'result',
'bytes',
'usage',
'maxmempool',
'mempoolminfree'
])
})
})
describe('getRawMempool()', () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await uut.getRawMempool(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 503 expected.')
assert.include(
result.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.getRawMempool(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.getRawMempool(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 /getRawMempool', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockRawMempool } })
}
const result = await uut.getRawMempool(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
// Not sure what other assertions should be made here.
})
})
describe('getMempoolEntrySingle()', () => {
it('should throw 400 if txid is empty', async () => {
const result = await uut.getMempoolEntrySingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'txid can not be empty')
})
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
req.params.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getMempoolEntrySingle(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 503 expected.')
assert.include(
result.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' })
req.params.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getMempoolEntrySingle(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' })
req.params.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getMempoolEntrySingle(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 /getMempoolEntry', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(uut.axios, 'request').resolves({
data: { result: { error: 'Transaction not in mempool' } }
})
}
req.params.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getMempoolEntrySingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.isString(result.error)
assert.equal(result.error, 'Transaction not in mempool')
})
})
describe('#getMempoolEntryBulk', () => {
it('should throw an error for an empty body', async () => {
req.body = {}
const result = await uut.getMempoolEntryBulk(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'txids needs to be an array',
'Proper error message'
)
})
it('should error on non-array single txid', async () => {
req.body.txids =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getMempoolEntryBulk(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'txids needs to be an array',
'Proper error message'
)
})
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
const result = await uut.getMempoolEntryBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Array too large')
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
req.body.txids = [
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
]
const result = await uut.getMempoolEntryBulk(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' })
req.body.txids = [
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
]
const result = await uut.getMempoolEntryBulk(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'
)
})
// Only execute on integration tests.
if (process.env.TEST !== 'unit') {
// Dev-note: This test passes because it expects an error. TXIDs do not
// stay in the mempool for long, so it does not work well for a unit or
// integration test.
it('should retrieve single mempool entry', async () => {
req.body.txids = [
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
]
const result = await uut.getMempoolEntryBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.isString(result.error)
assert.equal(result.error, 'Transaction not in mempool')
})
// Dev-note: This test passes because it expects an error. TXIDs do not
// stay in the mempool for long, so it does not work well for a unit or
// integration test.
it('should retrieve multiple mempool entries', async () => {
req.body.txids = [
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde',
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
]
const result = await uut.getMempoolEntryBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.isString(result.error)
assert.equal(result.error, 'Transaction not in mempool')
})
}
})
describe('getMempoolAncestorsSingle()', () => {
it('should throw 400 if txid is empty', async () => {
const result = await uut.getMempoolAncestorsSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'txid can not be empty')
})
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
req.params.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getMempoolAncestorsSingle(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 503 expected.')
assert.include(
result.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' })
req.params.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getMempoolAncestorsSingle(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' })
req.params.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getMempoolAncestorsSingle(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 /getMempoolAncestorsSingle', async () => {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockAncestors } })
req.params.txid =
'bb0d349892d351da2767f8c45f6f7949713ff09bd12838d53e76158ddee3ce93'
const result = await uut.getMempoolAncestorsSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
})
})
describe('getTxOut()', () => {
it('should throw 400 if txid is empty', async () => {
const result = await uut.getTxOut(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'txid can not be empty')
})
it('should throw 400 if n is empty', async () => {
req.params.txid = 'sometxid'
const result = await uut.getTxOut(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'n can not be empty')
})
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
req.params.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
req.params.n = 0
const result = await uut.getTxOut(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 503 expected.')
assert.include(
result.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' })
req.params.txid =
'197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d'
req.params.n = 0
req.query.include_mempool = 'true'
const result = await uut.getTxOut(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' })
req.params.txid =
'197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d'
req.params.n = 0
req.query.include_mempool = 'true'
const result = await uut.getTxOut(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'
)
})
// This test can only run for unit tests. See TODO at the top of this file.
it('should GET /getTxOut', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockTxOut } })
}
req.params.txid =
'197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d'
req.params.n = 0
req.query.include_mempool = 'true'
const result = await uut.getTxOut(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
'bestblock',
'confirmations',
'value',
'scriptPubKey',
'coinbase'
])
assert.hasAllKeys(result.scriptPubKey, [
'asm',
'hex',
'reqSigs',
'type',
'addresses'
])
assert.isArray(result.scriptPubKey.addresses)
})
})
describe('getTxOutPost()', () => {
it('should throw 400 if txid is empty', async () => {
const result = await uut.getTxOutPost(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'txid can not be empty')
})
it('should throw 400 if n is empty', async () => {
req.body.txid = 'sometxid'
const result = await uut.getTxOutPost(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'vout can not be empty')
})
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
req.body.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
req.body.vout = 0
const result = await uut.getTxOutPost(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 503 expected.')
assert.include(
result.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' })
req.body.txid =
'197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d'
req.body.vout = 0
req.body.mempool = true
const result = await uut.getTxOutPost(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' })
req.body.txid =
'197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d'
req.body.vout = 0
req.body.mempool = true
const result = await uut.getTxOutPost(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 POST /getTxOut', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockTxOut } })
}
req.body.txid =
'197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d'
req.body.vout = 0
req.body.mempool = true
const result = await uut.getTxOutPost(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
'bestblock',
'confirmations',
'value',
'scriptPubKey',
'coinbase'
])
assert.hasAllKeys(result.scriptPubKey, [
'asm',
'hex',
'reqSigs',
'type',
'addresses'
])
assert.isArray(result.scriptPubKey.addresses)
})
})
describe('getTxOutProofSingle()', () => {
it('should throw 400 if txid is empty', async () => {
const result = await uut.getTxOutProofSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'txid can not be empty')
})
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
req.params.txid =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getTxOutProofSingle(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 503 expected.')
assert.include(
result.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' })
req.params.txid =
'197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d'
req.params.n = 0
req.query.include_mempool = 'true'
const result = await uut.getTxOutProofSingle(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' })
req.params.txid =
'197dcda59864b1eee05498fd3c52cad787ec56ab7e635503cb39f9ab6f295d5d'
req.params.n = 0
req.query.include_mempool = 'true'
const result = await uut.getTxOutProofSingle(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 /getTxOutProof', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockTxOutProof } })
}
req.params.txid =
'2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266'
const result = await uut.getTxOutProofSingle(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
})
describe('#getTxOutProofBulk', () => {
it('should throw an error for an empty body', async () => {
req.body = {}
const result = await uut.getTxOutProofBulk(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'txids needs to be an array',
'Proper error message'
)
})
it('should error on non-array single txid', async () => {
req.body.txids =
'd65881582ff2bff36747d7a0d0e273f10281abc8bd5c15df5d72f8f3fa779cde'
const result = await uut.getTxOutProofBulk(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'txids needs to be an array',
'Proper error message'
)
})
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
const result = await uut.getTxOutProofBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Array too large')
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
req.body.txids = [
'2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266'
]
const result = await uut.getTxOutProofBulk(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' })
req.body.txids = [
'2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266'
]
const result = await uut.getTxOutProofBulk(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 proof for single txid', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockTxOutProof } })
}
req.body.txids = [
'2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266'
]
const result = await uut.getTxOutProofBulk(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
})
it('should GET proof for multiple txids', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockTxOutProof } })
}
req.body.txids = [
'2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266',
'2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266'
]
const result = await uut.getTxOutProofBulk(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result.length, 2, 'Correct length of returned array')
})
})
describe('verifyTxOutProofSingle()', () => {
it('should throw 400 if proof is empty', async () => {
const result = await uut.verifyTxOutProofSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'proof can not be empty')
})
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = 'http://fakeurl/api/'
req.params.proof = mockData.mockTxOutProof
const result = await uut.verifyTxOutProofSingle(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 503 expected.')
assert.include(
result.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' })
req.params.proof =
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700'
const result = await uut.verifyTxOutProofSingle(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' })
req.params.proof =
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700'
const result = await uut.verifyTxOutProofSingle(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 /verifyTxOutProof', async () => {
const expected =
'2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266'
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: [expected] } })
}
req.params.proof =
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700'
const result = await uut.verifyTxOutProofSingle(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(result[0], expected)
})
})
describe('#verifyTxOutProofBulk', () => {
it('should throw an error for an empty body', async () => {
req.body = {}
const result = await uut.verifyTxOutProofBulk(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'proofs needs to be an array',
'Proper error message'
)
})
it('should error on non-array single txid', async () => {
req.body.proofs = mockData.mockTxOutProof
const result = await uut.verifyTxOutProofBulk(req, res)
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
'proofs needs to be an array',
'Proper error message'
)
})
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
req.body.proofs = testArray
const result = await uut.verifyTxOutProofBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Array too large')
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
req.body.proofs = [
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700'
]
const result = await uut.verifyTxOutProofBulk(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' })
req.body.proofs = [
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700'
]
const result = await uut.verifyTxOutProofBulk(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 single proof', async () => {
const expected =
'2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266'
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: [expected] } })
}
req.body.proofs = [
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700'
]
const result = await uut.verifyTxOutProofBulk(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(result[0], expected)
})
it('should get multiple proofs', async () => {
const expected =
'2c7ae9f865f7ce0c33c189b2f83414176903ce4b06ed9f8b7bcf55efbd4a7266'
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: [expected] } })
}
req.body.proofs = [
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700',
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700'
]
const result = await uut.verifyTxOutProofBulk(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(result[0], expected)
assert.equal(result.length, 2)
})
})
describe('getBlock()', () => {
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(uut.axios, 'request').throws({ code: 'ECONNABORTED' })
req.body.blockhash =
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700'
const result = await uut.getBlock(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' })
req.body.blockhash =
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c1e000000067139f230701a2819a76795564bd2f67ded7eeae68596f368eddb3dd5bc54e59320e896f71d61cfc3ae3d4a90fca08b1aa35ba91256d8939d2cad11e638c0081f66724abdef55cf7b8b9fed064bce0369171434f8b289c1330ccef765f8e97a2c0d794d81aafb535855f7daa6bb51e40f77c6b59d7af7f62d0eb726a4fc4df82353d56fcbda7c7ea6bd935d61af8fb3b295637e6f323b10231135b3f10a034cfb238f635830c0595e52c6c31247cf677b555f7a287076e20cd0e1d3cc9af7260f02b700'
const result = await uut.getBlock(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 throw 400 if blockhash is empty', async () => {
const result = await uut.getBlock(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'blockhash can not be empty')
})
it('return block info with verbosity 0', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockInfo.verbosity0 } })
}
req.body.blockhash =
'000000000000000002a5fe0bdd6e3f04342a975c0f55e57f97e73bb90041676b'
req.body.verbosity = 0
const result = await uut.getBlock(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
it('return block info with verbosity 1', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockInfo.verbosity1 } })
}
req.body.blockhash =
'000000000000000002a5fe0bdd6e3f04342a975c0f55e57f97e73bb90041676b'
req.body.verbosity = 1
const result = await uut.getBlock(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'hash', 'hash property expected')
assert.property(
result,
'confirmations',
'confirmations property expected'
)
assert.property(result, 'size', 'size property expected')
assert.property(result, 'strippedsize', 'strippedsize property expected')
assert.property(result, 'weight', 'weight property expected')
assert.property(result, 'height', 'height property expected')
assert.property(result, 'version', 'version property expected')
assert.property(result, 'versionHex', 'versionHex property expected')
assert.property(result, 'merkleroot', 'merkleroot property expected')
assert.property(result, 'tx', 'tx property expected')
assert.property(result, 'time', 'time property expected')
assert.property(result, 'mediantime', 'mediantime property expected')
assert.property(result, 'nonce', 'nonce property expected')
assert.property(result, 'bits', 'bits property expected')
assert.property(result, 'difficulty', 'difficulty property expected')
assert.property(result, 'chainwork', 'chainwork property expected')
assert.property(result, 'nTx', 'nTx property expected')
assert.property(
result,
'previousblockhash',
'previousblockhash property expected'
)
assert.property(
result,
'nextblockhash',
'nextblockhash property expected'
)
})
it('return block info with verbosity 2', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockInfo.verbosity1 } })
}
req.body.blockhash =
'000000000000000002a5fe0bdd6e3f04342a975c0f55e57f97e73bb90041676b'
req.body.verbosity = 1
const result = await uut.getBlock(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'hash', 'hash property expected')
assert.property(
result,
'confirmations',
'confirmations property expected'
)
assert.property(result, 'size', 'size property expected')
assert.property(result, 'strippedsize', 'strippedsize property expected')
assert.property(result, 'weight', 'weight property expected')
assert.property(result, 'height', 'height property expected')
assert.property(result, 'version', 'version property expected')
assert.property(result, 'versionHex', 'versionHex property expected')
assert.property(result, 'merkleroot', 'merkleroot property expected')
assert.property(result, 'tx', 'tx property expected')
assert.property(result, 'time', 'time property expected')
assert.property(result, 'mediantime', 'mediantime property expected')
assert.property(result, 'nonce', 'nonce property expected')
assert.property(result, 'bits', 'bits property expected')
assert.property(result, 'difficulty', 'difficulty property expected')
assert.property(result, 'chainwork', 'chainwork property expected')
assert.property(result, 'nTx', 'nTx property expected')
assert.property(
result,
'previousblockhash',
'previousblockhash property expected'
)
assert.property(
result,
'nextblockhash',
'nextblockhash property expected'
)
})
it('return block info without verbosity especified', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox
.stub(uut.axios, 'request')
.resolves({ data: { result: mockData.mockBlockInfo.verbosity1 } })
}
req.body.blockhash =
'000000000000000002a5fe0bdd6e3f04342a975c0f55e57f97e73bb90041676b'
const result = await uut.getBlock(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'hash', 'hash property expected')
assert.property(
result,
'confirmations',
'confirmations property expected'
)
assert.property(result, 'size', 'size property expected')
assert.property(result, 'strippedsize', 'strippedsize property expected')
assert.property(result, 'weight', 'weight property expected')
assert.property(result, 'height', 'height property expected')
assert.property(result, 'version', 'version property expected')
assert.property(result, 'versionHex', 'versionHex property expected')
assert.property(result, 'merkleroot', 'merkleroot property expected')
assert.property(result, 'tx', 'tx property expected')
assert.property(result, 'time', 'time property expected')
assert.property(result, 'mediantime', 'mediantime property expected')
assert.property(result, 'nonce', 'nonce property expected')
assert.property(result, 'bits', 'bits property expected')
assert.property(result, 'difficulty', 'difficulty property expected')
assert.property(result, 'chainwork', 'chainwork property expected')
assert.property(result, 'nTx', 'nTx property expected')
assert.property(
result,
'previousblockhash',
'previousblockhash property expected'
)
assert.property(
result,
'nextblockhash',
'nextblockhash property expected'
)
})
})
})