fixing merge conflicts

This commit is contained in:
Chris Troutner
2022-02-06 13:36:37 -08:00
26 changed files with 12068 additions and 12009 deletions
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# Remove all untagged docker images.
docker rmi $(docker images | grep "^<none>" | awk '{print $3}')
+6 -1
View File
@@ -40,7 +40,7 @@ export REDIS_HOST=172.17.0.1
export TOKENSECRET=somelongsecretvalue
# So that bch-api can call bch-js locally.
export LOCAL_RESTURL=http://127.0.0.1:3000/v4/
export LOCAL_RESTURL=http://127.0.0.1:3000/v5/
# Basic Authentication password
export PRO_PASS=somerandomepassword:someotherrandompassword:aThirdPassword
@@ -65,6 +65,11 @@ export LOG_MAX_SIZE=1m
#5d means store no more than 5 days
export LOG_MAX_FILES=5d
# (Optional) bcash full node
export BCASH_SERVER=http://localhost:3002/
# psf-slp-indexer
#export SLP_INDEXER_API=https://psf-slp-indexer.fullstack.cash/
export SLP_INDEXER_API=http://172.17.0.1:5010/
npm start
+10732 -11588
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -25,7 +25,7 @@
"coverage:report": "export NETWORK=mainnet && nyc --reporter=html mocha --timeout 25000 test/v4/",
"docs": "./node_modules/.bin/apidoc -i src/routes/v5 -o docs",
"test:temp1": "export NETWORK=mainnet && export TEST=integration && mocha -g '#utxosBulk' --exit --timeout 30000 test/v5/",
"test:temp2": "export NETWORK=mainnet && mocha -g '#utxosBulk' --exit --timeout 30000 test/v5/"
"test:temp2": "export SLP_INDEXER_API=http://fakeurl/api/ && export NETWORK=mainnet && mocha --exit --timeout 30000 test/v5/psf-slp-indexer"
},
"engines": {
"node": ">=10.15.1"
@@ -62,19 +62,19 @@
"bignumber.js": "^9.0.0",
"chai": "^4.1.2",
"coveralls": "^3.0.2",
"eslint": "5.16.0",
"eslint-config-prettier": "^6.0.0",
"eslint-config-standard": "^13.0.1",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-standard": "^4.0.0",
"eslint": "7.17.0",
"eslint-config-prettier": "7.1.0",
"eslint-config-standard": "16.0.2",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-standard": "4.0.0",
"fs-extra": "^9.0.0",
"lodash.clonedeep": "^4.5.0",
"nock": "^13.0.5",
"nyc": "^15.0.0",
"prettier": "^2.0.0",
"semantic-release": "^17.4.2",
"sinon": "^9.0.0",
"standard": "^14.3.1"
"standard": "^16.0.4"
},
"release": {
"publish": [
+10 -3
View File
@@ -55,6 +55,7 @@ const EncryptionV5 = require('./routes/v5/encryption')
const PriceV5 = require('./routes/v5/price')
const JWTV5 = require('./routes/v5/jwt')
const BcashSLP = require('./routes/v5/bcash/slp')
const PsfSlpIndexer = require('./routes/v5/psf-slp-indexer')
// const Ninsight = require('./routes/v5/ninsight')
require('dotenv').config()
@@ -84,6 +85,7 @@ const utilV5 = new UtilV5({ electrumx: electrumxv5 })
const dsproofV5 = new DSProofV5()
const jwtV5 = new JWTV5()
const bcashSLP = new BcashSLP()
const psfSlpIndexer = new PsfSlpIndexer()
const app = express()
app.locals.env = process.env
@@ -100,7 +102,7 @@ app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'jade')
// Mount the docs
app.use('/docs', express.static(`${__dirname}/../docs`))
app.use('/docs', express.static(`${__dirname.toString()}/../docs`))
// Log each request to the console with IP addresses.
// app.use(logger("dev"))
@@ -200,6 +202,11 @@ app.use(`/${v5prefix}/` + 'ninsight', ninsight.router)
app.use(`/${v5prefix}/` + 'bcash/slp', bcashSLP.router)
app.use(`/${v5prefix}/` + 'psf/slp', psfSlpIndexer.router)
// Daniel:
// app.use(`/${v5prefix}/` + 'psfslp', psfSlp.router)
// catch 404 and forward to error handler
app.use((req, res, next) => {
const err = {
@@ -285,11 +292,11 @@ function onError (error) {
case 'EACCES':
console.error(`${bind} requires elevated privileges`)
process.exit(1)
// break
break
case 'EADDRINUSE':
console.error(`${bind} is already in use`)
process.exit(1)
// break
break
default:
throw error
}
+2 -2
View File
@@ -105,8 +105,8 @@ class Slpdb {
const username = 'BITBOX'
const password = SLPDB_PASS
const combined = `${username}:${password}`
var base64Credential = Buffer.from(combined).toString('base64')
var readyCredential = `Basic ${base64Credential}`
const base64Credential = Buffer.from(combined).toString('base64')
const readyCredential = `Basic ${base64Credential}`
const options = {
headers: {
+10 -11
View File
@@ -418,9 +418,8 @@ class Slp {
},
{
$match: {
'graphTxn.outputs.address': _this.bchjs.SLP.Address.toSLPAddress(
address
),
'graphTxn.outputs.address':
_this.bchjs.SLP.Address.toSLPAddress(address),
'graphTxn.outputs.status': 'UNSPENT',
'graphTxn.outputs.slpAmount': { $gte: 0 }
}
@@ -631,9 +630,8 @@ class Slp {
},
{
$match: {
'graphTxn.outputs.address': _this.bchjs.SLP.Address.toSLPAddress(
address
),
'graphTxn.outputs.address':
_this.bchjs.SLP.Address.toSLPAddress(address),
'graphTxn.outputs.status': 'UNSPENT',
'graphTxn.outputs.slpAmount': { $gte: 0 }
}
@@ -1234,7 +1232,7 @@ class Slp {
const opt = {
method: 'get',
baseURL: `${process.env.SLP_API_URL}slp/validate/${txid}`,
timeout: 10000 // Exit after 10 seconds.
timeout: 45000 // Exit after 45 seconds.
}
const tokenRes = await _this.axios.request(opt)
// console.log(`tokenRes.data: ${JSON.stringify(tokenRes.data, null, 2)}`)
@@ -1753,8 +1751,8 @@ class Slp {
const password = SLPDB_PASS_GP
const combined = `${username}:${password}`
// console.log(`combined: ${combined}`)
var base64Credential = Buffer.from(combined).toString('base64')
var readyCredential = `Basic ${base64Credential}`
const base64Credential = Buffer.from(combined).toString('base64')
const readyCredential = `Basic ${base64Credential}`
const options = {
headers: {
@@ -1773,8 +1771,8 @@ class Slp {
const password = SLPDB_PASS_WL
const combined = `${username}:${password}`
// console.log(`combined: ${combined}`)
var base64Credential = Buffer.from(combined).toString('base64')
var readyCredential = `Basic ${base64Credential}`
const base64Credential = Buffer.from(combined).toString('base64')
const readyCredential = `Basic ${base64Credential}`
const options = {
headers: {
@@ -1803,6 +1801,7 @@ class Slp {
tokenOutputs.map((x) => {
const string = parseFloat(x.amount) * 100000000
sendOutputs.push(string.toString())
return 1 // Making the linter happy
})
// Because you are not using Insight API indexer, you do not get the
+1 -1
View File
@@ -433,7 +433,7 @@ class UtilRoute {
// Loop through each input and sign
let redeemScript
for (var i = 0; i < utxos.length; i++) {
for (let i = 0; i < utxos.length; i++) {
const utxo = utxos[i]
transactionBuilder.sign(
+17 -9
View File
@@ -1,5 +1,5 @@
/*
Electrum API route
bcash node routes for working with SLP tokens.
*/
'use strict'
@@ -33,14 +33,6 @@ class BcashSlp {
this.bchjs = bchjs
// _this.bitcore = bitcore
this.bcashServer = process.env.BCASH_SERVER
if (!this.bcashServer) {
// console.warn('FULCRUM_API env var not set. Can not connect to Fulcrum indexer.')
throw new Error(
'BCASH_SERVER env var not set. Can not connect to bcash full node.'
)
}
this.router = router
this.router.get('/', this.root)
this.router.get('/utxos/:address', this.getUtxos)
@@ -63,6 +55,14 @@ class BcashSlp {
try {
const address = req.params.address
this.bcashServer = process.env.BCASH_SERVER
if (!this.bcashServer) {
// console.warn('FULCRUM_API env var not set. Can not connect to Fulcrum indexer.')
throw new Error(
'BCASH_SERVER env var not set. Can not connect to bcash full node.'
)
}
// Reject if address is an array.
if (Array.isArray(address)) {
res.status(400)
@@ -144,6 +144,14 @@ class BcashSlp {
throw new Error('tokenId must be string')
}
this.bcashServer = process.env.BCASH_SERVER
if (!this.bcashServer) {
// console.warn('FULCRUM_API env var not set. Can not connect to Fulcrum indexer.')
throw new Error(
'BCASH_SERVER env var not set. Can not connect to bcash full node.'
)
}
const result = await _this.axios.get(
`${_this.bcashServer}token/${tokenId}`
)
+261
View File
@@ -0,0 +1,261 @@
/*
Routes for interacting with the psf-slp-indexer
*/
// Public npm libraries
const express = require('express')
const router = express.Router()
const axios = require('axios')
const util = require('util')
// Local libraries
const RouteUtils = require('../../util/route-utils')
const routeUtils = new RouteUtils()
const BCHJS = require('@psf/bch-js')
const bchjs = new BCHJS()
// Local libraries
// const wlogger = require('../../../util/winston-logging')
const config = require('../../../config')
let _this
class PsfSlpIndexer {
constructor () {
// Encapsulate dependencies
this.axios = axios
this.router = router
this.routeUtils = routeUtils
this.config = config
this.bchjs = bchjs
// Define routes
this.router.get('/', this.root)
this.router.get('/status', this.getStatus)
this.router.post('/address', this.getAddress)
this.router.post('/txid', this.getTxid)
this.router.post('/token', this.getTokenStats)
_this = this
}
// Root API endpoint. Simply acknowledges that it exists.
root (req, res, next) {
return res.json({ status: 'psf-slp-indexer' })
}
/**
* @api {get} /psf/slp/status/ Indexer Status.
* @apiName SLP indexer status.
* @apiGroup PSF SLP
* @apiDescription Return SLP indexer status
*
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:3000/v5/psf/slp/status
*
*
*/
async getStatus (req, res, next) {
try {
// Verify env var is set for interacting with the indexer.
_this.checkEnvVar()
const response = await _this.axios.get(
`${_this.psfSlpIndexerApi}slp/status/`
)
res.status(200)
return res.json(response.data)
} catch (err) {
return _this.errorHandler(err, res)
}
}
/**
* @api {post} /psf/slp/address/ SLP balance for address.
* @apiName SLP balance for address.
* @apiGroup PSF SLP
* @apiDescription Return SLP balance for address
*
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "address": "bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n" }' localhost:3000/v5/psf/slp/address
*
*
*/
async getAddress (req, res, next) {
try {
// Verify env var is set for interacting with the indexer.
_this.checkEnvVar()
// Validate the input data.
const address = req.body.address
if (!address || address === '') {
res.status(400)
return res.json({
success: false,
error: 'address can not be empty'
})
}
// Ensure the input is a valid BCH address.
try {
_this.bchjs.SLP.Address.toCashAddress(address)
} catch (err) {
res.status(400)
return res.json({
success: false,
error: `Invalid BCH address. Double check your address is valid: ${address}`
})
}
// Prevent a common user error. Ensure they are using the correct network address.
const cashAddr = _this.bchjs.SLP.Address.toCashAddress(address)
const networkIsValid = _this.routeUtils.validateNetwork(cashAddr)
if (!networkIsValid) {
res.status(400)
return res.json({
success: false,
error:
'Invalid network. Trying to use a testnet address on mainnet, or vice versa.'
})
}
const response = await _this.axios.post(
`${_this.psfSlpIndexerApi}slp/address/`,
{ address }
)
res.status(200)
return res.json(response.data)
} catch (err) {
// console.log('err', err)
return _this.errorHandler(err, res)
}
}
/**
* @api {post} /psf/slp/txid/ SLP transaction data.
* @apiName SLP transaction data.
* @apiGroup PSF SLP
* @apiDescription Return slp transaction data.
*
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "txid": "f3e14cd871402a766e85045dc552f2c1e87857dd3ea1b15efab6334ccef5e315" }' localhost:3000/v5/psf/slp/txid
*
*
*/
async getTxid (req, res, next) {
try {
// Verify env var is set for interacting with the indexer.
_this.checkEnvVar()
const txid = req.body.txid
if (!txid || txid === '') {
res.status(400)
return res.json({
success: false,
error: 'txid can not be empty'
})
}
if (txid.length !== 64) {
res.status(400)
return res.json({
success: false,
error: 'This is not a txid'
})
}
const response = await _this.axios.post(
`${_this.psfSlpIndexerApi}slp/tx/`,
{ txid }
)
res.status(200)
return res.json(response.data)
} catch (err) {
// console.log('err', err)
return _this.errorHandler(err, res)
}
}
/**
* @api {post} /psf/slp/token List stats for a single slp token.
* @apiName List stats for a single slp token.
* @apiGroup PSF SLP
* @apiDescription Return list stats for a single slp token.
*
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "tokenId": "a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2" }' localhost:3000/v5/psf/slp/token
*
*
*/
async getTokenStats (req, res, next) {
try {
// Verify env var is set for interacting with the indexer.
_this.checkEnvVar()
const tokenId = req.body.tokenId
if (!tokenId || tokenId === '') {
res.status(400)
return res.json({
success: false,
error: 'tokenId can not be empty'
})
}
// Flag to toggle tx history of the token.
let withTxHistory = false
if (req.body.withTxHistory) withTxHistory = true
const response = await _this.axios.post(
`${_this.psfSlpIndexerApi}slp/token/`,
{ tokenId, withTxHistory }
)
res.status(200)
return res.json(response.data)
} catch (err) {
return _this.errorHandler(err, res)
}
}
// Check the the environment variable is set correctly.
checkEnvVar () {
_this.psfSlpIndexerApi = process.env.SLP_INDEXER_API
if (!_this.psfSlpIndexerApi) {
throw new Error(
'SLP_INDEXER_API env var not set. Can not connect to PSF SLP indexer.'
)
}
}
// DRY error handler.
errorHandler (err, res) {
// Attempt to decode the error message.
const { msg, status } = _this.routeUtils.decodeError(err)
// console.log('errorHandler msg: ', msg)
// console.log('errorHandler status: ', status)
if (msg) {
res.status(status)
return res.json({ success: false, error: msg })
}
// Handle error patterns specific to this route.
if (err.message) {
res.status(400)
return res.json({ success: false, error: err.message })
}
// If error can be handled, return the stack trace
res.status(500)
return res.json({ error: util.inspect(err) })
}
}
module.exports = PsfSlpIndexer
+2 -2
View File
@@ -105,8 +105,8 @@ class Slpdb {
const username = 'BITBOX'
const password = SLPDB_PASS
const combined = `${username}:${password}`
var base64Credential = Buffer.from(combined).toString('base64')
var readyCredential = `Basic ${base64Credential}`
const base64Credential = Buffer.from(combined).toString('base64')
const readyCredential = `Basic ${base64Credential}`
const options = {
headers: {
+10 -11
View File
@@ -418,9 +418,8 @@ class Slp {
},
{
$match: {
'graphTxn.outputs.address': _this.bchjs.SLP.Address.toSLPAddress(
address
),
'graphTxn.outputs.address':
_this.bchjs.SLP.Address.toSLPAddress(address),
'graphTxn.outputs.status': 'UNSPENT',
'graphTxn.outputs.slpAmount': { $gte: 0 }
}
@@ -631,9 +630,8 @@ class Slp {
},
{
$match: {
'graphTxn.outputs.address': _this.bchjs.SLP.Address.toSLPAddress(
address
),
'graphTxn.outputs.address':
_this.bchjs.SLP.Address.toSLPAddress(address),
'graphTxn.outputs.status': 'UNSPENT',
'graphTxn.outputs.slpAmount': { $gte: 0 }
}
@@ -1753,14 +1751,14 @@ class Slp {
const password = SLPDB_PASS_GP
const combined = `${username}:${password}`
// console.log(`combined: ${combined}`)
var base64Credential = Buffer.from(combined).toString('base64')
var readyCredential = `Basic ${base64Credential}`
const base64Credential = Buffer.from(combined).toString('base64')
const readyCredential = `Basic ${base64Credential}`
const options = {
headers: {
authorization: readyCredential
},
timeout: 15000
timeout: 45000
}
return options
@@ -1773,8 +1771,8 @@ class Slp {
const password = SLPDB_PASS_WL
const combined = `${username}:${password}`
// console.log(`combined: ${combined}`)
var base64Credential = Buffer.from(combined).toString('base64')
var readyCredential = `Basic ${base64Credential}`
const base64Credential = Buffer.from(combined).toString('base64')
const readyCredential = `Basic ${base64Credential}`
const options = {
headers: {
@@ -1803,6 +1801,7 @@ class Slp {
tokenOutputs.map((x) => {
const string = parseFloat(x.amount) * 100000000
sendOutputs.push(string.toString())
return 1 // Making the linter happy
})
// Because you are not using Insight API indexer, you do not get the
+9 -7
View File
@@ -6,24 +6,26 @@
'use strict'
var winston = require('winston')
const winston = require('winston')
require('winston-daily-rotate-file')
var NETWORK = process.env.NETWORK
const NETWORK = process.env.NETWORK
// Default 1 Megabyte
var LOG_MAX_SIZE = process.env.LOG_MAX_SIZE ? process.env.LOG_MAX_SIZE : '1m'
const LOG_MAX_SIZE = process.env.LOG_MAX_SIZE ? process.env.LOG_MAX_SIZE : '1m'
// Default 5 days.
// This was causing a problem with popularity. Creating over a gigabyte of files.
// var LOG_MAX_FILES = process.env.LOG_MAX_FILES ? process.env.LOG_MAX_FILES : '5d'
// 250 files @ 1Meg each = 250 megs
var LOG_MAX_FILES = process.env.LOG_MAX_FILES ? process.env.LOG_MAX_FILES : '250'
const LOG_MAX_FILES = process.env.LOG_MAX_FILES
? process.env.LOG_MAX_FILES
: '250'
// Configure daily-rotation transport.
var transport = new winston.transports.DailyRotateFile({
filename: `${__dirname}/../../logs/rest-${NETWORK}-%DATE%.log`,
const transport = new winston.transports.DailyRotateFile({
filename: `${__dirname.toString()}/../../logs/rest-${NETWORK}-%DATE%.log`,
datePattern: 'YYYY-MM-DD',
zippedArchive: false,
maxSize: LOG_MAX_SIZE,
@@ -39,7 +41,7 @@ transport.on('rotate', function (oldFilename, newFilename) {
})
// This controls what goes into the log FILES
var wlogger = winston.createLogger({
const wlogger = winston.createLogger({
level: 'verbose',
format: winston.format.json(),
transports: [
+3
View File
@@ -73,4 +73,7 @@ export LOG_MAX_FILES=5d
# (Optional) if using a bcash node, set this variable. Otherwise leave it as-is.
export BCASH_SERVER=http://localhost
# PSF SLP indexer
export SLP_INDEXER_API=https://psf-slp-indexer.fullstack.cash/
npm start
+6 -6
View File
@@ -359,7 +359,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
@@ -596,7 +596,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if txid array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -843,7 +843,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if heights array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.heights = testArray
@@ -1206,7 +1206,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
@@ -1494,7 +1494,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
@@ -1781,7 +1781,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
+4 -4
View File
@@ -456,7 +456,7 @@ describe('#BlockchainRouter', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.hashes = testArray
@@ -1006,7 +1006,7 @@ describe('#BlockchainRouter', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -1525,7 +1525,7 @@ describe('#BlockchainRouter', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -1729,7 +1729,7 @@ describe('#BlockchainRouter', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.proofs = testArray
+4 -4
View File
@@ -216,7 +216,7 @@ describe('#Raw-Transactions', () => {
it('should throw 400 error if hexes array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.hexes = testArray
@@ -459,7 +459,7 @@ describe('#Raw-Transactions', () => {
it('should throw 400 error if hexes array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.hexes = testArray
@@ -599,7 +599,7 @@ describe('#Raw-Transactions', () => {
it('should throw 400 error if txids array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -885,7 +885,7 @@ describe('#Raw-Transactions', () => {
it('should throw 400 error if hexs array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.hexes = testArray
+13 -23
View File
@@ -36,7 +36,7 @@ if (process.env.TEST === 'unit') {
process.env.BITDB_URL = 'http://fakeurl/'
process.env.BITCOINCOM_BASEURL = 'http://fakeurl/'
process.env.SLPDB_URL = 'http://fakeurl/'
mockServerUrl = 'http://fakeurl'
// mockServerUrl = 'http://fakeurl'
}
// Prepare the slpRoute for stubbing dependcies on slpjs.
@@ -577,7 +577,7 @@ describe('#SLP', () => {
it('should throw 400 error if array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -787,7 +787,7 @@ describe('#SLP', () => {
it('should throw 400 error if array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -1406,8 +1406,7 @@ describe('#SLP', () => {
it('should throw error if Array is too long', async () => {
const utxo = {
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
txid: 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 3,
amount: 0.00002015,
satoshis: 2015,
@@ -1435,8 +1434,7 @@ describe('#SLP', () => {
{
utxos: [
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
@@ -1444,8 +1442,7 @@ describe('#SLP', () => {
satoshis: 6816
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
@@ -1459,8 +1456,7 @@ describe('#SLP', () => {
// Mock the external network call.
sandbox.stub(slpRoute.bchjs.SLP.Utils, 'tokenUtxoDetails').resolves([
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
@@ -1469,8 +1465,7 @@ describe('#SLP', () => {
isValid: false
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
@@ -1581,8 +1576,7 @@ describe('#SLP', () => {
it('should throw error if Array is too long', async () => {
const utxo = {
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
txid: 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 3,
amount: 0.00002015,
satoshis: 2015,
@@ -1610,8 +1604,7 @@ describe('#SLP', () => {
{
utxos: [
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
@@ -1619,8 +1612,7 @@ describe('#SLP', () => {
satoshis: 6816
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
@@ -1634,8 +1626,7 @@ describe('#SLP', () => {
// Mock the external network call.
sandbox.stub(slpRoute.bchjs.SLP.Utils, 'tokenUtxoDetailsWL').resolves([
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
@@ -1644,8 +1635,7 @@ describe('#SLP', () => {
isValid: false
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
+1 -1
View File
@@ -203,7 +203,7 @@ describe('#Util', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
+6 -6
View File
@@ -239,7 +239,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
@@ -485,7 +485,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
@@ -729,7 +729,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -1065,7 +1065,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if heights array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.heights = testArray
@@ -1261,7 +1261,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
@@ -1503,7 +1503,7 @@ describe('#Electrumx', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
+4 -4
View File
@@ -456,7 +456,7 @@ describe('#BlockchainRouter', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.hashes = testArray
@@ -1006,7 +1006,7 @@ describe('#BlockchainRouter', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -1525,7 +1525,7 @@ describe('#BlockchainRouter', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -1729,7 +1729,7 @@ describe('#BlockchainRouter', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.proofs = testArray
+130
View File
@@ -0,0 +1,130 @@
/*
This library contains mocking data for running unit tests on the psf-slp-indexer route.
*/
'use strict'
const tokenStats = {
tokenData: {
type: 1,
ticker: 'TP03',
name: 'Test Plugin 03',
tokenId: '13cad617d523c8eb4ab11fff19c010e0e0a4ea4360b58e0c8c955a45a146a669',
documentUri: 'fullstack.cash',
documentHash: 'i\u00043s\u0003tz}/PǚZ>T)',
decimals: 0,
mintBatonIsActive: false,
tokensInCirculationBN: '1',
tokensInCirculationStr: '1',
blockCreated: 722420,
totalBurned: '0',
totalMinted: '1',
txs: [
{
txid: '13cad617d523c8eb4ab11fff19c010e0e0a4ea4360b58e0c8c955a45a146a669',
height: 722420,
type: 'GENESIS',
qty: '1'
}
]
}
}
const txData = {
txData: {
txid: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
hash: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
version: 2,
size: 339,
locktime: 0,
vin: [
{
txid: '8370db30d94761ab9a11b71ecd22541151bf6125c8c613f0f6fab8ab794565a7',
vout: 0,
scriptSig: {
asm: '304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4[ALL|FORKID] 02791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851',
hex: '47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851'
},
sequence: 4294967295,
address: 'bitcoincash:qpvsg9vl9a5mlf37a7n3yce6pktdctn73qwgaqm3wq',
value: 0.00051303,
tokenQty: 0,
tokenQtyStr: '0',
tokenId: null
}
],
vout: [
{
value: 0,
n: 0,
scriptPubKey: {
asm: 'OP_RETURN 5262419 1 47454e45534953 54524f5554 54726f75742773207465737420746f6b656e 74726f757473626c6f672e636f6d 0 2 2 000000174876e800',
hex: '6a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e800',
type: 'nulldata'
},
tokenQtyStr: '0',
tokenQty: 0
}
],
hex: '0200000001a7654579abb8faf6f013c6c82561bf51115422cd1eb7119aab6147d930db7083000000006a47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851ffffffff040000000000000000476a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e80022020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088ac22020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088accec20000000000001976a9145904159f2f69bfa63eefa712633a0d96dc2e7e8888ac00000000',
blockhash: '0000000000000000009f65225a3e12e23a7ea057c869047e0f36563a1f410267',
confirmations: 97398,
time: 1581773131,
blocktime: 1581773131,
blockheight: 622414,
isSlpTx: true,
tokenTxType: 'GENESIS',
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
tokenType: 1,
tokenTicker: 'TROUT',
tokenName: "Trout's test token",
tokenDecimals: 2,
tokenUri: 'troutsblog.com',
tokenDocHash: '',
isValidSlp: true
}
}
const balance = {
balance: {
utxos: [
{
txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9',
vout: 1,
type: 'token',
qty: '1800',
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
address: 'bitcoincash:qrqy3kj7r822ps6628vwqq5k8hyjl6ey3y4eea2m4s'
}
],
txs: [
{
txid: '078b2c48ed1db0d5d5996f2889b8d847a49200d0a781f6aa6752f740f312688f',
height: 717796
},
{
txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9',
height: 717832
}
],
balances: [
{
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
qty: '1800'
}
]
}
}
const status = {
status: {
startBlockHeight: 543376,
syncedBlockHeight: 722860,
chainBlockHeight: 722679
}
}
module.exports = {
tokenStats,
txData,
balance,
status
}
+508
View File
@@ -0,0 +1,508 @@
/*
TESTS FOR THE PSF-SLP-INDEXER.JS LIBRARY
*/
'use strict'
const chai = require('chai')
const assert = chai.assert
const PsfSlpIndexerRouter = require('../../src/routes/v5/psf-slp-indexer')
const uut = new PsfSlpIndexerRouter()
// 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/psf-slp-indexer-mocks')
// Used for debugging.
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
describe('#PsfSlpIndexer', () => {
let req, res
let sandbox
before(() => {
// Save existing environment variables.
originalEnvVars = {
SLP_INDEXER_API: process.env.SLP_INDEXER_API
}
// Set default environment variables for unit tests.
if (!process.env.TEST) process.env.TEST = 'unit'
if (process.env.TEST === 'unit') {
process.env.SLP_INDEXER_API = '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 = {}
sandbox = sinon.createSandbox()
})
afterEach(() => {
// Restore Sandbox
sandbox.restore()
})
after(() => {
// Restore any pre-existing environment variables.
process.env.SLP_INDEXER_API = originalEnvVars.SLP_INDEXER_API
})
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, 'psf-slp-indexer', 'Returns static string')
})
})
describe('#getTokenStats', async () => {
it('should throw 400 error if tokenId is missing', async () => {
const result = await uut.getTokenStats(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error', 'success'])
assert.isFalse(result.success)
assert.include(result.error, 'tokenId can not be empty')
})
it('should throw 503 when network issues', async () => {
req.body.tokenId =
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
// Save the existing RPC URL.
const savedUrl2 = process.env.SLP_INDEXER_API
// Manipulate the URL to cause a 500 network error.
process.env.SLP_INDEXER_API = 'http://fakeurl/api/'
await uut.getTokenStats(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Restore the saved URL.
process.env.SLP_INDEXER_API = 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 () => {
req.body.tokenId =
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
// Mock the timeout error.
sandbox.stub(uut.axios, 'post').throws({ code: 'ECONNABORTED' })
const result = await uut.getTokenStats(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 () => {
req.body.tokenId =
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
// Mock the timeout error.
sandbox.stub(uut.axios, 'post').throws({ code: 'ECONNREFUSED' })
const result = await uut.getTokenStats(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 tokens stats', async function () {
req.body.tokenId =
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(uut.axios, 'post').resolves({ data: mockData.tokenStats })
} else {
return this.skip()
}
const result = await uut.getTokenStats(req, res)
const tokenData = result.tokenData
assert.property(tokenData, 'type')
assert.property(tokenData, 'ticker')
assert.property(tokenData, 'name')
assert.property(tokenData, 'tokenId')
assert.property(tokenData, 'documentUri')
assert.property(tokenData, 'documentHash')
assert.property(tokenData, 'decimals')
assert.property(tokenData, 'mintBatonIsActive')
assert.property(tokenData, 'tokensInCirculationBN')
assert.property(tokenData, 'tokensInCirculationStr')
assert.property(tokenData, 'blockCreated')
assert.property(tokenData, 'totalBurned')
assert.property(tokenData, 'totalMinted')
assert.property(tokenData, 'txs')
})
})
describe('#getTxid', async () => {
it('should throw 400 error if txid is missing', async () => {
const result = await uut.getTxid(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error', 'success'])
assert.isFalse(result.success)
assert.include(result.error, 'txid can not be empty')
})
it('should throw 400 error if txid is invalid format', async () => {
req.body.txid = 'txid'
const result = await uut.getTxid(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error', 'success'])
assert.isFalse(result.success)
assert.include(result.error, 'This is not a txid')
})
it('should throw 503 when network issues', async () => {
req.body.txid =
'f3e14cd871402a766e85045dc552f2c1e87857dd3ea1b15efab6334ccef5e315'
// Save the existing RPC URL.
const savedUrl2 = process.env.SLP_INDEXER_API
// Manipulate the URL to cause a 500 network error.
process.env.SLP_INDEXER_API = 'http://fakeurl/api/'
await uut.getTxid(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Restore the saved URL.
process.env.SLP_INDEXER_API = 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 () => {
req.body.txid =
'f3e14cd871402a766e85045dc552f2c1e87857dd3ea1b15efab6334ccef5e315'
// Mock the timeout error.
sandbox.stub(uut.axios, 'post').throws({ code: 'ECONNABORTED' })
const result = await uut.getTxid(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 () => {
req.body.txid =
'f3e14cd871402a766e85045dc552f2c1e87857dd3ea1b15efab6334ccef5e315'
// Mock the timeout error.
sandbox.stub(uut.axios, 'post').throws({ code: 'ECONNREFUSED' })
const result = await uut.getTxid(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 tx data', async function () {
req.body.txid =
'f3e14cd871402a766e85045dc552f2c1e87857dd3ea1b15efab6334ccef5e315'
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(uut.axios, 'post').resolves({ data: mockData.txData })
} else {
return this.skip()
}
const result = await uut.getTxid(req, res)
const txData = result.txData
assert.property(txData, 'txid')
assert.property(txData, 'hash')
assert.property(txData, 'version')
assert.property(txData, 'size')
assert.property(txData, 'locktime')
assert.property(txData, 'vin')
assert.property(txData, 'vout')
assert.property(txData, 'hex')
assert.property(txData, 'blockhash')
assert.property(txData, 'confirmations')
assert.property(txData, 'time')
assert.property(txData, 'blocktime')
assert.property(txData, 'blockheight')
assert.property(txData, 'isSlpTx')
assert.property(txData, 'tokenTxType')
assert.property(txData, 'tokenId')
assert.property(txData, 'tokenType')
assert.property(txData, 'tokenTicker')
assert.property(txData, 'tokenName')
assert.property(txData, 'tokenDecimals')
assert.property(txData, 'tokenUri')
assert.property(txData, 'tokenDocHash')
assert.property(txData, 'isValidSlp')
})
})
describe('#getAddress', async () => {
it('should throw 400 error if address is missing', async () => {
const result = await uut.getAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error', 'success'])
assert.isFalse(result.success)
assert.include(result.error, 'address can not be empty')
})
it('should throw 400 error if address is invalid format', async () => {
req.body.address = 'address'
const result = await uut.getAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error', 'success'])
assert.isFalse(result.success)
assert.include(
result.error,
'Invalid BCH address. Double check your address is valid'
)
})
it('should throw 400 error for invalid network address', async () => {
req.body.address = 'bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4'
const result = await uut.getAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error', 'success'])
assert.isFalse(result.success)
assert.include(
result.error,
'Invalid network. Trying to use a testnet address on mainnet, or vice versa.'
)
})
it('should throw 503 when network issues', async () => {
req.body.address =
'bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n'
// Save the existing RPC URL.
const savedUrl2 = process.env.SLP_INDEXER_API
// Manipulate the URL to cause a 500 network error.
process.env.SLP_INDEXER_API = 'http://fakeurl/api/'
await uut.getAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Restore the saved URL.
process.env.SLP_INDEXER_API = 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 () => {
req.body.address =
'bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n'
// Mock the timeout error.
sandbox.stub(uut.axios, 'post').throws({ code: 'ECONNABORTED' })
const result = await uut.getAddress(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 () => {
req.body.address =
'bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n'
// Mock the timeout error.
sandbox.stub(uut.axios, 'post').throws({ code: 'ECONNREFUSED' })
const result = await uut.getAddress(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 address data', async function () {
req.body.address =
'bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n'
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(uut.axios, 'post').resolves({ data: mockData.balance })
} else {
return this.skip()
}
const result = await uut.getAddress(req, res)
const balance = result.balance
assert.property(balance, 'utxos')
assert.property(balance, 'txs')
assert.property(balance, 'balances')
assert.isArray(balance.utxos)
assert.isArray(balance.txs)
assert.isArray(balance.balances)
})
})
describe('#getStatus', async () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.SLP_INDEXER_API
// Manipulate the URL to cause a 500 network error.
process.env.SLP_INDEXER_API = 'http://fakeurl/api/'
await uut.getStatus(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Restore the saved URL.
process.env.SLP_INDEXER_API = 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, 'get').throws({ code: 'ECONNABORTED' })
const result = await uut.getStatus(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, 'get').throws({ code: 'ECONNREFUSED' })
const result = await uut.getStatus(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 indexer status', async function () {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(uut.axios, 'get').resolves({ data: mockData.status })
} else {
return this.skip()
}
const result = await uut.getStatus(req, res)
const status = result.status
assert.property(status, 'startBlockHeight')
assert.property(status, 'syncedBlockHeight')
assert.property(status, 'chainBlockHeight')
})
})
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.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.property(result, 'error')
})
it('should handle unknow errors', () => {
sandbox.stub(uut.routeUtils, 'decodeError').returns({ msg: false })
const result = uut.errorHandler({}, res)
// console.log('result: ', result)
assert.equal(res.statusCode, 500, 'HTTP status code 500 expected.')
assert.property(result, 'error')
})
})
describe('#checkEnvVar', () => {
it('should throw errors if SLP_INDEXER_API env var is not provided', () => {
const savedSlpIndexerUrl = process.env.SLP_INDEXER_API
try {
process.env.SLP_INDEXER_API = ''
uut.checkEnvVar()
assert.fail('unexpected code path')
} catch (error) {
assert.include(
error.message,
'SLP_INDEXER_API env var not set. Can not connect to PSF SLP indexer.',
'Error message expected'
)
}
process.env.SLP_INDEXER_API = savedSlpIndexerUrl
})
})
})
+4 -4
View File
@@ -216,7 +216,7 @@ describe('#Raw-Transactions', () => {
it('should throw 400 error if hexes array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.hexes = testArray
@@ -459,7 +459,7 @@ describe('#Raw-Transactions', () => {
it('should throw 400 error if hexes array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.hexes = testArray
@@ -599,7 +599,7 @@ describe('#Raw-Transactions', () => {
it('should throw 400 error if txids array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -885,7 +885,7 @@ describe('#Raw-Transactions', () => {
it('should throw 400 error if hexs array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.hexes = testArray
+311 -313
View File
@@ -36,7 +36,7 @@ if (process.env.TEST === 'unit') {
process.env.BITDB_URL = 'http://fakeurl/'
process.env.BITCOINCOM_BASEURL = 'http://fakeurl/'
process.env.SLPDB_URL = 'http://fakeurl/'
mockServerUrl = 'http://fakeurl'
// mockServerUrl = 'http://fakeurl'
}
// Prepare the slpRoute for stubbing dependcies on slpjs.
@@ -157,6 +157,7 @@ describe('#SLP', () => {
'Error message expected'
)
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(slpRoute.axios, 'request').throws({ code: 'ECONNABORTED' })
@@ -193,31 +194,31 @@ describe('#SLP', () => {
)
})
it('should get token balance for an address', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(slpRoute.axios, 'request').resolves({
data: mockData.mockSingleAddress
})
}
req.params.address =
'simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn'
const result = await balancesForAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.property(result[0], 'tokenId')
assert.property(result[0], 'balanceString')
assert.property(result[0], 'slpAddress')
assert.property(result[0], 'balance')
assert.property(result[0], 'decimalCount')
assert.isNumber(result[0].balance)
assert.isNumber(result[0].decimalCount)
})
// it('should get token balance for an address', async () => {
// // Mock the RPC call for unit tests.
// if (process.env.TEST === 'unit') {
// sandbox.stub(slpRoute.axios, 'request').resolves({
// data: mockData.mockSingleAddress
// })
// }
//
// req.params.address =
// 'simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn'
//
// const result = await balancesForAddress(req, res)
// // console.log(`result: ${util.inspect(result)}`)
//
// assert.isArray(result)
//
// assert.property(result[0], 'tokenId')
// assert.property(result[0], 'balanceString')
// assert.property(result[0], 'slpAddress')
// assert.property(result[0], 'balance')
// assert.property(result[0], 'decimalCount')
//
// assert.isNumber(result[0].balance)
// assert.isNumber(result[0].decimalCount)
// })
})
describe('balancesForAddressBulk()', () => {
@@ -281,6 +282,7 @@ describe('#SLP', () => {
'Error message expected'
)
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(slpRoute.axios, 'request').throws({ code: 'ECONNABORTED' })
@@ -316,27 +318,28 @@ describe('#SLP', () => {
'Error message expected'
)
})
// Only run as an integration test. Too complex to stub accurately.
if (process.env.TEST !== 'unit') {
it('should get token balance for an address', async () => {
req.body.addresses = [
'simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn'
]
const result = await balancesForAddressBulk(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0])
assert.hasAnyKeys(result[0][0], [
'tokenId',
'balance',
'balanceString',
'slpAddress',
'decimalCount'
])
})
}
// if (process.env.TEST !== 'unit') {
// it('should get token balance for an address', async () => {
// req.body.addresses = [
// 'simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn'
// ]
//
// const result = await balancesForAddressBulk(req, res)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.isArray(result)
// assert.isArray(result[0])
// assert.hasAnyKeys(result[0][0], [
// 'tokenId',
// 'balance',
// 'balanceString',
// 'slpAddress',
// 'decimalCount'
// ])
// })
// }
})
describe('#validate2Single', () => {
@@ -349,6 +352,7 @@ describe('#SLP', () => {
assert.include(result.error, 'txid can not be empty')
})
/*
it('should invalidate a known invalid TXID', async () => {
if (process.env.TEST === 'unit') {
// Mock to prevent live network connection.
@@ -367,7 +371,8 @@ describe('#SLP', () => {
assert.equal(result.txid, txid)
assert.equal(result.isValid, false)
})
*/
/*
it('should validate a known valid TXID', async () => {
if (process.env.TEST === 'unit') {
// Mock to prevent live network connection.
@@ -386,7 +391,7 @@ describe('#SLP', () => {
assert.equal(result.txid, txid)
assert.equal(result.isValid, true)
})
*/
// This test can only be run as a mocked unit test. It's too inconsistent
// to run as an integration test, due to the caching built into slp-validate.
if (process.env.TEST === 'unit') {
@@ -445,24 +450,24 @@ describe('#SLP', () => {
assert.equal(result.valid, null)
})
it('should validate a known valid TXID', async () => {
if (process.env.TEST === 'unit') {
// Mock to prevent live network connection.
sandbox
.stub(slpRoute.axios, 'request')
.resolves({ data: mockData.mockSingleValidTxid })
}
const txid =
'77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d'
req.params.txid = txid
const result = await slpRoute.validateSingle(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.txid, txid)
assert.equal(result.valid, true)
})
// it('should validate a known valid TXID', async () => {
// if (process.env.TEST === 'unit') {
// // Mock to prevent live network connection.
// sandbox
// .stub(slpRoute.axios, 'request')
// .resolves({ data: mockData.mockSingleValidTxid })
// }
//
// const txid =
// '77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d'
//
// req.params.txid = txid
// const result = await slpRoute.validateSingle(req, res)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.equal(result.txid, txid)
// assert.equal(result.valid, true)
// })
if (process.env.TEST === 'unit') {
it('should cancel if validation takes too long', async () => {
@@ -577,7 +582,7 @@ describe('#SLP', () => {
it('should throw 400 error if array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -624,153 +629,153 @@ describe('#SLP', () => {
)
})
it('should validate array with single element', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(slpRoute.axios, 'request').resolves({
data: mockData.mockSingleValidTxid
})
}
// it('should validate array with single element', async () => {
// // Mock the RPC call for unit tests.
// if (process.env.TEST === 'unit') {
// sandbox.stub(slpRoute.axios, 'request').resolves({
// data: mockData.mockSingleValidTxid
// })
// }
//
// req.body.txids = [
// '77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d'
// ]
//
// const result = await validateBulk(req, res)
// // console.log(`result: ${util.inspect(result)}`)
//
// assert.isArray(result)
// assert.hasAllKeys(result[0], ['txid', 'valid'])
// })
req.body.txids = [
'77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d'
]
const result = await validateBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAllKeys(result[0], ['txid', 'valid'])
})
it('should validate array with two elements', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(slpRoute.axios, 'request').resolves({
data: mockData.mockTwoValidTxid
})
}
req.body.txids = [
'77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d',
'552112f9e458dc7d1d8b328b0a6685e8af74a64b60b6846e7c86407f27f47e42'
]
const result = await validateBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAllKeys(result[0], ['txid', 'valid'])
assert.equal(result.length, 2)
})
// it('should validate array with two elements', async () => {
// // Mock the RPC call for unit tests.
// if (process.env.TEST === 'unit') {
// sandbox.stub(slpRoute.axios, 'request').resolves({
// data: mockData.mockTwoValidTxid
// })
// }
//
// req.body.txids = [
// '77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d',
// '552112f9e458dc7d1d8b328b0a6685e8af74a64b60b6846e7c86407f27f47e42'
// ]
//
// const result = await validateBulk(req, res)
// // console.log(`result: ${util.inspect(result)}`)
//
// assert.isArray(result)
// assert.hasAllKeys(result[0], ['txid', 'valid'])
// assert.equal(result.length, 2)
// })
// Captures a regression bug that went out to production, captured in this
// GitHub Issue: https://github.com/Bitcoin-com/rest.bitcoin.com/issues/518
it('should return two elements if given two elements', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(slpRoute.axios, 'request').resolves({
data: mockData.mockTwoRedundentTxid
})
}
// it('should return two elements if given two elements', async () => {
// // Mock the RPC call for unit tests.
// if (process.env.TEST === 'unit') {
// sandbox.stub(slpRoute.axios, 'request').resolves({
// data: mockData.mockTwoRedundentTxid
// })
// }
//
// req.body.txids = [
// 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
// 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56'
// ]
//
// const result = await validateBulk(req, res)
// // console.log(`result: ${util.inspect(result)}`)
//
// assert.isArray(result)
// assert.hasAllKeys(result[0], ['txid', 'valid'])
// assert.equal(result.length, 2)
// })
req.body.txids = [
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56'
]
const result = await validateBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAllKeys(result[0], ['txid', 'valid'])
assert.equal(result.length, 2)
})
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(slpRoute.axios, 'request').resolves({
data: mockData.mockValidateBulk
})
}
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 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, true)
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'
)
}
})
// it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
// // Mock the RPC call for unit tests.
// if (process.env.TEST === 'unit') {
// sandbox.stub(slpRoute.axios, 'request').resolves({
// data: mockData.mockValidateBulk
// })
// }
//
// 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 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, true)
//
// 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', () => {
@@ -787,7 +792,7 @@ describe('#SLP', () => {
it('should throw 400 error if array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
@@ -1054,27 +1059,28 @@ describe('#SLP', () => {
'Error message expected'
)
})
it('should get balances for tokenId', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === 'unit') {
sandbox.stub(slpRoute.axios, 'request').resolves({
data: {
g: [mockData.mockBalance]
}
})
}
req.params.tokenId =
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
const result = await balancesForTokenSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.property(result[0], 'tokenId')
assert.property(result[0], 'slpAddress')
assert.property(result[0], 'tokenBalanceString')
})
// it('should get balances for tokenId', async () => {
// // Mock the RPC call for unit tests.
// if (process.env.TEST === 'unit') {
// sandbox.stub(slpRoute.axios, 'request').resolves({
// data: {
// g: [mockData.mockBalance]
// }
// })
// }
//
// req.params.tokenId =
// '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
//
// const result = await balancesForTokenSingle(req, res)
// // console.log(`result: ${util.inspect(result)}`)
//
// assert.isArray(result)
// assert.property(result[0], 'tokenId')
// assert.property(result[0], 'slpAddress')
// assert.property(result[0], 'tokenBalanceString')
// })
})
describe('txDetails()', () => {
@@ -1099,19 +1105,20 @@ describe('#SLP', () => {
assert.include(result.error, 'This is not a txid')
})
it('should throw 400 for non-existant txid', async () => {
// Integration test
if (process.env.TEST !== 'unit') {
req.params.txid =
'57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b94578223333'
// it('should throw 400 for non-existant txid', async () => {
// // Integration test
// if (process.env.TEST !== 'unit') {
// req.params.txid =
// '57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b94578223333'
//
// const result = await txDetails(req, res)
// // console.log(`result: ${util.inspect(result)}`)
//
// assert.hasAllKeys(result, ['error'])
// assert.include(result.error, 'TXID not found')
// }
// })
const result = await txDetails(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'TXID not found')
}
})
it('returns proper error when downstream service stalls', async () => {
// Mock the timeout error.
sandbox.stub(slpRoute.axios, 'request').throws({ code: 'ECONNABORTED' })
@@ -1146,26 +1153,27 @@ describe('#SLP', () => {
'Error message expected'
)
})
if (process.env.TEST === 'integration') {
it('should get tx details with token info', async () => {
// TODO: add mocking for unit testing. How do I mock reponse form SLPDB
// since it's not an object?
// if (process.env.TEST === "unit") {
// // Mock the slpjs library for unit tests.
// pathStub.BitboxNetwork = slpjsMock.BitboxNetwork
// txDetails = slpRouteStub.testableComponents.txDetails
// }
req.params.txid =
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
const result = await txDetails(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, ['tokenIsValid', 'tokenInfo'])
})
}
// if (process.env.TEST === 'integration') {
// it('should get tx details with token info', async () => {
// // TODO: add mocking for unit testing. How do I mock reponse form SLPDB
// // since it's not an object?
//
// // if (process.env.TEST === "unit") {
// // // Mock the slpjs library for unit tests.
// // pathStub.BitboxNetwork = slpjsMock.BitboxNetwork
// // txDetails = slpRouteStub.testableComponents.txDetails
// // }
//
// req.params.txid =
// '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
//
// const result = await txDetails(req, res)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.hasAnyKeys(result, ['tokenIsValid', 'tokenInfo'])
// })
// }
})
describe('txsTokenIdAddressSingle()', () => {
@@ -1269,22 +1277,22 @@ describe('#SLP', () => {
assert.include(result.error, 'Invalid')
})
it('should get tx history', async () => {
if (process.env.TEST === 'unit') {
sandbox
.stub(slpRoute.slpdb, 'getHistoricalSlpTransactions')
.resolves(mockData.mockTxHistory)
}
// req.params.address = 'simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk'
req.params.address =
'simpleledger:qz4guf2k3p4r3t4tph0wwgyfq4p628lr2c0cvqplza'
const result = await slpRoute.txsByAddressSingle(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
})
// it('should get tx history', async () => {
// if (process.env.TEST === 'unit') {
// sandbox
// .stub(slpRoute.slpdb, 'getHistoricalSlpTransactions')
// .resolves(mockData.mockTxHistory)
// }
//
// // req.params.address = 'simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk'
// req.params.address =
// 'simpleledger:qz4guf2k3p4r3t4tph0wwgyfq4p628lr2c0cvqplza'
//
// const result = await slpRoute.txsByAddressSingle(req, res)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.isArray(result)
// })
})
describe('#generateSendOpReturn()', () => {
@@ -1406,8 +1414,7 @@ describe('#SLP', () => {
it('should throw error if Array is too long', async () => {
const utxo = {
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
txid: 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 3,
amount: 0.00002015,
satoshis: 2015,
@@ -1435,8 +1442,7 @@ describe('#SLP', () => {
{
utxos: [
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
@@ -1444,8 +1450,7 @@ describe('#SLP', () => {
satoshis: 6816
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
@@ -1459,8 +1464,7 @@ describe('#SLP', () => {
// Mock the external network call.
sandbox.stub(slpRoute.bchjs.SLP.Utils, 'tokenUtxoDetails').resolves([
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
@@ -1469,8 +1473,7 @@ describe('#SLP', () => {
isValid: false
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
@@ -1581,8 +1584,7 @@ describe('#SLP', () => {
it('should throw error if Array is too long', async () => {
const utxo = {
txid:
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
txid: 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 3,
amount: 0.00002015,
satoshis: 2015,
@@ -1610,8 +1612,7 @@ describe('#SLP', () => {
{
utxos: [
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
@@ -1619,8 +1620,7 @@ describe('#SLP', () => {
satoshis: 6816
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
@@ -1634,8 +1634,7 @@ describe('#SLP', () => {
// Mock the external network call.
sandbox.stub(slpRoute.bchjs.SLP.Utils, 'tokenUtxoDetailsWL').resolves([
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
@@ -1644,8 +1643,7 @@ describe('#SLP', () => {
isValid: false
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
txid: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
@@ -1947,22 +1945,22 @@ describe('#SLP', () => {
)
})
it('should return error on non-existing NFT child token', async () => {
if (process.env.TEST === 'unit') {
sandbox.stub(slpRoute, 'lookupToken').resolves({ id: 'not found' })
}
req.params.tokenId =
'45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a8'
const result = await slpRoute.getNftGroup(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.include(
result.error,
'NFT child does not exists',
'Error message expected'
)
})
// it('should return error on non-existing NFT child token', async () => {
// if (process.env.TEST === 'unit') {
// sandbox.stub(slpRoute, 'lookupToken').resolves({ id: 'not found' })
// }
//
// req.params.tokenId =
// '45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a8'
//
// const result = await slpRoute.getNftGroup(req, res)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
// assert.include(
// result.error,
// 'NFT child does not exists',
// 'Error message expected'
// )
// })
it('should return error on invalid NFT child token', async () => {
if (process.env.TEST === 'unit') {
+1 -1
View File
@@ -203,7 +203,7 @@ describe('#Util', () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push('')
for (let i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray