fix(linting): Switching to standard linter. Fixed linting errors

This commit is contained in:
Chris Troutner
2020-02-16 06:38:25 -08:00
parent 7a6a033eb9
commit bb1bac5ada
48 changed files with 4547 additions and 3702 deletions
+6 -50
View File
@@ -1,54 +1,10 @@
{
"root": true,
"parserOptions": {
"ecmaVersion": 2018
"extends": "standard",
"env": {
"node": true,
"mocha": true
},
"plugins": ["prettier"],
"rules": {
"no-debugger": ["warn"],
"no-regex-spaces": ["error"],
"no-unsafe-negation": ["error"],
"curly": ["error", "multi-or-nest", "consistent"],
"dot-location": ["error", "property"],
"dot-notation": ["error"],
"eqeqeq": ["error", "smart"],
"no-else-return": ["error"],
"no-extra-bind": ["error"],
"no-extra-label": ["error"],
"no-floating-decimal": ["error"],
"no-implicit-coercion": ["error", { "allow": ["!!"] }],
"no-lonely-if": ["off"],
"wrap-iife": ["error", "inside"],
"strict": ["error", "global"],
"func-call-spacing": ["error", "never"],
"comma-style": ["error", "last"],
"keyword-spacing": ["error"],
"linebreak-style": ["error", "unix"],
"new-parens": ["error"],
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],
"no-whitespace-before-property": ["error"],
"semi": ["error", "never"],
"arrow-body-style": ["error", "as-needed"],
"arrow-parens": ["error", "as-needed"],
"arrow-spacing": ["error"],
"no-useless-computed-key": ["error"],
"no-useless-rename": ["error"],
"no-var": ["off"],
"prefer-spread": ["error"],
"prefer-template": ["error"],
"rest-spread-spacing": ["error", "never"],
"prefer-const": ["warn", { "destructuring": "all" }],
"no-unreachable": ["warn"],
"no-unused-vars": ["off"],
"prettier/prettier": [
"warn",
{
"printWidth": 80,
"trailingComma": "none",
"singleQuote": false,
"semi": false
}
]
"parserOptions": {
"ecmaVersion": 10
}
}
+1144 -264
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -11,6 +11,7 @@
"start": "node ./src/app.js",
"dev": "nodemon ./dist/app.js",
"test": "npm run test-v3",
"lint": "standard --env mocha --fix",
"test-v3": "export NETWORK=mainnet && nyc --reporter=text mocha --timeout 25000 test/v3/",
"test:temp": "export NETWORK=mainnet && mocha --timeout 25000 test/v3/blockchain.js",
"test:integration": "mocha test/v3/integration",
@@ -48,7 +49,6 @@
"pg": "^7.11.0",
"pg-hstore": "^2.3.2",
"rate-limiter-flexible": "^2.0.0",
"strftime": "^0.10.0",
"winston": "^3.2.1",
"winston-daily-rotate-file": "^4.0.0"
},
@@ -69,8 +69,9 @@
"proxyquire": "^2.1.0",
"request": "^2.88.0",
"request-promise": "^4.2.2",
"sinon": "^8.0.0",
"semantic-release": "^17.0.0",
"sinon": "^8.0.0",
"standard": "^14.3.1",
"typescript": "^3.1.4"
},
"release": {
+57 -56
View File
@@ -1,41 +1,41 @@
"use strict"
'use strict'
const express = require("express")
const express = require('express')
// Middleware
// const { routeRateLimit } = require("./middleware/route-ratelimit")
const RateLimits = require("./middleware/route-ratelimit")
const RateLimits = require('./middleware/route-ratelimit')
const rateLimits = new RateLimits()
const path = require("path")
const logger = require("morgan")
const wlogger = require("./util/winston-logging")
const cookieParser = require("cookie-parser")
const bodyParser = require("body-parser")
const basicAuth = require("express-basic-auth")
const helmet = require("helmet")
const debug = require("debug")("rest-cloud:server")
const http = require("http")
const cors = require("cors")
const path = require('path')
const logger = require('morgan')
const wlogger = require('./util/winston-logging')
const cookieParser = require('cookie-parser')
const bodyParser = require('body-parser')
// const basicAuth = require("express-basic-auth")
const helmet = require('helmet')
const debug = require('debug')('rest-cloud:server')
const http = require('http')
const cors = require('cors')
// Auth and rate limiting middleware libraries.
const AuthMW = require("./middleware/auth")
const jwtAuth = require("./middleware/jwt-auth")
const AuthMW = require('./middleware/auth')
const jwtAuth = require('./middleware/jwt-auth')
// v3
const healthCheckV3 = require("./routes/v3/health-check")
const BlockchainV3 = require("./routes/v3/full-node/blockchain")
const controlV3 = require("./routes/v3/full-node/control")
const miningV3 = require("./routes/v3/full-node/mining")
const networkV3 = require("./routes/v3/full-node/network")
const rawtransactionsV3 = require("./routes/v3/full-node/rawtransactions")
const utilV3 = require("./routes/v3/util")
const slpV3 = require("./routes/v3/slp")
const xpubV3 = require("./routes/v3/xpub")
const blockbookV3 = require("./routes/v3/blockbook")
const Ninsight = require("./routes/v3/ninsight")
const healthCheckV3 = require('./routes/v3/health-check')
const BlockchainV3 = require('./routes/v3/full-node/blockchain')
const controlV3 = require('./routes/v3/full-node/control')
const miningV3 = require('./routes/v3/full-node/mining')
const networkV3 = require('./routes/v3/full-node/network')
const rawtransactionsV3 = require('./routes/v3/full-node/rawtransactions')
const utilV3 = require('./routes/v3/util')
const slpV3 = require('./routes/v3/slp')
const xpubV3 = require('./routes/v3/xpub')
const blockbookV3 = require('./routes/v3/blockbook')
const Ninsight = require('./routes/v3/ninsight')
require("dotenv").config()
require('dotenv').config()
// Instantiate route libraries.
const blockchainV3 = new BlockchainV3()
@@ -49,18 +49,19 @@ app.locals.env = process.env
app.use(helmet())
app.use(cors())
app.enable("trust proxy")
app.enable('trust proxy')
// view engine setup
app.set("views", path.join(__dirname, "views"))
app.set("view engine", "jade")
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}/../docs`))
// Log each request to the console with IP addresses.
// app.use(logger("dev"))
const morganFormat = `:remote-addr :remote-user :method :url :status :response-time ms - :res[content-length] :user-agent`
const morganFormat =
':remote-addr :remote-user :method :url :status :response-time ms - :res[content-length] :user-agent'
app.use(logger(morganFormat))
// Log the same data to the winston logs.
@@ -74,10 +75,10 @@ app.use(logger(morganFormat, { stream: logStream }))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.static(path.join(__dirname, "public")))
app.use(express.static(path.join(__dirname, 'public')))
// const v2prefix = "v2"
const v3prefix = "v3"
const v3prefix = 'v3'
// Inspect the header for a JWT token.
app.use(`/${v3prefix}/`, jwtAuth.getTokenFromHeaders)
@@ -92,24 +93,24 @@ app.use(`/${v3prefix}/`, auth.mw())
// app.use(`/${v3prefix}/`, rateLimits.routeRateLimit)
app.use(`/${v3prefix}/`, rateLimits.rateLimitByResource)
app.use(`/${v3prefix}/` + `health-check`, healthCheckV3)
app.use(`/${v3prefix}/` + `blockchain`, blockchainV3.router)
app.use(`/${v3prefix}/` + `control`, controlV3.router)
app.use(`/${v3prefix}/` + `mining`, miningV3.router)
app.use(`/${v3prefix}/` + `network`, networkV3)
app.use(`/${v3prefix}/` + `rawtransactions`, rawtransactionsV3.router)
app.use(`/${v3prefix}/` + `util`, utilV3.router)
app.use(`/${v3prefix}/` + `slp`, slpV3.router)
app.use(`/${v3prefix}/` + `xpub`, xpubV3.router)
app.use(`/${v3prefix}/` + `blockbook`, blockbookV3.router)
app.use(`/${v3prefix}/` + 'health-check', healthCheckV3)
app.use(`/${v3prefix}/` + 'blockchain', blockchainV3.router)
app.use(`/${v3prefix}/` + 'control', controlV3.router)
app.use(`/${v3prefix}/` + 'mining', miningV3.router)
app.use(`/${v3prefix}/` + 'network', networkV3)
app.use(`/${v3prefix}/` + 'rawtransactions', rawtransactionsV3.router)
app.use(`/${v3prefix}/` + 'util', utilV3.router)
app.use(`/${v3prefix}/` + 'slp', slpV3.router)
app.use(`/${v3prefix}/` + 'xpub', xpubV3.router)
app.use(`/${v3prefix}/` + 'blockbook', blockbookV3.router)
const ninsight = new Ninsight()
app.use(`/${v3prefix}/` + `ninsight`, ninsight.router)
app.use(`/${v3prefix}/` + 'ninsight', ninsight.router)
// catch 404 and forward to error handler
app.use((req, res, next) => {
const err = {
message: "Not Found",
message: 'Not Found',
status: 404
}
@@ -122,7 +123,7 @@ app.use((err, req, res, next) => {
// set locals, only providing error in development
res.locals.message = err.message
res.locals.error = req.app.get("env") === "development" ? err : {}
res.locals.error = req.app.get('env') === 'development' ? err : {}
// render the error page
res.status(status)
@@ -135,8 +136,8 @@ app.use((err, req, res, next) => {
/**
* Get port from environment and store in Express.
*/
const port = normalizePort(process.env.PORT || "3000")
app.set("port", port)
const port = normalizePort(process.env.PORT || '3000')
app.set('port', port)
console.log(`bch-api started on port ${port}`)
/**
@@ -149,8 +150,8 @@ const server = http.createServer(app)
*/
server.listen(port)
server.on("error", onError)
server.on("listening", onListening)
server.on('error', onError)
server.on('listening', onListening)
// Set the time before a timeout error is generated. This impacts testing and
// the handling of timeout errors. Is 10 seconds too agressive?
@@ -180,17 +181,17 @@ function normalizePort(val) {
* Event listener for HTTP server "error" event.
*/
function onError (error) {
if (error.syscall !== "listen") throw error
if (error.syscall !== 'listen') throw error
const bind = typeof port === "string" ? `Pipe ${port}` : `Port ${port}`
const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`
// handle specific listen errors with friendly messages
switch (error.code) {
case "EACCES":
case 'EACCES':
console.error(`${bind} requires elevated privileges`)
process.exit(1)
break
case "EADDRINUSE":
case 'EADDRINUSE':
console.error(`${bind} is already in use`)
process.exit(1)
break
@@ -205,7 +206,7 @@ function onError(error) {
function onListening () {
const addr = server.address()
const bind = typeof addr === "string" ? `pipe ${addr}` : `port ${addr.port}`
const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`
debug(`Listening on ${bind}`)
}
//
+12 -12
View File
@@ -19,30 +19,30 @@
is set and passed to the route-ratelimits.ts middleware.
*/
"use strict"
'use strict'
const passport = require("passport")
const BasicStrategy = require("passport-http").BasicStrategy
const AnonymousStrategy = require("passport-anonymous")
const wlogger = require("../util/winston-logging")
const passport = require('passport')
const BasicStrategy = require('passport-http').BasicStrategy
const AnonymousStrategy = require('passport-anonymous')
const wlogger = require('../util/winston-logging')
// Used for debugging and iterrogating JS objects.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
let _this
// let _this
// Set default rate limit value for testing
const PRO_PASSes = process.env.PRO_PASS ? process.env.PRO_PASS : "BITBOX"
const PRO_PASSES = process.env.PRO_PASS ? process.env.PRO_PASS : 'BITBOX'
// Convert the pro-tier password string into an array split by ':'.
const PRO_PASS = PRO_PASSes.split(":")
const PRO_PASS = PRO_PASSES.split(':')
// wlogger.verbose(`PRO_PASS set to: ${PRO_PASS}`)
// Auth Middleware
class AuthMW {
constructor () {
_this = this
// _this = this
// Initialize passport for 'anonymous' authentication.
passport.use(new AnonymousStrategy())
@@ -73,7 +73,7 @@ class AuthMW {
// Evaluate the username and password and set the rate limit accordingly.
// if (username === "BITBOX" && password === PRO_PASS) {
if (username === "BITBOX") {
if (username === 'BITBOX') {
for (let i = 0; i < PRO_PASS.length; i++) {
const thisPass = PRO_PASS[i]
@@ -96,7 +96,7 @@ class AuthMW {
// Middleware called by the route.
mw () {
return passport.authenticate(["basic", "anonymous"], {
return passport.authenticate(['basic', 'anonymous'], {
session: false
})
}
+4 -4
View File
@@ -5,7 +5,7 @@
If found, will populate req.locals.jwtToken with the JWT token.
*/
"use strict"
'use strict'
// This function searches the header for the a JWT token in the authorization header.
// If one is found, this middleware passes the JWT token through the
@@ -18,8 +18,8 @@ const getTokenFromHeaders = (req, res, next) => {
const authStr = req.headers.authorization
// If the header is proceeded by the word 'Token'
if (authStr.split(" ")[0] === "Token") {
const token = authStr.split(" ")[1]
if (authStr.split(' ')[0] === 'Token') {
const token = authStr.split(' ')[1]
// console.log(`JWT found: ${token}`)
@@ -36,7 +36,7 @@ const getTokenFromHeaders = (req, res, next) => {
}
}
} catch (err) {
console.log(`Error in getTokenFromHeaders: `, err)
console.log('Error in getTokenFromHeaders: ', err)
}
next()
+41 -44
View File
@@ -1,28 +1,28 @@
"use strict"
'use strict'
const express = require("express")
const RateLimit = require("express-rate-limit")
const axios = require("axios")
// const express = require('express')
const RateLimit = require('express-rate-limit')
const axios = require('axios')
const wlogger = require("../util/winston-logging")
const wlogger = require('../util/winston-logging')
const jwt = require("jsonwebtoken")
const KeyEncoder = require("key-encoder").default
const keyEncoder = new KeyEncoder("secp256k1")
const jwt = require('jsonwebtoken')
const KeyEncoder = require('key-encoder').default
const keyEncoder = new KeyEncoder('secp256k1')
// Redis
const redisOptions = {
enableOfflineQueue: false,
port: process.env.REDIS_PORT ? process.env.REDIS_PORT : 6379,
host: process.env.REDIS_HOST ? process.env.REDIS_HOST : "127.0.0.1"
host: process.env.REDIS_HOST ? process.env.REDIS_HOST : '127.0.0.1'
}
console.log(`redisOptions: ${JSON.stringify(redisOptions, null, 2)}`)
const Redis = require("ioredis")
const Redis = require('ioredis')
const redisClient = new Redis(redisOptions)
// Rate limiter middleware lib.
const { RateLimiterRedis } = require("rate-limiter-flexible")
const { RateLimiterRedis } = require('rate-limiter-flexible')
const rateLimitOptions = {
storeClient: redisClient,
points: 100, // Number of points
@@ -32,7 +32,7 @@ const rateLimitOptions = {
// This hard-coded value is temporary. It will be swapped out with an environment
// variable when moved to production.
const publicKey =
"03e6c358092a459f7da9420de770eef3e16cf3c9c54a3d3d14ac2d7f0b82af4d7d"
'03e6c358092a459f7da9420de770eef3e16cf3c9c54a3d3d14ac2d7f0b82af4d7d'
// Set max requests per minute
const maxRequests = process.env.RATE_LIMIT_MAX_REQUESTS
@@ -87,7 +87,7 @@ class RateLimits {
if (!req.locals) {
req.locals = {
// default values
jwtToken: "",
jwtToken: '',
proLimit: false,
apiLevel: 0
}
@@ -95,9 +95,9 @@ class RateLimits {
// Warn if JWT_AUTH_SERVER env var is not set.
const authServer = process.env.JWT_AUTH_SERVER
if (!authServer || authServer === "") {
if (!authServer || authServer === '') {
console.warn(
"JWT_AUTH_SERVER env var is not set. JWT tokens not being evaluated."
'JWT_AUTH_SERVER env var is not set. JWT tokens not being evaluated.'
)
} else {
// If a JWT token is passed in, validate it and enable pro-tier rate limits
@@ -129,7 +129,7 @@ class RateLimits {
}
// Current route
const rateLimitTier = req.locals.proLimit ? "PRO" : "BASIC"
const rateLimitTier = req.locals.proLimit ? 'PRO' : 'BASIC'
const path = req.baseUrl + req.path
// Create a unique string as a route identifier.
@@ -138,9 +138,9 @@ class RateLimits {
req.method +
req.locals.apiLevel + // Generates new rate limit when user upgrades JWT token.
path
.split("/")
.split('/')
.slice(0, 4)
.join("/")
.join('/')
// console.log(`route identifier: ${JSON.stringify(route, null, 2)}`)
// console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
@@ -224,9 +224,9 @@ class RateLimits {
// if apiLevel = 0 (free tier), then return the default values.
if (retObj.apiLevel === 0) return retObj
const level20Routes = ["insight", "bitcore", "blockbook"]
const level20Routes = ['insight', 'bitcore', 'blockbook']
const locals = req.locals
// const locals = req.locals
// console.log(`locals: ${JSON.stringify(locals, null, 2)}`)
const url = req.url
// console.log(`url: ${JSON.stringify(url, null, 2)}`)
@@ -258,7 +258,7 @@ class RateLimits {
if (!req.locals) {
req.locals = {
// default values
jwtToken: "",
jwtToken: '',
proLimit: false,
apiLevel: 0
}
@@ -267,10 +267,10 @@ class RateLimits {
// Decode the JWT token if one exists.
if (req.locals.jwtToken) {
const jwtOptions = {
algorithms: ["ES256"]
algorithms: ['ES256']
}
const pemPublicKey = keyEncoder.encodePublic(publicKey, "raw", "pem")
const pemPublicKey = keyEncoder.encodePublic(publicKey, 'raw', 'pem')
// Validate the JWT token.
decoded = _this.jwt.verify(
@@ -282,7 +282,7 @@ class RateLimits {
userId = decoded.id
} else {
wlogger.debug(`No JWT token found!`)
wlogger.debug('No JWT token found!')
}
// Code here for the rate limiter is adapted from this example:
@@ -292,7 +292,7 @@ class RateLimits {
const resource = _this.getResource(req.url)
wlogger.debug(`resource: ${resource}`)
let key = userId ? userId : req.ip
let key = userId || req.ip
// const pointsToConsume = userId ? 1 : 30
decoded.resource = resource
@@ -316,7 +316,7 @@ class RateLimits {
})
}
} catch (err) {
wlogger.error(`Error in route-ratelimit.js/newRateLimit(): `, err)
wlogger.error('Error in route-ratelimit.js/newRateLimit(): ', err)
// throw err
}
@@ -334,8 +334,8 @@ class RateLimits {
const apiLevel = jwtInfo.apiLevel
const resource = jwtInfo.resource
const level30Routes = ["insight", "bitcore", "blockbook"]
const level40Routes = ["slp"]
const level30Routes = ['insight', 'bitcore', 'blockbook']
const level40Routes = ['slp']
wlogger.debug(`apiLevel: ${apiLevel}`)
@@ -346,28 +346,25 @@ class RateLimits {
if (apiLevel >= 40) retVal = 1
// else if (apiLevel >= 10) retVal = 10
else retVal = 10
}
// Normal indexer routes
else if (level30Routes.includes(resource)) {
} else if (level30Routes.includes(resource)) {
if (apiLevel >= 30) retVal = 1
else retVal = 10
}
// Full node tier
else if (apiLevel >= 20) {
} else if (apiLevel >= 20) {
retVal = 1
}
// Free tier, full node only.
else {
} else {
retVal = 10
}
}
return retVal
} catch (err) {
wlogger.error(`Error in route-ratelimit.js/calcPoints()`)
wlogger.error('Error in route-ratelimit.js/calcPoints()')
// throw err
retVal = 30
}
@@ -383,12 +380,12 @@ class RateLimits {
try {
wlogger.debug(`url: ${JSON.stringify(url, null, 2)}`)
const splitUrl = url.split("/")
const splitUrl = url.split('/')
const resource = splitUrl[1]
return resource
} catch (err) {
wlogger.error(`Error in getResource().`)
wlogger.error('Error in getResource().')
throw err
}
}
@@ -406,7 +403,7 @@ class RateLimits {
if (!req.locals) {
req.locals = {
// default values
jwtToken: "",
jwtToken: '',
proLimit: false,
rateLimit: 3
}
@@ -415,10 +412,10 @@ class RateLimits {
// Decode the JWT token if one exists.
if (req.locals.jwtToken) {
const jwtOptions = {
algorithms: ["ES256"]
algorithms: ['ES256']
}
const pemPublicKey = keyEncoder.encodePublic(publicKey, "raw", "pem")
const pemPublicKey = keyEncoder.encodePublic(publicKey, 'raw', 'pem')
// Validate the JWT token.
decoded = _this.jwt.verify(
@@ -430,14 +427,14 @@ class RateLimits {
userId = decoded.id
} else {
wlogger.debug(`No JWT token found!`)
wlogger.debug('No JWT token found!')
}
// Code here for the rate limiter is adapted from this example:
// https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#authorized-and-not-authorized-users
try {
// Key for Redis key/value pair.
const key = userId ? userId : req.ip
const key = userId || req.ip
const pointsToConsume = _this.calcPoints2(decoded)
@@ -454,7 +451,7 @@ class RateLimits {
})
}
} catch (err) {
wlogger.error(`Error in route-ratelimit.js/rateLimitSimple(): `, err)
wlogger.error('Error in route-ratelimit.js/rateLimitSimple(): ', err)
// throw err
}
@@ -480,7 +477,7 @@ class RateLimits {
retVal = points
}
} catch (err) {
wlogger.error(`Error in route-ratelimit.js/calcPoints2()`)
wlogger.error('Error in route-ratelimit.js/calcPoints2()')
// throw err
retVal = 30
}
+58 -54
View File
@@ -2,42 +2,42 @@
Blockbook API route
*/
"use strict"
'use strict'
const express = require("express")
const axios = require("axios")
const routeUtils = require("./route-utils")
const wlogger = require("../../util/winston-logging")
const express = require('express')
const axios = require('axios')
const routeUtils = require('./route-utils')
const wlogger = require('../../util/winston-logging')
// Library for easily switching the API paths to use different instances of
// Blockbook.
const BlockbookPath = require("../../util/blockbook-path")
const BlockbookPath = require('../../util/blockbook-path')
const BLOCKBOOKPATH = new BlockbookPath()
// BLOCKBOOKPATH.toOpenBazaar()
const router = express.Router()
// Used for processing error messages before sending them to the user.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const BCHJS = require("@chris.troutner/bch-js")
const BCHJS = require('@chris.troutner/bch-js')
const bchjs = new BCHJS()
// const BLOCKBOOK_URL = process.env.BLOCKBOOK_URL
// Connect the route endpoints to their handler functions.
router.get("/", root)
router.get("/balance/:address", balanceSingle)
router.post("/balance", balanceBulk)
router.get("/utxos/:address", utxosSingle)
router.post("/utxos", utxosBulk)
router.get("/tx/:txid", txSingle)
router.post("/tx", txBulk)
router.get('/', root)
router.get('/balance/:address', balanceSingle)
router.post('/balance', balanceBulk)
router.get('/utxos/:address', utxosSingle)
router.post('/utxos', utxosBulk)
router.get('/tx/:txid', txSingle)
router.post('/tx', txBulk)
// Root API endpoint. Simply acknowledges that it exists.
function root (req, res, next) {
return res.json({ status: "address" })
return res.json({ status: 'address' })
}
// Query the Blockbook Node API for a balance on a single BCH address.
@@ -61,6 +61,7 @@ async function balanceFromBlockbook(thisAddress) {
} catch (err) {
// Dev Note: Do not log error messages here. Throw them instead and let the
// parent function handle it.
wlogger.debug('Error in blockbook.js/balanceFromBlockbook()')
throw err
}
}
@@ -81,27 +82,28 @@ async function balanceSingle(req, res, next) {
try {
const address = req.params.address
if (!address || address === "") {
if (!address || address === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
// Reject if address is an array.
if (Array.isArray(address)) {
res.status(400)
return res.json({
error: "address can not be an array. Use POST for bulk upload."
error: 'address can not be an array. Use POST for bulk upload.'
})
}
wlogger.debug(
`Executing blockbook/balanceSingle with this address: `,
'Executing blockbook/balanceSingle with this address: ',
address
)
// Ensure the input is a valid BCH address.
try {
const legacyAddr = bchjs.Address.toLegacyAddress(address)
// const legacyAddr = bchjs.Address.toLegacyAddress(address)
bchjs.Address.toLegacyAddress(address)
} catch (err) {
res.status(400)
return res.json({
@@ -114,7 +116,7 @@ async function balanceSingle(req, res, next) {
if (!networkIsValid) {
res.status(400)
return res.json({
error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
error: 'Invalid network. Trying to use a testnet address on mainnet, or vice versa.'
})
}
@@ -133,7 +135,7 @@ async function balanceSingle(req, res, next) {
}
// Write out error to error log.
wlogger.error(`Error in blockbook.js/balanceSingle().`, err)
wlogger.error('Error in blockbook.js/balanceSingle().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -156,13 +158,13 @@ async function balanceSingle(req, res, next) {
async function balanceBulk (req, res, next) {
try {
let addresses = req.body.addresses
const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
// const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
// Reject if addresses is not an array.
if (!Array.isArray(addresses)) {
res.status(400)
return res.json({
error: "addresses needs to be an array. Use GET for single address."
error: 'addresses needs to be an array. Use GET for single address.'
})
}
@@ -170,12 +172,12 @@ async function balanceBulk(req, res, next) {
if (!routeUtils.validateArraySize(req, addresses)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
wlogger.debug(
`Executing blockbook.js/balanceBulk with these addresses: `,
'Executing blockbook.js/balanceBulk with these addresses: ',
addresses
)
@@ -224,7 +226,7 @@ async function balanceBulk(req, res, next) {
return res.json({ error: msg })
}
wlogger.error(`Error in blockbook.js/balanceBulk().`, err)
wlogger.error('Error in blockbook.js/balanceBulk().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -249,13 +251,13 @@ async function utxosFromBlockbook(thisAddress) {
// console.log(`retData: ${util.inspect(retData)}`)
// Add the satoshis property to each UTXO.
for (let i = 0; i < retData.length; i++)
retData[i].satoshis = Number(retData[i].value)
for (let i = 0; i < retData.length; i++) { retData[i].satoshis = Number(retData[i].value) }
return retData
} catch (err) {
// Dev Note: Do not log error messages here. Throw them instead and let the
// parent function handle it.
wlogger.debug('Error in blockbook.js/utxosFromBlockbook()')
throw err
}
}
@@ -276,27 +278,28 @@ async function utxosSingle(req, res, next) {
try {
const address = req.params.address
if (!address || address === "") {
if (!address || address === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
// Reject if address is an array.
if (Array.isArray(address)) {
res.status(400)
return res.json({
error: "address can not be an array. Use POST for bulk upload."
error: 'address can not be an array. Use POST for bulk upload.'
})
}
wlogger.debug(
`Executing blockbook/utxosSingle with this address: `,
'Executing blockbook/utxosSingle with this address: ',
address
)
// Ensure the input is a valid BCH address.
try {
const legacyAddr = bchjs.Address.toLegacyAddress(address)
// const legacyAddr = bchjs.Address.toLegacyAddress(address)
bchjs.Address.toLegacyAddress(address)
} catch (err) {
res.status(400)
return res.json({
@@ -309,7 +312,7 @@ async function utxosSingle(req, res, next) {
if (!networkIsValid) {
res.status(400)
return res.json({
error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
error: 'Invalid network. Trying to use a testnet address on mainnet, or vice versa.'
})
}
@@ -328,7 +331,7 @@ async function utxosSingle(req, res, next) {
}
// Write out error to error log.
wlogger.error(`Error in blockbook.js/utxosSingle().`, err)
wlogger.error('Error in blockbook.js/utxosSingle().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -351,13 +354,13 @@ async function utxosSingle(req, res, next) {
async function utxosBulk (req, res, next) {
try {
let addresses = req.body.addresses
const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
// const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
// Reject if addresses is not an array.
if (!Array.isArray(addresses)) {
res.status(400)
return res.json({
error: "addresses needs to be an array. Use GET for single address."
error: 'addresses needs to be an array. Use GET for single address.'
})
}
@@ -365,12 +368,12 @@ async function utxosBulk(req, res, next) {
if (!routeUtils.validateArraySize(req, addresses)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
wlogger.debug(
`Executing blockbook.js/utxosBulk with these addresses: `,
'Executing blockbook.js/utxosBulk with these addresses: ',
addresses
)
@@ -419,7 +422,7 @@ async function utxosBulk(req, res, next) {
return res.json({ error: msg })
}
wlogger.error(`Error in blockbook.js/utxosBulk().`, err)
wlogger.error('Error in blockbook.js/utxosBulk().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -444,6 +447,7 @@ async function transactionsFromBlockbook(txid) {
} catch (err) {
// Dev Note: Do not log error messages here. Throw them instead and let the
// parent function handle it.
wlogger.debug('Error in blockbook.js/transactionsFromBlockbook()')
throw err
}
}
@@ -464,16 +468,16 @@ async function txSingle(req, res, next) {
try {
const txid = req.params.txid
if (!txid || txid === "") {
if (!txid || txid === '') {
res.status(400)
return res.json({ error: "txid can not be empty" })
return res.json({ error: 'txid can not be empty' })
}
// Reject if address is an array.
if (Array.isArray(txid)) {
res.status(400)
return res.json({
error: "txid can not be an array. Use POST for bulk upload."
error: 'txid can not be an array. Use POST for bulk upload.'
})
}
@@ -485,7 +489,7 @@ async function txSingle(req, res, next) {
})
}
wlogger.debug(`Executing blockbook/txSingle with this txid: `, txid)
wlogger.debug('Executing blockbook/txSingle with this txid: ', txid)
// Query the Blockbook Node API.
const retData = await transactionsFromBlockbook(txid)
@@ -502,7 +506,7 @@ async function txSingle(req, res, next) {
}
// Write out error to error log.
wlogger.error(`Error in blockbook.js/txSingle().`, err)
wlogger.error('Error in blockbook.js/txSingle().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -525,13 +529,13 @@ async function txSingle(req, res, next) {
async function txBulk (req, res, next) {
try {
let txids = req.body.txids
const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
// const currentPage = req.body.page ? parseInt(req.body.page, 10) : 0
// Reject if txids is not an array.
if (!Array.isArray(txids)) {
res.status(400)
return res.json({
error: "txids need to be an array. Use GET for single address."
error: 'txids need to be an array. Use GET for single address.'
})
}
@@ -539,19 +543,19 @@ async function txBulk(req, res, next) {
if (!routeUtils.validateArraySize(req, txids)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
wlogger.debug(`Executing blockbook.js/txBulk with these txids: `, txids)
wlogger.debug('Executing blockbook.js/txBulk with these txids: ', txids)
// Validate each element in the txids array.
for (let i = 0; i < txids.length; i++) {
const thisTxid = txids[i]
if (!thisTxid || thisTxid === "") {
if (!thisTxid || thisTxid === '') {
res.status(400)
return res.json({ error: "txid can not be empty" })
return res.json({ error: 'txid can not be empty' })
}
// TODO: Add regex comparison of txid to ensure it's valid.
@@ -584,7 +588,7 @@ async function txBulk(req, res, next) {
return res.json({ error: msg })
}
wlogger.error(`Error in blockbook.js/txBulk().`, err)
wlogger.error('Error in blockbook.js/txBulk().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
+117 -115
View File
@@ -2,22 +2,22 @@
A library for interacting with the Full Node
*/
"use strict"
'use strict'
const express = require("express")
const express = require('express')
const router = express.Router()
const axios = require("axios")
const wlogger = require("../../../util/winston-logging")
const axios = require('axios')
const wlogger = require('../../../util/winston-logging')
const RouteUtils = require("../route-utils2")
const RouteUtils = require('../route-utils2')
const routeUtils = new RouteUtils()
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const BCHJS = require("@chris.troutner/bch-js")
const BCHJS = require('@chris.troutner/bch-js')
const bchjs = new BCHJS()
let _this
@@ -31,31 +31,31 @@ class Blockchain {
this.routeUtils = routeUtils
this.router = router
this.router.get("/", this.root)
this.router.get("/getBestBlockHash", this.getBestBlockHash)
this.router.get("/getBlockchainInfo", this.getBlockchainInfo)
this.router.get("/getBlockCount", this.getBlockCount)
this.router.get("/getBlockHeader/:hash", this.getBlockHeaderSingle)
this.router.post("/getBlockHeader", this.getBlockHeaderBulk)
this.router.get("/getChainTips", this.getChainTips)
this.router.get("/getDifficulty", this.getDifficulty)
this.router.get("/getMempoolEntry/:txid", this.getMempoolEntrySingle)
this.router.post("/getMempoolEntry", this.getMempoolEntryBulk)
this.router.get('/', this.root)
this.router.get('/getBestBlockHash', this.getBestBlockHash)
this.router.get('/getBlockchainInfo', this.getBlockchainInfo)
this.router.get('/getBlockCount', this.getBlockCount)
this.router.get('/getBlockHeader/:hash', this.getBlockHeaderSingle)
this.router.post('/getBlockHeader', this.getBlockHeaderBulk)
this.router.get('/getChainTips', this.getChainTips)
this.router.get('/getDifficulty', this.getDifficulty)
this.router.get('/getMempoolEntry/:txid', this.getMempoolEntrySingle)
this.router.post('/getMempoolEntry', this.getMempoolEntryBulk)
this.router.get(
"/getMempoolAncestors/:txid",
'/getMempoolAncestors/:txid',
this.getMempoolAncestorsSingle
)
this.router.get("/getMempoolInfo", this.getMempoolInfo)
this.router.get("/getRawMempool", this.getRawMempool)
this.router.get("/getTxOut/:txid/:n", this.getTxOut)
this.router.get("/getTxOutProof/:txid", this.getTxOutProofSingle)
this.router.post("/getTxOutProof", this.getTxOutProofBulk)
this.router.get("/verifyTxOutProof/:proof", this.verifyTxOutProofSingle)
this.router.post("/verifyTxOutProof", this.verifyTxOutProofBulk)
this.router.get('/getMempoolInfo', this.getMempoolInfo)
this.router.get('/getRawMempool', this.getRawMempool)
this.router.get('/getTxOut/:txid/:n', this.getTxOut)
this.router.get('/getTxOutProof/:txid', this.getTxOutProofSingle)
this.router.post('/getTxOutProof', this.getTxOutProofBulk)
this.router.get('/verifyTxOutProof/:proof', this.verifyTxOutProofSingle)
this.router.post('/verifyTxOutProof', this.verifyTxOutProofBulk)
}
root (req, res, next) {
return res.json({ status: "blockchain" })
return res.json({ status: 'blockchain' })
}
// DRY error handler.
@@ -87,8 +87,8 @@ class Blockchain {
try {
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "getbestblockhash"
options.data.method = "getbestblockhash"
options.data.id = 'getbestblockhash'
options.data.method = 'getbestblockhash'
options.data.params = []
const response = await _this.axios.request(options)
@@ -97,7 +97,7 @@ class Blockchain {
return res.json(response.data.result)
} catch (err) {
// Write out error to error log.
wlogger.error("Error in blockchain.ts/getBestBlockHash().", err)
wlogger.error('Error in blockchain.ts/getBestBlockHash().', err)
return _this.errorHandler(err, res)
}
@@ -132,8 +132,8 @@ class Blockchain {
try {
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "getblockchaininfo"
options.data.method = "getblockchaininfo"
options.data.id = 'getblockchaininfo'
options.data.method = 'getblockchaininfo'
options.data.params = []
const response = await _this.axios.request(options)
@@ -141,7 +141,7 @@ class Blockchain {
return res.json(response.data.result)
} catch (err) {
// Write out error to error log.
wlogger.error("Error in blockchain.ts/getBlockchainInfo().", err)
wlogger.error('Error in blockchain.ts/getBlockchainInfo().', err)
return _this.errorHandler(err, res)
}
@@ -162,8 +162,8 @@ class Blockchain {
try {
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "getblockcount"
options.data.method = "getblockcount"
options.data.id = 'getblockcount'
options.data.method = 'getblockcount'
options.data.params = []
const response = await _this.axios.request(options)
@@ -172,7 +172,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getBlockCount().", err)
wlogger.error('Error in blockchain.ts/getBlockCount().', err)
return _this.errorHandler(err, res)
}
@@ -211,19 +211,20 @@ class Blockchain {
async getBlockHeaderSingle (req, res, next) {
try {
let verbose = false
if (req.query.verbose && req.query.verbose.toString() === "true")
if (req.query.verbose && req.query.verbose.toString() === 'true') {
verbose = true
}
const hash = req.params.hash
if (!hash || hash === "") {
if (!hash || hash === '') {
res.status(400)
return res.json({ error: "hash can not be empty" })
return res.json({ error: 'hash can not be empty' })
}
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "getblockheader"
options.data.method = "getblockheader"
options.data.id = 'getblockheader'
options.data.method = 'getblockheader'
options.data.params = [hash, verbose]
const response = await _this.axios.request(options)
@@ -232,7 +233,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getBlockHeaderSingle().", err)
wlogger.error('Error in blockchain.ts/getBlockHeaderSingle().', err)
return _this.errorHandler(err, res)
}
@@ -276,7 +277,7 @@ class Blockchain {
if (!Array.isArray(hashes)) {
res.status(400)
return res.json({
error: "hashes needs to be an array. Use GET for single hash."
error: 'hashes needs to be an array. Use GET for single hash.'
})
}
@@ -284,12 +285,12 @@ class Blockchain {
if (!routeUtils.validateArraySize(req, hashes)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: "Array too large."
error: 'Array too large.'
})
}
wlogger.debug(
"Executing blockchain/getBlockHeaderBulk with these hashes: ",
'Executing blockchain/getBlockHeaderBulk with these hashes: ',
hashes
)
@@ -308,11 +309,11 @@ class Blockchain {
// Loop through each hash and creates an array of requests to call in parallel
const promises = hashes.map(async hash => {
options.data.id = "getblockheader"
options.data.method = "getblockheader"
options.data.id = 'getblockheader'
options.data.method = 'getblockheader'
options.data.params = [hash, verbose]
return await _this.axios.request(options)
return _this.axios.request(options)
})
const axiosResult = await _this.axios.all(promises)
@@ -325,7 +326,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getBlockHeaderBulk().", err)
wlogger.error('Error in blockchain.ts/getBlockHeaderBulk().', err)
return _this.errorHandler(err, res)
}
@@ -347,8 +348,8 @@ class Blockchain {
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "getchaintips"
options.data.method = "getchaintips"
options.data.id = 'getchaintips'
options.data.method = 'getchaintips'
options.data.params = []
const response = await _this.axios.request(options)
@@ -356,7 +357,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getChainTips().", err)
wlogger.error('Error in blockchain.ts/getChainTips().', err)
return _this.errorHandler(err, res)
}
@@ -378,8 +379,8 @@ class Blockchain {
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "getdifficulty"
options.data.method = "getdifficulty"
options.data.id = 'getdifficulty'
options.data.method = 'getdifficulty'
options.data.params = []
const response = await _this.axios.request(options)
@@ -388,7 +389,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getDifficulty().", err)
wlogger.error('Error in blockchain.ts/getDifficulty().', err)
return _this.errorHandler(err, res)
}
@@ -409,16 +410,16 @@ class Blockchain {
try {
// Validate input parameter
const txid = req.params.txid
if (!txid || txid === "") {
if (!txid || txid === '') {
res.status(400)
return res.json({ error: "txid can not be empty" })
return res.json({ error: 'txid can not be empty' })
}
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "getmempoolentry"
options.data.method = "getmempoolentry"
options.data.id = 'getmempoolentry'
options.data.method = 'getmempoolentry'
options.data.params = [txid]
const response = await _this.axios.request(options)
@@ -427,7 +428,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getMempoolEntrySingle().", err)
wlogger.error('Error in blockchain.ts/getMempoolEntrySingle().', err)
return _this.errorHandler(err, res)
}
@@ -449,7 +450,7 @@ class Blockchain {
if (!Array.isArray(txids)) {
res.status(400)
return res.json({
error: "txids needs to be an array. Use GET for single txid."
error: 'txids needs to be an array. Use GET for single txid.'
})
}
@@ -457,12 +458,12 @@ class Blockchain {
if (!routeUtils.validateArraySize(req, txids)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: "Array too large."
error: 'Array too large.'
})
}
wlogger.debug(
"Executing blockchain/getMempoolEntry with these txids: ",
'Executing blockchain/getMempoolEntry with these txids: ',
txids
)
@@ -472,7 +473,7 @@ class Blockchain {
if (txid.length !== 64) {
res.status(400)
return res.json({ error: "This is not a txid" })
return res.json({ error: 'This is not a txid' })
}
}
@@ -481,11 +482,11 @@ class Blockchain {
// Loop through each txid and creates an array of requests to call in parallel
const promises = txids.map(async txid => {
options.data.id = "getmempoolentry"
options.data.method = "getmempoolentry"
options.data.id = 'getmempoolentry'
options.data.method = 'getmempoolentry'
options.data.params = [txid]
return await _this.axios.request(options)
return _this.axios.request(options)
})
const axiosResult = await _this.axios.all(promises)
@@ -498,7 +499,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getMempoolEntryBulk().", err)
wlogger.error('Error in blockchain.ts/getMempoolEntryBulk().', err)
return _this.errorHandler(err, res)
}
@@ -520,9 +521,9 @@ class Blockchain {
try {
// Validate input parameter
const txid = req.params.txid
if (!txid || txid === "") {
if (!txid || txid === '') {
res.status(400)
return res.json({ error: "txid can not be empty" })
return res.json({ error: 'txid can not be empty' })
}
let verbose = req.params.verbose
@@ -531,8 +532,8 @@ class Blockchain {
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "getmempoolancestors"
options.data.method = "getmempoolancestors"
options.data.id = 'getmempoolancestors'
options.data.method = 'getmempoolancestors'
options.data.params = [txid, verbose]
const response = await _this.axios.request(options)
@@ -542,7 +543,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getMempoolAncestorsSingle().", err)
wlogger.error('Error in blockchain.ts/getMempoolAncestorsSingle().', err)
return _this.errorHandler(err, res)
}
@@ -563,8 +564,8 @@ class Blockchain {
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "getmempoolinfo"
options.data.method = "getmempoolinfo"
options.data.id = 'getmempoolinfo'
options.data.method = 'getmempoolinfo'
options.data.params = []
const response = await _this.axios.request(options)
@@ -572,7 +573,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getMempoolInfo().", err)
wlogger.error('Error in blockchain.ts/getMempoolInfo().', err)
return _this.errorHandler(err, res)
}
@@ -608,10 +609,10 @@ class Blockchain {
const options = _this.routeUtils.getAxiosOptions()
let verbose = false
if (req.query.verbose && req.query.verbose === "true") verbose = true
if (req.query.verbose && req.query.verbose === 'true') verbose = true
options.data.id = "getrawmempool"
options.data.method = "getrawmempool"
options.data.id = 'getrawmempool'
options.data.method = 'getrawmempool'
options.data.params = [verbose]
const response = await _this.axios.request(options)
@@ -620,7 +621,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getRawMempool().", err)
wlogger.error('Error in blockchain.ts/getRawMempool().', err)
return _this.errorHandler(err, res)
}
@@ -645,28 +646,29 @@ class Blockchain {
try {
// Validate input parameter
const txid = req.params.txid
if (!txid || txid === "") {
if (!txid || txid === '') {
res.status(400)
return res.json({ error: "txid can not be empty" })
return res.json({ error: 'txid can not be empty' })
}
let n = req.params.n
if (n === undefined || n === "") {
if (n === undefined || n === '') {
res.status(400)
return res.json({ error: "n can not be empty" })
return res.json({ error: 'n can not be empty' })
}
n = parseInt(n)
let include_mempool = false
if (req.query.include_mempool && req.query.include_mempool === "true")
include_mempool = true
let includeMempool = false
if (req.query.includeMempool && req.query.includeMempool === 'true') {
includeMempool = true
}
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "gettxout"
options.data.method = "gettxout"
options.data.params = [txid, n, include_mempool]
options.data.id = 'gettxout'
options.data.method = 'gettxout'
options.data.params = [txid, n, includeMempool]
// console.log(`requestConfig: ${JSON.stringify(requestConfig, null, 2)}`)
@@ -676,7 +678,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getTxOut().", err)
wlogger.error('Error in blockchain.ts/getTxOut().', err)
return _this.errorHandler(err, res)
}
@@ -698,16 +700,16 @@ class Blockchain {
try {
// Validate input parameter
const txid = req.params.txid
if (!txid || txid === "") {
if (!txid || txid === '') {
res.status(400)
return res.json({ error: "txid can not be empty" })
return res.json({ error: 'txid can not be empty' })
}
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "gettxoutproof"
options.data.method = "gettxoutproof"
options.data.id = 'gettxoutproof'
options.data.method = 'gettxoutproof'
options.data.params = [[txid]]
const response = await _this.axios.request(options)
@@ -716,7 +718,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getTxOutProofSingle().", err)
wlogger.error('Error in blockchain.ts/getTxOutProofSingle().', err)
return _this.errorHandler(err, res)
}
@@ -731,7 +733,7 @@ class Blockchain {
if (!Array.isArray(txids)) {
res.status(400)
return res.json({
error: "txids needs to be an array. Use GET for single txid."
error: 'txids needs to be an array. Use GET for single txid.'
})
}
@@ -739,7 +741,7 @@ class Blockchain {
if (!routeUtils.validateArraySize(req, txids)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: "Array too large."
error: 'Array too large.'
})
}
@@ -759,17 +761,17 @@ class Blockchain {
}
wlogger.debug(
"Executing blockchain/getTxOutProof with these txids: ",
'Executing blockchain/getTxOutProof with these txids: ',
txids
)
// Loop through each txid and creates an array of requests to call in parallel
const promises = txids.map(async txid => {
options.data.id = "gettxoutproof"
options.data.method = "gettxoutproof"
options.data.id = 'gettxoutproof'
options.data.method = 'gettxoutproof'
options.data.params = [[txid]]
return await _this.axios.request(options)
return _this.axios.request(options)
})
// Wait for all parallel promisses to resolve.
@@ -783,7 +785,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/getTxOutProofBulk().", err)
wlogger.error('Error in blockchain.ts/getTxOutProofBulk().', err)
return _this.errorHandler(err, res)
}
@@ -793,16 +795,16 @@ class Blockchain {
try {
// Validate input parameter
const proof = req.params.proof
if (!proof || proof === "") {
if (!proof || proof === '') {
res.status(400)
return res.json({ error: "proof can not be empty" })
return res.json({ error: 'proof can not be empty' })
}
// Axios options
const options = _this.routeUtils.getAxiosOptions()
options.data.id = "verifytxoutproof"
options.data.method = "verifytxoutproof"
options.data.id = 'verifytxoutproof'
options.data.method = 'verifytxoutproof'
options.data.params = [req.params.proof]
const response = await _this.axios.request(options)
@@ -811,7 +813,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/verifyTxOutProofSingle().", err)
wlogger.error('Error in blockchain.ts/verifyTxOutProofSingle().', err)
return _this.errorHandler(err, res)
}
@@ -825,7 +827,7 @@ class Blockchain {
if (!Array.isArray(proofs)) {
res.status(400)
return res.json({
error: "proofs needs to be an array. Use GET for single proof."
error: 'proofs needs to be an array. Use GET for single proof.'
})
}
@@ -833,7 +835,7 @@ class Blockchain {
if (!routeUtils.validateArraySize(req, proofs)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: "Array too large."
error: 'Array too large.'
})
}
@@ -844,24 +846,24 @@ class Blockchain {
for (let i = 0; i < proofs.length; i++) {
const proof = proofs[i]
if (!proof || proof === "") {
if (!proof || proof === '') {
res.status(400)
return res.json({ error: `proof can not be empty: ${proof}` })
}
}
wlogger.debug(
"Executing blockchain/verifyTxOutProof with these proofs: ",
'Executing blockchain/verifyTxOutProof with these proofs: ',
proofs
)
// Loop through each proof and creates an array of requests to call in parallel
const promises = proofs.map(async proof => {
options.data.id = "verifytxoutproof"
options.data.method = "verifytxoutproof"
options.data.id = 'verifytxoutproof'
options.data.method = 'verifytxoutproof'
options.data.params = [proof]
return await _this.axios.request(options)
return _this.axios.request(options)
})
// Wait for all parallel promisses to resolve.
@@ -875,7 +877,7 @@ class Blockchain {
} catch (err) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error("Error in blockchain.ts/verifyTxOutProofBulk().", err)
wlogger.error('Error in blockchain.ts/verifyTxOutProofBulk().', err)
return _this.errorHandler(err, res)
}
+15 -16
View File
@@ -1,21 +1,21 @@
"use strict"
'use strict'
const express = require("express")
const express = require('express')
const router = express.Router()
const axios = require("axios")
// const axios = require('axios')
const routeUtils = require("../route-utils")
const wlogger = require("../../../util/winston-logging")
const routeUtils = require('../route-utils')
const wlogger = require('../../../util/winston-logging')
// Used for processing error messages before sending them to the user.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
router.get("/", root)
router.get("/getnetworkinfo", getNetworkInfo)
router.get('/', root)
router.get('/getnetworkinfo', getNetworkInfo)
function root (req, res, next) {
return res.json({ status: "control" })
return res.json({ status: 'control' })
}
/**
@@ -31,13 +31,13 @@ function root(req, res, next) {
async function getNetworkInfo (req, res, next) {
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
requestConfig.data.id = "getnetworkinfo"
requestConfig.data.method = "getnetworkinfo"
requestConfig.data.id = 'getnetworkinfo'
requestConfig.data.method = 'getnetworkinfo'
requestConfig.data.params = []
try {
@@ -45,14 +45,13 @@ async function getNetworkInfo(req, res, next) {
return res.json(response.data.result)
} catch (error) {
wlogger.error(`Error in control.ts/getNetworkInfo().`, error)
wlogger.error('Error in control.ts/getNetworkInfo().', error)
// Write out error to error log.
// logger.error(`Error in control/getInfo: `, error)
res.status(500)
if (error.response && error.response.data && error.response.data.error)
return res.json({ error: error.response.data.error })
if (error.response && error.response.data && error.response.data.error) { return res.json({ error: error.response.data.error }) }
return res.json({ error: util.inspect(error) })
}
}
+35 -35
View File
@@ -1,39 +1,39 @@
"use strict"
'use strict'
const express = require("express")
const express = require('express')
const router = express.Router()
const axios = require("axios")
// const axios = require('axios')
const routeUtils = require("../route-utils")
const wlogger = require("../../../util/winston-logging")
const routeUtils = require('../route-utils')
const wlogger = require('../../../util/winston-logging')
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const BitboxHTTP = axios.create({
baseURL: process.env.RPC_BASEURL
})
const username = process.env.RPC_USERNAME
const password = process.env.RPC_PASSWORD
// const BitboxHTTP = axios.create({
// baseURL: process.env.RPC_BASEURL
// })
// const username = process.env.RPC_USERNAME
// const password = process.env.RPC_PASSWORD
const requestConfig = {
method: "post",
auth: {
username: username,
password: password
},
data: {
jsonrpc: "1.0"
}
}
// const requestConfig = {
// method: 'post',
// auth: {
// username: username,
// password: password
// },
// data: {
// jsonrpc: '1.0'
// }
// }
router.get("/", root)
router.get("/getMiningInfo", getMiningInfo)
router.get("/getNetworkHashps", getNetworkHashPS)
router.get('/', root)
router.get('/getMiningInfo', getMiningInfo)
router.get('/getNetworkHashps', getNetworkHashPS)
function root (req, res, next) {
return res.json({ status: "mining" })
return res.json({ status: 'mining' })
}
//
@@ -76,13 +76,13 @@ async function getMiningInfo(req, res, next) {
try {
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
requestConfig.data.id = "getmininginfo"
requestConfig.data.method = "getmininginfo"
requestConfig.data.id = 'getmininginfo'
requestConfig.data.method = 'getmininginfo'
requestConfig.data.params = []
const response = await BitboxHTTP(requestConfig)
@@ -96,7 +96,7 @@ async function getMiningInfo(req, res, next) {
return res.json({ error: msg })
}
wlogger.error(`Error in mining.ts/getMiningInfo().`, err)
wlogger.error('Error in mining.ts/getMiningInfo().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -123,13 +123,13 @@ async function getNetworkHashPS(req, res, next) {
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
requestConfig.data.id = "getnetworkhashps"
requestConfig.data.method = "getnetworkhashps"
requestConfig.data.id = 'getnetworkhashps'
requestConfig.data.method = 'getnetworkhashps'
requestConfig.data.params = [nblocks, height]
const response = await BitboxHTTP(requestConfig)
@@ -143,7 +143,7 @@ async function getNetworkHashPS(req, res, next) {
return res.json({ error: msg })
}
wlogger.error(`Error in mining.ts/getNetworkHashPS().`, err)
wlogger.error('Error in mining.ts/getNetworkHashPS().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
+4 -4
View File
@@ -1,10 +1,10 @@
"use strict"
'use strict'
const express = require("express")
const express = require('express')
const router = express.Router()
router.get("/", async (req, res, next) => {
res.json({ status: "network" })
router.get('/', async (req, res, next) => {
res.json({ status: 'network' })
})
// router.post('/addNode/:node/:command', (req, res, next) => {
+103 -103
View File
@@ -1,45 +1,45 @@
"use strict"
'use strict'
const express = require("express")
const express = require('express')
const router = express.Router()
const axios = require("axios")
const axios = require('axios')
const routeUtils = require("../route-utils")
const wlogger = require("../../../util/winston-logging")
const routeUtils = require('../route-utils')
const wlogger = require('../../../util/winston-logging')
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const BitboxHTTP = axios.create({
baseURL: process.env.RPC_BASEURL
})
const username = process.env.RPC_USERNAME
const password = process.env.RPC_PASSWORD
// const BitboxHTTP = axios.create({
// baseURL: process.env.RPC_BASEURL
// })
// const username = process.env.RPC_USERNAME
// const password = process.env.RPC_PASSWORD
const requestConfig = {
method: "post",
auth: {
username: username,
password: password
},
data: {
jsonrpc: "1.0"
}
}
// const requestConfig = {
// method: 'post',
// auth: {
// username: username,
// password: password
// },
// data: {
// jsonrpc: '1.0'
// }
// }
router.get("/", root)
router.get("/decodeRawTransaction/:hex", decodeRawTransactionSingle)
router.post("/decodeRawTransaction", decodeRawTransactionBulk)
router.get("/decodeScript/:hex", decodeScriptSingle)
router.post("/decodeScript", decodeScriptBulk)
router.post("/getRawTransaction", getRawTransactionBulk)
router.get("/getRawTransaction/:txid", getRawTransactionSingle)
router.post("/sendRawTransaction", sendRawTransactionBulk)
router.get("/sendRawTransaction/:hex", sendRawTransactionSingle)
router.get('/', root)
router.get('/decodeRawTransaction/:hex', decodeRawTransactionSingle)
router.post('/decodeRawTransaction', decodeRawTransactionBulk)
router.get('/decodeScript/:hex', decodeScriptSingle)
router.post('/decodeScript', decodeScriptBulk)
router.post('/getRawTransaction', getRawTransactionBulk)
router.get('/getRawTransaction/:txid', getRawTransactionSingle)
router.post('/sendRawTransaction', sendRawTransactionBulk)
router.get('/sendRawTransaction/:hex', sendRawTransactionSingle)
function root (req, res, next) {
return res.json({ status: "rawtransactions" })
return res.json({ status: 'rawtransactions' })
}
// Decode transaction hex into a JSON object.
@@ -61,20 +61,20 @@ async function decodeRawTransactionSingle(req, res, next) {
const hex = req.params.hex
// Throw an error if hex is empty.
if (!hex || hex === "") {
if (!hex || hex === '') {
res.status(400)
return res.json({ error: "hex can not be empty" })
return res.json({ error: 'hex can not be empty' })
}
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
requestConfig.data.id = "decoderawtransaction"
requestConfig.data.method = "decoderawtransaction"
requestConfig.data.id = 'decoderawtransaction'
requestConfig.data.method = 'decoderawtransaction'
requestConfig.data.params = [hex]
const response = await BitboxHTTP(requestConfig)
@@ -90,7 +90,7 @@ async function decodeRawTransactionSingle(req, res, next) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeRawTransaction: `, err)
wlogger.error(
`Error in rawtransactions.ts/decodeRawTransactionSingle().`,
'Error in rawtransactions.ts/decodeRawTransactionSingle().',
err
)
@@ -117,44 +117,44 @@ async function decodeRawTransactionBulk(req, res, next) {
if (!Array.isArray(hexes)) {
res.status(400)
return res.json({ error: "hexes must be an array" })
return res.json({ error: 'hexes must be an array' })
}
// Enforce array size rate limits
if (!routeUtils.validateArraySize(req, hexes)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
const results = []
// const results = []
// Validate each element in the address array.
for (let i = 0; i < hexes.length; i++) {
const thisHex = hexes[i]
// Reject if id is empty
if (!thisHex || thisHex === "") {
if (!thisHex || thisHex === '') {
res.status(400)
return res.json({ error: "Encountered empty hex" })
return res.json({ error: 'Encountered empty hex' })
}
}
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
// Loop through each height and creates an array of requests to call in parallel
const promises = hexes.map(async hex => {
requestConfig.data.id = "decoderawtransaction"
requestConfig.data.method = "decoderawtransaction"
requestConfig.data.id = 'decoderawtransaction'
requestConfig.data.method = 'decoderawtransaction'
requestConfig.data.params = [hex]
return await BitboxHTTP(requestConfig)
return BitboxHTTP(requestConfig)
})
// Wait for all parallel Insight requests to return.
@@ -212,7 +212,7 @@ async function decodeRawTransactionBulk(req, res, next) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/getRawTransaction: `, err)
wlogger.error(
`Error in rawtransactions.ts/decodeRawTransactionBulk().`,
'Error in rawtransactions.ts/decodeRawTransactionBulk().',
err
)
@@ -240,20 +240,20 @@ async function decodeScriptSingle(req, res, next) {
const hex = req.params.hex
// Throw an error if hex is empty.
if (!hex || hex === "") {
if (!hex || hex === '') {
res.status(400)
return res.json({ error: "hex can not be empty" })
return res.json({ error: 'hex can not be empty' })
}
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
requestConfig.data.id = "decodescript"
requestConfig.data.method = "decodescript"
requestConfig.data.id = 'decodescript'
requestConfig.data.method = 'decodescript'
requestConfig.data.params = [hex]
const response = await BitboxHTTP(requestConfig)
@@ -268,7 +268,7 @@ async function decodeScriptSingle(req, res, next) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeScript: `, err)
wlogger.error(`Error in rawtransactions.ts/decodeScriptSingle().`, err)
wlogger.error('Error in rawtransactions.ts/decodeScriptSingle().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -296,14 +296,14 @@ async function decodeScriptBulk(req, res, next) {
// Validation
if (!Array.isArray(hexes)) {
res.status(400)
return res.json({ error: "hexes must be an array" })
return res.json({ error: 'hexes must be an array' })
}
// Enforce array size rate limits
if (!routeUtils.validateArraySize(req, hexes)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
@@ -312,23 +312,23 @@ async function decodeScriptBulk(req, res, next) {
const hex = hexes[i]
// Throw an error if hex is empty.
if (!hex || hex === "") {
if (!hex || hex === '') {
res.status(400)
return res.json({ error: "Encountered empty hex" })
return res.json({ error: 'Encountered empty hex' })
}
}
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
// Loop through each hex and create an array of promises
const promises = hexes.map(async hex => {
requestConfig.data.id = "decodescript"
requestConfig.data.method = "decodescript"
requestConfig.data.id = 'decodescript'
requestConfig.data.method = 'decodescript'
requestConfig.data.params = [hex]
const response = await BitboxHTTP(requestConfig)
@@ -353,7 +353,7 @@ async function decodeScriptBulk(req, res, next) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/decodeScript: `, err)
wlogger.error(`Error in rawtransactions.ts/decodeScriptBulk().`, err)
wlogger.error('Error in rawtransactions.ts/decodeScriptBulk().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -366,20 +366,20 @@ async function getRawTransactionsFromNode(txid, verbose) {
try {
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
requestConfig.data.id = "getrawtransaction"
requestConfig.data.method = "getrawtransaction"
requestConfig.data.id = 'getrawtransaction'
requestConfig.data.method = 'getrawtransaction'
requestConfig.data.params = [txid, verbose]
const response = await BitboxHTTP(requestConfig)
return response.data.result
} catch (err) {
wlogger.error(`Error in rawtransactions.ts/getRawTransactionsFromNode().`)
wlogger.error('Error in rawtransactions.ts/getRawTransactionsFromNode().')
throw err
}
}
@@ -405,32 +405,32 @@ async function getRawTransactionBulk(req, res, next) {
const txids = req.body.txids
if (!Array.isArray(txids)) {
res.status(400)
return res.json({ error: "txids must be an array" })
return res.json({ error: 'txids must be an array' })
}
// Enforce array size rate limits
if (!routeUtils.validateArraySize(req, txids)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
// stub response object
const returnResponse = {
status: 100,
json: {
error: ""
}
}
// const returnResponse = {
// status: 100,
// json: {
// error: ''
// }
// }
// Validate each txid in the array.
for (let i = 0; i < txids.length; i++) {
const txid = txids[i]
if (!txid || txid === "") {
if (!txid || txid === '') {
res.status(400)
return res.json({ error: `Encountered empty TXID` })
return res.json({ error: 'Encountered empty TXID' })
}
if (txid.length !== 64) {
@@ -461,7 +461,7 @@ async function getRawTransactionBulk(req, res, next) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/getRawTransaction: `, err)
wlogger.error(`Error in rawtransactions.ts/getRawTransactionBulk().`, err)
wlogger.error('Error in rawtransactions.ts/getRawTransactionBulk().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -485,12 +485,12 @@ async function getRawTransactionBulk(req, res, next) {
async function getRawTransactionSingle (req, res, next) {
try {
let verbose = 0
if (req.query.verbose === "true") verbose = 1
if (req.query.verbose === 'true') verbose = 1
const txid = req.params.txid
if (!txid || txid === "") {
if (!txid || txid === '') {
res.status(400)
return res.json({ error: "txid can not be empty" })
return res.json({ error: 'txid can not be empty' })
}
const data = await getRawTransactionsFromNode(txid, verbose)
@@ -506,7 +506,7 @@ async function getRawTransactionSingle(req, res, next) {
// Write out error to error log.
// logger.error(`Error in rawtransactions/getRawTransaction: `, err)
wlogger.error(`Error in rawtransactions.ts/getRawTransactionSingle().`, err)
wlogger.error('Error in rawtransactions.ts/getRawTransactionSingle().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -534,13 +534,13 @@ async function sendRawTransactionBulk(req, res, next) {
// Reject if input is not an array
if (!Array.isArray(hexes)) {
res.status(400)
return res.json({ error: "hex must be an array" })
return res.json({ error: 'hex must be an array' })
}
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
@@ -548,7 +548,7 @@ async function sendRawTransactionBulk(req, res, next) {
if (!routeUtils.validateArraySize(req, hexes)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
@@ -556,10 +556,10 @@ async function sendRawTransactionBulk(req, res, next) {
for (let i = 0; i < hexes.length; i++) {
const hex = hexes[i]
if (hex === "") {
if (hex === '') {
res.status(400)
return res.json({
error: `Encountered empty hex`
error: 'Encountered empty hex'
})
}
}
@@ -594,8 +594,8 @@ async function sendRawTransactionBulk(req, res, next) {
for (let i = 0; i < hexes.length; i++) {
const hex = hexes[i]
requestConfig.data.id = "sendrawtransaction"
requestConfig.data.method = "sendrawtransaction"
requestConfig.data.id = 'sendrawtransaction'
requestConfig.data.method = 'sendrawtransaction'
requestConfig.data.params = [hex]
const rpcResult = await BitboxHTTP(requestConfig)
@@ -613,7 +613,7 @@ async function sendRawTransactionBulk(req, res, next) {
return res.json({ error: msg })
}
wlogger.error(`Error in rawtransactions.ts/sendRawTransactionBulk().`, err)
wlogger.error('Error in rawtransactions.ts/sendRawTransactionBulk().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -638,29 +638,29 @@ async function sendRawTransactionSingle(req, res, next) {
const hex = req.params.hex // URL parameter
// Reject if input is not an array or a string
if (typeof hex !== "string") {
if (typeof hex !== 'string') {
res.status(400)
return res.json({ error: "hex must be a string" })
return res.json({ error: 'hex must be a string' })
}
// Validation
if (hex === "") {
if (hex === '') {
res.status(400)
return res.json({
error: `Encountered empty hex`
error: 'Encountered empty hex'
})
}
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
// RPC call
requestConfig.data.id = "sendrawtransaction"
requestConfig.data.method = "sendrawtransaction"
requestConfig.data.id = 'sendrawtransaction'
requestConfig.data.method = 'sendrawtransaction'
requestConfig.data.params = [hex]
const rpcResult = await BitboxHTTP(requestConfig)
@@ -678,7 +678,7 @@ async function sendRawTransactionSingle(req, res, next) {
}
wlogger.error(
`Error in rawtransactions.ts/sendRawTransactionSingle().`,
'Error in rawtransactions.ts/sendRawTransactionSingle().',
err
)
+3 -3
View File
@@ -3,13 +3,13 @@
readiness.
*/
"use strict"
'use strict'
const express = require("express")
const express = require('express')
const router = express.Router()
/* GET home page. */
router.get("/", (req, res, next) => {
router.get('/', (req, res, next) => {
res.json({ status: true })
})
+11 -11
View File
@@ -2,30 +2,30 @@
A library for interacting with the Bitcoin.com ninsight (not Insight) indexer.
*/
"use strict"
'use strict'
const express = require("express")
const axios = require("axios")
const routeUtils = require("./route-utils")
const wlogger = require("../../util/winston-logging")
const express = require('express')
// const axios = require('axios')
// const routeUtils = require('./route-utils')
// const wlogger = require('../../util/winston-logging')
const router = express.Router()
const BCHJS = require("@chris.troutner/bch-js")
const bchjs = new BCHJS()
// const BCHJS = require('@chris.troutner/bch-js')
// const bchjs = new BCHJS()
let _this
// let _this
class Ninsight {
constructor () {
_this = this
// _this = this
this.router = router
this.router.get("/", this.root)
this.router.get('/', this.root)
}
root (req, res, next) {
return res.json({ status: "ninsight" })
return res.json({ status: 'ninsight' })
}
}
+27 -25
View File
@@ -2,15 +2,15 @@
A private library of utility functions used by several different routes.
*/
"use strict"
'use strict'
const axios = require("axios")
const wlogger = require("../../util/winston-logging")
const axios = require('axios')
const wlogger = require('../../util/winston-logging')
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const BCHJS = require("@chris.troutner/bch-js")
const BCHJS = require('@chris.troutner/bch-js')
const bchjs = new BCHJS()
module.exports = {
@@ -48,8 +48,8 @@ function validateNetwork(addr) {
const network = process.env.NETWORK
// Return false if NETWORK is not defined.
if (!network || network === "") {
console.log(`Warning: NETWORK environment variable is not defined!`)
if (!network || network === '') {
console.log('Warning: NETWORK environment variable is not defined!')
return false
}
@@ -59,15 +59,15 @@ function validateNetwork(addr) {
// Return true if the network and address both match testnet
const addrIsTest = bchjs.Address.isTestnetAddress(cashAddr)
if (network === "testnet" && addrIsTest) return true
if (network === 'testnet' && addrIsTest) return true
// Return true if the network and address both match mainnet
const addrIsMain = bchjs.Address.isMainnetAddress(cashAddr)
if (network === "mainnet" && addrIsMain) return true
if (network === 'mainnet' && addrIsMain) return true
return false
} catch (err) {
logger.error(`Error in validateNetwork()`)
wlogger.error('Error in validateNetwork()')
return false
}
}
@@ -82,13 +82,13 @@ function setEnvVars() {
const password = process.env.RPC_PASSWORD
const requestConfig = {
method: "post",
method: 'post',
auth: {
username: username,
password: password
},
data: {
jsonrpc: "1.0"
jsonrpc: '1.0'
}
}
@@ -98,7 +98,7 @@ function setEnvVars() {
// Axios options used when calling axios.post() to talk with a full node.
function getAxiosOptions () {
return {
method: "post",
method: 'post',
baseURL: process.env.RPC_BASEURL,
timeout: 15000,
auth: {
@@ -106,7 +106,7 @@ function getAxiosOptions() {
password: process.env.RPC_PASSWORD
},
data: {
jsonrpc: "1.0"
jsonrpc: '1.0'
}
}
}
@@ -124,39 +124,41 @@ function decodeError(err) {
err.response.data &&
err.response.data.error &&
err.response.data.error.message
)
) {
return { msg: err.response.data.error.message, status: 400 }
}
// Attempt to extract the Insight error message
if (err.response && err.response.data)
if (err.response && err.response.data) {
return { msg: err.response.data, status: err.response.status }
}
// console.log(`err.message: ${err.message}`)
// console.log(`err: `, err)
// Attempt to detect a network connection error.
if (err.message && err.message.indexOf("ENOTFOUND") > -1) {
if (err.message && err.message.indexOf('ENOTFOUND') > -1) {
return {
msg:
"Network error: Could not communicate with full node or other external service.",
'Network error: Could not communicate with full node or other external service.',
status: 503
}
}
// Different kind of network error
if (err.message && err.message.indexOf("ENETUNREACH") > -1) {
if (err.message && err.message.indexOf('ENETUNREACH') > -1) {
return {
msg:
"Network error: Could not communicate with full node or other external service.",
'Network error: Could not communicate with full node or other external service.',
status: 503
}
}
// Different kind of network error
if (err.message && err.message.indexOf("EAI_AGAIN") > -1) {
if (err.message && err.message.indexOf('EAI_AGAIN') > -1) {
return {
msg:
"Network error: Could not communicate with full node or other external service.",
'Network error: Could not communicate with full node or other external service.',
status: 503
}
}
@@ -164,18 +166,18 @@ function decodeError(err) {
// Axios timeout (aborted) error, or service is down (connection refused).
if (
err.code &&
(err.code === "ECONNABORTED" || err.code === "ECONNREFUSED")
(err.code === 'ECONNABORTED' || err.code === 'ECONNREFUSED')
) {
return {
msg:
"Network error: Could not communicate with full node or other external service.",
'Network error: Could not communicate with full node or other external service.',
status: 503
}
}
return { msg: false, status: 500 }
} catch (err) {
wlogger.error(`unhandled error in route-utils.js/decodeError(): `, err)
wlogger.error('unhandled error in route-utils.js/decodeError(): ', err)
return { msg: false, status: 500 }
}
}
+27 -25
View File
@@ -2,22 +2,22 @@
A private library of utility functions used by several different routes.
*/
"use strict"
'use strict'
const axios = require("axios")
const wlogger = require("../../util/winston-logging")
const axios = require('axios')
const wlogger = require('../../util/winston-logging')
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const BCHJS = require("@chris.troutner/bch-js")
const BCHJS = require('@chris.troutner/bch-js')
const bchjs = new BCHJS()
let _this
// let _this
class RouteUtils {
constructor () {
_this = this
// _this = this
this.bchjs = bchjs
this.axios = axios
@@ -43,7 +43,7 @@ class RouteUtils {
// Axios options used when calling axios.post() to talk with a full node.
getAxiosOptions () {
return {
method: "post",
method: 'post',
baseURL: process.env.RPC_BASEURL,
timeout: 15000,
auth: {
@@ -51,7 +51,7 @@ class RouteUtils {
password: process.env.RPC_PASSWORD
},
data: {
jsonrpc: "1.0"
jsonrpc: '1.0'
}
}
}
@@ -66,8 +66,8 @@ class RouteUtils {
const network = process.env.NETWORK
// Return false if NETWORK is not defined.
if (!network || network === "") {
console.log(`Warning: NETWORK environment variable is not defined!`)
if (!network || network === '') {
console.log('Warning: NETWORK environment variable is not defined!')
return false
}
@@ -77,15 +77,15 @@ class RouteUtils {
// Return true if the network and address both match testnet
const addrIsTest = this.bchjs.Address.isTestnetAddress(cashAddr)
if (network === "testnet" && addrIsTest) return true
if (network === 'testnet' && addrIsTest) return true
// Return true if the network and address both match mainnet
const addrIsMain = this.bchjs.Address.isMainnetAddress(cashAddr)
if (network === "mainnet" && addrIsMain) return true
if (network === 'mainnet' && addrIsMain) return true
return false
} catch (err) {
logger.error(`Error in validateNetwork()`)
wlogger.error('Error in validateNetwork()')
return false
}
}
@@ -103,39 +103,41 @@ class RouteUtils {
err.response.data &&
err.response.data.error &&
err.response.data.error.message
)
) {
return { msg: err.response.data.error.message, status: 400 }
}
// Attempt to extract the Insight error message
if (err.response && err.response.data)
if (err.response && err.response.data) {
return { msg: err.response.data, status: err.response.status }
}
// console.log(`err.message: ${err.message}`)
// console.log(`err: `, err)
// Attempt to detect a network connection error.
if (err.message && err.message.indexOf("ENOTFOUND") > -1) {
if (err.message && err.message.indexOf('ENOTFOUND') > -1) {
return {
msg:
"Network error: Could not communicate with full node or other external service.",
'Network error: Could not communicate with full node or other external service.',
status: 503
}
}
// Different kind of network error
if (err.message && err.message.indexOf("ENETUNREACH") > -1) {
if (err.message && err.message.indexOf('ENETUNREACH') > -1) {
return {
msg:
"Network error: Could not communicate with full node or other external service.",
'Network error: Could not communicate with full node or other external service.',
status: 503
}
}
// Different kind of network error
if (err.message && err.message.indexOf("EAI_AGAIN") > -1) {
if (err.message && err.message.indexOf('EAI_AGAIN') > -1) {
return {
msg:
"Network error: Could not communicate with full node or other external service.",
'Network error: Could not communicate with full node or other external service.',
status: 503
}
}
@@ -143,18 +145,18 @@ class RouteUtils {
// Axios timeout (aborted) error, or service is down (connection refused).
if (
err.code &&
(err.code === "ECONNABORTED" || err.code === "ECONNREFUSED")
(err.code === 'ECONNABORTED' || err.code === 'ECONNREFUSED')
) {
return {
msg:
"Network error: Could not communicate with full node or other external service.",
'Network error: Could not communicate with full node or other external service.',
status: 503
}
}
return { msg: false, status: 500 }
} catch (err) {
wlogger.error(`unhandled error in route-utils.js/decodeError(): `, err)
wlogger.error('unhandled error in route-utils.js/decodeError(): ', err)
return { msg: false, status: 500 }
}
}
+192 -197
View File
@@ -1,68 +1,69 @@
"use strict"
'use strict'
const express = require("express")
const express = require('express')
const router = express.Router()
const axios = require("axios")
const BigNumber = require("bignumber.js")
const axios = require('axios')
const BigNumber = require('bignumber.js')
const routeUtils = require("./route-utils")
const strftime = require("strftime")
const wlogger = require("../../util/winston-logging")
const routeUtils = require('./route-utils')
// const strftime = require('strftime')
const wlogger = require('../../util/winston-logging')
const BCHJS = require("@chris.troutner/bch-js")
const BCHJS = require('@chris.troutner/bch-js')
const bchjs = new BCHJS()
// Used to convert error messages to strings, to safely pass to users.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 5 }
// Setup JSON RPC
const BitboxHTTP = axios.create({
baseURL: process.env.RPC_BASEURL
})
const username = process.env.RPC_USERNAME
const password = process.env.RPC_PASSWORD
// const BitboxHTTP = axios.create({
// baseURL: process.env.RPC_BASEURL
// })
// const username = process.env.RPC_USERNAME
// const password = process.env.RPC_PASSWORD
// Determine the Access password for a private instance of SLPDB.
// https://gist.github.com/christroutner/fc717ca704dec3dded8b52fae387eab2
const SLPDB_PASS = process.env.SLPDB_PASS ? process.env.SLPDB_PASS : "BITBOX"
const SLPDB_PASS = process.env.SLPDB_PASS ? process.env.SLPDB_PASS : 'BITBOX'
// const transactions = require("./insight/transaction")
const rawtransactions = require("./full-node/rawtransactions")
const rawtransactions = require('./full-node/rawtransactions')
// Setup REST and TREST URLs used by slpjs
// Dev note: this allows for unit tests to mock the URL.
if (!process.env.REST_URL) process.env.REST_URL = `https://rest.bitcoin.com/v2/`
if (!process.env.TREST_URL)
process.env.TREST_URL = `https://trest.bitcoin.com/v2/`
router.get("/", root)
router.get("/list", list)
router.get("/list/:tokenId", listSingleToken)
router.post("/list", listBulkToken)
router.get("/balancesForAddress/:address", balancesForAddress)
router.post("/balancesForAddress", balancesForAddressBulk)
router.get("/balancesForToken/:tokenId", balancesForTokenSingle)
router.get("/balance/:address/:tokenId", balancesForAddressByTokenID)
router.get("/convert/:address", convertAddressSingle)
router.post("/convert", convertAddressBulk)
router.post("/validateTxid", validateBulk)
router.get("/validateTxid/:txid", validateSingle)
router.get("/txDetails/:txid", txDetails)
router.get("/tokenStats/:tokenId", tokenStats)
router.get("/transactions/:tokenId/:address", txsTokenIdAddressSingle)
const requestConfig = {
method: "post",
auth: {
username: username,
password: password
},
data: {
jsonrpc: "1.0"
}
if (!process.env.REST_URL) process.env.REST_URL = 'https://rest.bitcoin.com/v2/'
if (!process.env.TREST_URL) {
process.env.TREST_URL = 'https://trest.bitcoin.com/v2/'
}
router.get('/', root)
router.get('/list', list)
router.get('/list/:tokenId', listSingleToken)
router.post('/list', listBulkToken)
router.get('/balancesForAddress/:address', balancesForAddress)
router.post('/balancesForAddress', balancesForAddressBulk)
router.get('/balancesForToken/:tokenId', balancesForTokenSingle)
router.get('/balance/:address/:tokenId', balancesForAddressByTokenID)
router.get('/convert/:address', convertAddressSingle)
router.post('/convert', convertAddressBulk)
router.post('/validateTxid', validateBulk)
router.get('/validateTxid/:txid', validateSingle)
router.get('/txDetails/:txid', txDetails)
router.get('/tokenStats/:tokenId', tokenStats)
router.get('/transactions/:tokenId/:address', txsTokenIdAddressSingle)
// const requestConfig = {
// method: 'post',
// auth: {
// username: username,
// password: password
// },
// data: {
// jsonrpc: '1.0'
// }
// }
function formatTokenOutput (token) {
token.tokenDetails.id = token.tokenDetails.tokenIdHex
delete token.tokenDetails.tokenIdHex
@@ -99,7 +100,7 @@ function formatTokenOutput(token) {
}
function root (req, res, next) {
return res.json({ status: "slp" })
return res.json({ status: 'slp' })
}
/**
@@ -119,18 +120,18 @@ async function list(req, res, next) {
const query = {
v: 3,
q: {
db: ["t"],
db: ['t'],
find: {
$query: {}
},
project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
sort: { "tokenStats.block_created": -1 },
sort: { 'tokenStats.block_created': -1 },
limit: 10000
}
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
// Get data from SLPDB.
@@ -148,7 +149,7 @@ async function list(req, res, next) {
res.status(200)
return res.json(formattedTokens)
} catch (err) {
wlogger.error(`Error in slp.ts/list().`, err)
wlogger.error('Error in slp.ts/list().', err)
const { msg, status } = routeUtils.decodeError(err)
if (msg) {
@@ -176,9 +177,9 @@ async function listSingleToken(req, res, next) {
try {
const tokenId = req.params.tokenId
if (!tokenId || tokenId === "") {
if (!tokenId || tokenId === '') {
res.status(400)
return res.json({ error: "tokenId can not be empty" })
return res.json({ error: 'tokenId can not be empty' })
}
const t = await lookupToken(tokenId)
@@ -186,7 +187,7 @@ async function listSingleToken(req, res, next) {
res.status(200)
return res.json(t)
} catch (err) {
wlogger.error(`Error in slp.ts/listSingleToken().`, err)
wlogger.error('Error in slp.ts/listSingleToken().', err)
const { msg, status } = routeUtils.decodeError(err)
if (msg) {
@@ -218,7 +219,7 @@ async function listBulkToken(req, res, next) {
if (!Array.isArray(tokenIds)) {
res.status(400)
return res.json({
error: "tokenIds needs to be an array. Use GET for single tokenId."
error: 'tokenIds needs to be an array. Use GET for single tokenId.'
})
}
@@ -226,27 +227,27 @@ async function listBulkToken(req, res, next) {
if (!routeUtils.validateArraySize(req, tokenIds)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
const query = {
v: 3,
q: {
db: ["t"],
db: ['t'],
find: {
"tokenDetails.tokenIdHex": {
'tokenDetails.tokenIdHex': {
$in: tokenIds
}
},
project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
sort: { "tokenStats.block_created": -1 },
sort: { 'tokenStats.block_created': -1 },
limit: 10000
}
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
const tokenRes = await axios.get(url)
@@ -274,7 +275,7 @@ async function listBulkToken(req, res, next) {
res.status(200)
return res.json(formattedTokens)
} catch (err) {
wlogger.error(`Error in slp.ts/listBulkToken().`, err)
wlogger.error('Error in slp.ts/listBulkToken().', err)
const { msg, status } = routeUtils.decodeError(err)
if (msg) {
@@ -291,10 +292,10 @@ async function lookupToken(tokenId) {
const query = {
v: 3,
q: {
db: ["t"],
db: ['t'],
find: {
$query: {
"tokenDetails.tokenIdHex": tokenId
'tokenDetails.tokenIdHex': tokenId
}
},
project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
@@ -303,7 +304,7 @@ async function lookupToken(tokenId) {
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
// console.log(`url: ${url}`)
@@ -331,13 +332,13 @@ async function lookupToken(tokenId) {
// If token could not be found.
if (t === undefined) {
t = {
id: "not found"
id: 'not found'
}
}
return t
} catch (err) {
wlogger.error(`Error in slp.ts/lookupToken().`, err)
wlogger.error('Error in slp.ts/lookupToken().', err)
// console.log(`Error in slp.ts/lookupToken()`)
throw err
}
@@ -360,14 +361,14 @@ async function balancesForAddress(req, res, next) {
try {
// Validate the input data.
const address = req.params.address
if (!address || address === "") {
if (!address || address === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
// Ensure the input is a valid BCH address.
try {
const cash = bchjs.SLP.Address.toCashAddress(address)
bchjs.SLP.Address.toCashAddress(address)
} catch (err) {
res.status(400)
return res.json({
@@ -381,14 +382,15 @@ async function balancesForAddress(req, res, next) {
if (!networkIsValid) {
res.status(400)
return res.json({
error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
error:
'Invalid network. Trying to use a testnet address on mainnet, or vice versa.'
})
}
const query = {
v: 3,
q: {
db: ["a"],
db: ['a'],
find: {
address: bchjs.SLP.Address.toSLPAddress(address),
token_balance: { $gte: 0 }
@@ -398,7 +400,7 @@ async function balancesForAddress(req, res, next) {
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
const tokenRes = await axios.get(url)
@@ -419,19 +421,18 @@ async function balancesForAddress(req, res, next) {
})
const promises = tokenIds.map(async tokenId => {
try {
const query2 = {
v: 3,
q: {
db: ["t"],
db: ['t'],
find: {
$query: {
"tokenDetails.tokenIdHex": tokenId
'tokenDetails.tokenIdHex': tokenId
}
},
project: {
"tokenDetails.decimals": 1,
"tokenDetails.tokenIdHex": 1,
'tokenDetails.decimals': 1,
'tokenDetails.tokenIdHex': 1,
_id: 0
},
limit: 1000
@@ -439,30 +440,28 @@ async function balancesForAddress(req, res, next) {
}
const s2 = JSON.stringify(query2)
const b642 = Buffer.from(s2).toString("base64")
const b642 = Buffer.from(s2).toString('base64')
const url2 = `${process.env.SLPDB_URL}q/${b642}`
const tokenRes2 = await axios.get(url2)
return tokenRes2.data
} catch (err) {
throw err
}
})
const details = await axios.all(promises)
tokenRes.data.a = tokenRes.data.a.map(token => {
details.forEach(detail => {
if (detail.t[0].tokenDetails.tokenIdHex === token.tokenId)
if (detail.t[0].tokenDetails.tokenIdHex === token.tokenId) {
token.decimalCount = detail.t[0].tokenDetails.decimals
}
})
return token
})
return res.json(tokenRes.data.a)
}
return res.json("No balance for this address")
return res.json('No balance for this address')
} catch (err) {
wlogger.error(`Error in slp.ts/balancesForAddress().`, err)
wlogger.error('Error in slp.ts/balancesForAddress().', err)
// Decode the error message.
const { msg, status } = routeUtils.decodeError(err)
@@ -497,19 +496,19 @@ async function balancesForAddressBulk(req, res, next) {
// Reject if addresses is not an array.
if (!Array.isArray(addresses)) {
res.status(400)
return res.json({ error: "addresses needs to be an array" })
return res.json({ error: 'addresses needs to be an array' })
}
// Enforce array size rate limits
if (!routeUtils.validateArraySize(req, addresses)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
wlogger.debug(
`Executing slp/balancesForAddresss with these addresses: `,
'Executing slp/balancesForAddresss with these addresses: ',
addresses
)
@@ -518,9 +517,9 @@ async function balancesForAddressBulk(req, res, next) {
const address = addresses[i]
// Validate the input data.
if (!address || address === "") {
if (!address || address === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
// Ensure the input is a valid BCH address.
@@ -539,7 +538,8 @@ async function balancesForAddressBulk(req, res, next) {
if (!networkIsValid) {
res.status(400)
return res.json({
error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
error:
'Invalid network. Trying to use a testnet address on mainnet, or vice versa.'
})
}
}
@@ -547,11 +547,10 @@ async function balancesForAddressBulk(req, res, next) {
// Collect an array of promises, one for each request to slpserve.
// This is a nested array of promises.
const balancesPromises = addresses.map(async address => {
try {
const query = {
v: 3,
q: {
db: ["a"],
db: ['a'],
find: {
address: bchjs.SLP.Address.toSLPAddress(address),
token_balance: { $gte: 0 }
@@ -561,7 +560,7 @@ async function balancesForAddressBulk(req, res, next) {
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
const tokenRes = await axios.get(url)
@@ -586,19 +585,18 @@ async function balancesForAddressBulk(req, res, next) {
// Collect another array of promises.
const promises = tokenIds.map(async tokenId => {
try {
const query2 = {
v: 3,
q: {
db: ["t"],
db: ['t'],
find: {
$query: {
"tokenDetails.tokenIdHex": tokenId
'tokenDetails.tokenIdHex': tokenId
}
},
project: {
"tokenDetails.decimals": 1,
"tokenDetails.tokenIdHex": 1,
'tokenDetails.decimals': 1,
'tokenDetails.tokenIdHex': 1,
_id: 0
},
limit: 1000
@@ -606,14 +604,11 @@ async function balancesForAddressBulk(req, res, next) {
}
const s2 = JSON.stringify(query2)
const b642 = Buffer.from(s2).toString("base64")
const b642 = Buffer.from(s2).toString('base64')
const url2 = `${process.env.SLPDB_URL}q/${b642}`
const tokenRes2 = await axios.get(url2)
return tokenRes2.data
} catch (err) {
throw err
}
})
// Wait for all the promises to resolve.
@@ -621,16 +616,14 @@ async function balancesForAddressBulk(req, res, next) {
tokenRes.data.a = tokenRes.data.a.map(token => {
details.forEach(detail => {
if (detail.t[0].tokenDetails.tokenIdHex === token.tokenId)
if (detail.t[0].tokenDetails.tokenIdHex === token.tokenId) {
token.decimalCount = detail.t[0].tokenDetails.decimals
}
})
return token
})
return tokenRes.data.a
} catch (err) {
throw err
}
})
// Wait for all the promises to resolve.
@@ -638,7 +631,7 @@ async function balancesForAddressBulk(req, res, next) {
return res.json(axiosResult)
} catch (err) {
wlogger.error(`Error in slp.js/balancesForAddressBulk().`, err)
wlogger.error('Error in slp.js/balancesForAddressBulk().', err)
// Decode the error message.
const { msg, status } = routeUtils.decodeError(err)
@@ -671,16 +664,16 @@ async function balancesForTokenSingle(req, res, next) {
try {
// Validate the input data.
const tokenId = req.params.tokenId
if (!tokenId || tokenId === "") {
if (!tokenId || tokenId === '') {
res.status(400)
return res.json({ error: "tokenId can not be empty" })
return res.json({ error: 'tokenId can not be empty' })
}
const query = {
v: 3,
q: {
find: {
"tokenDetails.tokenIdHex": tokenId,
'tokenDetails.tokenIdHex': tokenId,
token_balance: { $gte: 0 }
},
limit: 10000,
@@ -689,7 +682,7 @@ async function balancesForTokenSingle(req, res, next) {
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
// Get data from SLPDB.
@@ -705,7 +698,7 @@ async function balancesForTokenSingle(req, res, next) {
})
return res.json(resBalances)
} catch (err) {
wlogger.error(`Error in slp.ts/balancesForTokenSingle().`, err)
wlogger.error('Error in slp.ts/balancesForTokenSingle().', err)
// Decode the error message.
const { msg, status } = routeUtils.decodeError(err)
@@ -738,20 +731,20 @@ async function balancesForAddressByTokenID(req, res, next) {
try {
// Validate input data.
const address = req.params.address
if (!address || address === "") {
if (!address || address === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
const tokenId = req.params.tokenId
if (!tokenId || tokenId === "") {
if (!tokenId || tokenId === '') {
res.status(400)
return res.json({ error: "tokenId can not be empty" })
return res.json({ error: 'tokenId can not be empty' })
}
// Ensure the input is a valid BCH address.
try {
const cash = utils.toCashAddress(address)
bchjs.SLP.Address.toCashAddress(address)
} catch (err) {
res.status(400)
return res.json({
@@ -760,22 +753,23 @@ async function balancesForAddressByTokenID(req, res, next) {
}
// Prevent a common user error. Ensure they are using the correct network address.
const cashAddr = utils.toCashAddress(address)
const cashAddr = bchjs.SLP.Address.toCashAddress(address)
const networkIsValid = routeUtils.validateNetwork(cashAddr)
if (!networkIsValid) {
res.status(400)
return res.json({
error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
error:
'Invalid network. Trying to use a testnet address on mainnet, or vice versa.'
})
}
// Convert input to an simpleledger: address.
const slpAddr = utils.toSlpAddress(req.params.address)
const slpAddr = bchjs.SLP.Address.toSlpAddress(req.params.address)
const query = {
v: 3,
q: {
db: ["a"],
db: ['a'],
find: {
address: slpAddr,
token_balance: { $gte: 0 }
@@ -785,7 +779,7 @@ async function balancesForAddressByTokenID(req, res, next) {
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
// Get data from SLPDB.
@@ -814,7 +808,7 @@ async function balancesForAddressByTokenID(req, res, next) {
}
return res.json(resVal)
} catch (err) {
wlogger.error(`Error in slp.ts/balancesForAddressByTokenID().`, err)
wlogger.error('Error in slp.ts/balancesForAddressByTokenID().', err)
// Decode the error message.
const { msg, status } = routeUtils.decodeError(err)
@@ -847,26 +841,26 @@ async function convertAddressSingle(req, res, next) {
const address = req.params.address
// Validate input
if (!address || address === "") {
if (!address || address === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
const slpAddr = SLP.Address.toSLPAddress(address)
const slpAddr = bchjs.SLP.Address.toSLPAddress(address)
const obj = {
slpAddress: "",
cashAddress: "",
legacyAddress: ""
slpAddress: '',
cashAddress: '',
legacyAddress: ''
}
obj.slpAddress = slpAddr
obj.cashAddress = SLP.Address.toCashAddress(slpAddr)
obj.legacyAddress = SLP.Address.toLegacyAddress(obj.cashAddress)
obj.cashAddress = bchjs.SLP.Address.toCashAddress(slpAddr)
obj.legacyAddress = bchjs.SLP.Address.toLegacyAddress(obj.cashAddress)
res.status(200)
return res.json(obj)
} catch (err) {
wlogger.error(`Error in slp.ts/convertAddressSingle().`, err)
wlogger.error('Error in slp.ts/convertAddressSingle().', err)
const { msg, status } = routeUtils.decodeError(err)
if (msg) {
@@ -899,7 +893,7 @@ async function convertAddressBulk(req, res, next) {
if (!Array.isArray(addresses)) {
res.status(400)
return res.json({
error: "addresses needs to be an array. Use GET for single address."
error: 'addresses needs to be an array. Use GET for single address.'
})
}
@@ -907,7 +901,7 @@ async function convertAddressBulk(req, res, next) {
if (!routeUtils.validateArraySize(req, addresses)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
@@ -917,21 +911,21 @@ async function convertAddressBulk(req, res, next) {
const address = addresses[i]
// Validate input
if (!address || address === "") {
if (!address || address === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
const slpAddr = SLP.Address.toSLPAddress(address)
const slpAddr = bchjs.SLP.Address.toSLPAddress(address)
const obj = {
slpAddress: "",
cashAddress: "",
legacyAddress: ""
slpAddress: '',
cashAddress: '',
legacyAddress: ''
}
obj.slpAddress = slpAddr
obj.cashAddress = SLP.Address.toCashAddress(slpAddr)
obj.legacyAddress = SLP.Address.toLegacyAddress(obj.cashAddress)
obj.cashAddress = bchjs.SLP.Address.toCashAddress(slpAddr)
obj.legacyAddress = bchjs.SLP.Address.toLegacyAddress(obj.cashAddress)
convertedAddresses.push(obj)
}
@@ -959,32 +953,32 @@ async function validateBulk(req, res, next) {
// Reject if txids is not an array.
if (!Array.isArray(txids)) {
res.status(400)
return res.json({ error: "txids needs to be an array" })
return res.json({ error: 'txids needs to be an array' })
}
// Enforce array size rate limits
if (!routeUtils.validateArraySize(req, txids)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
wlogger.debug(`Executing slp/validate with these txids: `, txids)
wlogger.debug('Executing slp/validate with these txids: ', txids)
const query = {
v: 3,
q: {
db: ["c", "u"],
db: ['c', 'u'],
find: {
"tx.h": { $in: txids }
'tx.h': { $in: txids }
},
limit: 300,
project: { "slp.valid": 1, "tx.h": 1, "slp.invalidReason": 1 }
project: { 'slp.valid': 1, 'tx.h': 1, 'slp.invalidReason': 1 }
}
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
const options = generateCredentials()
@@ -1009,8 +1003,9 @@ async function validateBulk(req, res, next) {
}
// If the txid is invalid, add the reason it's invalid.
if (!validationResult.valid)
if (!validationResult.valid) {
validationResult.invalidReason = token.slp.invalidReason
}
formattedTokens.push(validationResult)
})
@@ -1047,7 +1042,7 @@ async function validateBulk(req, res, next) {
res.status(200)
return res.json(formattedTokens)
} catch (err) {
wlogger.error(`Error in slp.ts/validateBulk().`, err)
wlogger.error('Error in slp.ts/validateBulk().', err)
// Attempt to decode the error message.
const { msg, status } = routeUtils.decodeError(err)
@@ -1078,29 +1073,29 @@ async function validateSingle(req, res, next) {
const txid = req.params.txid
// Validate input
if (!txid || txid === "") {
if (!txid || txid === '') {
res.status(400)
return res.json({ error: "txid can not be empty" })
return res.json({ error: 'txid can not be empty' })
}
wlogger.debug(`Executing slp/validate/:txid with this txid: `, txid)
wlogger.debug('Executing slp/validate/:txid with this txid: ', txid)
const query = {
v: 3,
q: {
db: ["c", "u"],
db: ['c', 'u'],
find: {
"tx.h": txid
'tx.h': txid
},
limit: 300,
project: { "slp.valid": 1, "tx.h": 1, "slp.invalidReason": 1 }
project: { 'slp.valid': 1, 'tx.h': 1, 'slp.invalidReason': 1 }
}
}
const options = generateCredentials()
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
// Get data from SLPDB.
@@ -1123,9 +1118,9 @@ async function validateSingle(req, res, next) {
}
res.status(200)
return res.json(tmp)
return res.json(result)
} catch (err) {
wlogger.error(`Error in slp.ts/validateSingle().`, err)
wlogger.error('Error in slp.ts/validateSingle().', err)
// Attempt to decode the error message.
const { msg, status } = routeUtils.decodeError(err)
@@ -1140,10 +1135,10 @@ async function validateSingle(req, res, next) {
}
// Returns a Boolean if the input TXID is a valid SLP TXID.
async function isValidSlpTxid(txid) {
const isValid = await slpValidator.isValidSlpTxid(txid)
return isValid
}
// async function isValidSlpTxid (txid) {
// const isValid = await slpValidator.isValidSlpTxid(txid)
// return isValid
// }
/**
* @api {get} /slp/txDetails/{txid} SLP transaction details.
@@ -1161,29 +1156,29 @@ async function txDetails(req, res, next) {
try {
// Validate input parameter
const txid = req.params.txid
if (!txid || txid === "") {
if (!txid || txid === '') {
res.status(400)
return res.json({ error: "txid can not be empty" })
return res.json({ error: 'txid can not be empty' })
}
if (txid.length !== 64) {
res.status(400)
return res.json({ error: "This is not a txid" })
return res.json({ error: 'This is not a txid' })
}
const query = {
v: 3,
db: ["g"],
db: ['g'],
q: {
find: {
"tx.h": txid
'tx.h': txid
},
limit: 300
}
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
const options = generateCredentials()
@@ -1194,7 +1189,7 @@ async function txDetails(req, res, next) {
if (tokenRes.data.c.length === 0) {
res.status(404)
return res.json({ error: "TXID not found" })
return res.json({ error: 'TXID not found' })
}
// Format the returned data to an object.
@@ -1215,7 +1210,7 @@ async function txDetails(req, res, next) {
res.status(200)
return res.json(response)
} catch (err) {
wlogger.error(`Error in slp.ts/txDetails().`, err)
wlogger.error('Error in slp.ts/txDetails().', err)
// Attempt to decode the error message.
const { msg, status } = routeUtils.decodeError(err)
@@ -1225,9 +1220,9 @@ async function txDetails(req, res, next) {
}
// Handle corner case of mis-typted txid
if (err.error && err.error.indexOf("Not found") > -1) {
if (err.error && err.error.indexOf('Not found') > -1) {
res.status(400)
return res.json({ error: "TXID not found" })
return res.json({ error: 'TXID not found' })
}
res.status(500)
@@ -1249,19 +1244,19 @@ async function txDetails(req, res, next) {
*/
async function tokenStats (req, res, next) {
const tokenId = req.params.tokenId
if (!tokenId || tokenId === "") {
if (!tokenId || tokenId === '') {
res.status(400)
return res.json({ error: "tokenId can not be empty" })
return res.json({ error: 'tokenId can not be empty' })
}
try {
const query = {
v: 3,
q: {
db: ["t"],
db: ['t'],
find: {
$query: {
"tokenDetails.tokenIdHex": tokenId
'tokenDetails.tokenIdHex': tokenId
}
},
project: { tokenDetails: 1, tokenStats: 1, _id: 0 },
@@ -1270,7 +1265,7 @@ async function tokenStats(req, res, next) {
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
// Get data from BitDB.
@@ -1288,7 +1283,7 @@ async function tokenStats(req, res, next) {
res.status(200)
return res.json(formattedTokens[0])
} catch (err) {
wlogger.error(`Error in slp.ts/tokenStats().`, err)
wlogger.error('Error in slp.ts/tokenStats().', err)
const { msg, status } = routeUtils.decodeError(err)
if (msg) {
@@ -1317,46 +1312,46 @@ async function txsTokenIdAddressSingle(req, res, next) {
try {
// Validate the input data.
const tokenId = req.params.tokenId
if (!tokenId || tokenId === "") {
if (!tokenId || tokenId === '') {
res.status(400)
return res.json({ error: "tokenId can not be empty" })
return res.json({ error: 'tokenId can not be empty' })
}
const address = req.params.address
if (!address || address === "") {
if (!address || address === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
const query = {
v: 3,
q: {
find: {
db: ["c", "u"],
db: ['c', 'u'],
$query: {
$or: [
{
"in.e.a": address
'in.e.a': address
},
{
"out.e.a": address
'out.e.a': address
}
],
"slp.detail.tokenIdHex": tokenId
'slp.detail.tokenIdHex': tokenId
},
$orderby: {
"blk.i": -1
'blk.i': -1
}
},
limit: 100
},
r: {
f: "[.[] | { txid: .tx.h, tokenDetails: .slp } ]"
f: '[.[] | { txid: .tx.h, tokenDetails: .slp } ]'
}
}
const s = JSON.stringify(query)
const b64 = Buffer.from(s).toString("base64")
const b64 = Buffer.from(s).toString('base64')
const url = `${process.env.SLPDB_URL}q/${b64}`
// Get data from SLPDB.
@@ -1365,7 +1360,7 @@ async function txsTokenIdAddressSingle(req, res, next) {
return res.json(tokenRes.data.c)
} catch (err) {
wlogger.error(`Error in slp.ts/txsTokenIdAddressSingle().`, err)
wlogger.error('Error in slp.ts/txsTokenIdAddressSingle().', err)
// Decode the error message.
const { msg, status } = routeUtils.decodeError(err)
@@ -1384,10 +1379,10 @@ async function txsTokenIdAddressSingle(req, res, next) {
// Generates a Basic Authorization header for slpserve.
function generateCredentials () {
// Generate the Basic Authentication header for a private instance of SLPDB.
const username = "BITBOX"
const username = 'BITBOX'
const password = SLPDB_PASS
const combined = `${username}:${password}`
var base64Credential = Buffer.from(combined).toString("base64")
var base64Credential = Buffer.from(combined).toString('base64')
var readyCredential = `Basic ${base64Credential}`
const options = {
@@ -1409,12 +1404,12 @@ async function formatToRestObject(slpDBFormat) {
? slpDBFormat.data.u[0]
: slpDBFormat.data.c[0]
const inputs = transaction.in
// const inputs = transaction.in
const outputs = transaction.out
// const outputs = transaction.out
const tokenOutputs = transaction.slp.detail.outputs
const sendOutputs = ["0"]
const sendOutputs = ['0']
tokenOutputs.map(x => {
const string = parseFloat(x.amount) * 100000000
sendOutputs.push(string.toString())
@@ -1446,7 +1441,7 @@ module.exports = {
convertAddressSingle,
convertAddressBulk,
validateBulk,
isValidSlpTxid,
// isValidSlpTxid,
txDetails,
tokenStats,
balancesForTokenSingle,
+85 -78
View File
@@ -1,37 +1,37 @@
"use strict"
'use strict'
const express = require("express")
const express = require('express')
const router = express.Router()
const axios = require("axios")
const axios = require('axios')
const routeUtils = require("./route-utils")
const wlogger = require("../../util/winston-logging")
const blockbook = require("./blockbook")
const routeUtils = require('./route-utils')
const wlogger = require('../../util/winston-logging')
const blockbook = require('./blockbook')
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const BCHJS = require("@chris.troutner/bch-js")
const BCHJS = require('@chris.troutner/bch-js')
const bchjs = new BCHJS()
const BCHJS_TESTNET = `https://testnet.bchjs.cash/v3/`
// const BCHJS_TESTNET = 'https://testnet.bchjs.cash/v3/'
const bchjsHTTP = axios.create({
baseURL: process.env.RPC_BASEURL
})
// const bchjsHTTP = axios.create({
// baseURL: process.env.RPC_BASEURL
// })
const username = process.env.RPC_USERNAME
const password = process.env.RPC_PASSWORD
// const username = process.env.RPC_USERNAME
// const password = process.env.RPC_PASSWORD
const requestConfig = {
method: "post",
auth: {
username: username,
password: password
},
data: {
jsonrpc: "1.0"
}
}
// const requestConfig = {
// method: 'post',
// auth: {
// username: username,
// password: password
// },
// data: {
// jsonrpc: '1.0'
// }
// }
let _this
@@ -44,7 +44,7 @@ class UtilRoute {
}
root (req, res, next) {
return res.json({ status: "util" })
return res.json({ status: 'util' })
}
/**
@@ -62,20 +62,20 @@ class UtilRoute {
async validateAddressSingle (req, res, next) {
try {
const address = req.params.address
if (!address || address === "") {
if (!address || address === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
requestConfig.data.id = "validateaddress"
requestConfig.data.method = "validateaddress"
requestConfig.data.id = 'validateaddress'
requestConfig.data.method = 'validateaddress'
requestConfig.data.params = [address]
const response = await BitboxHTTP(requestConfig)
@@ -89,7 +89,7 @@ class UtilRoute {
return res.json({ error: msg })
}
wlogger.error(`Error in util.ts/validateAddressSingle().`, err)
wlogger.error('Error in util.ts/validateAddressSingle().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -117,7 +117,7 @@ class UtilRoute {
if (!Array.isArray(addresses)) {
res.status(400)
return res.json({
error: "addresses needs to be an array. Use GET for single address."
error: 'addresses needs to be an array. Use GET for single address.'
})
}
@@ -125,7 +125,7 @@ class UtilRoute {
if (!routeUtils.validateArraySize(req, addresses)) {
res.status(429) // https://github.com/Bitcoin-com/rest.bitcoin.com/issues/330
return res.json({
error: `Array too large.`
error: 'Array too large.'
})
}
@@ -135,7 +135,7 @@ class UtilRoute {
// Ensure the input is a valid BCH address.
try {
var legacyAddr = bchjs.Address.toLegacyAddress(address)
bchjs.Address.toLegacyAddress(address)
} catch (err) {
res.status(400)
return res.json({
@@ -148,27 +148,28 @@ class UtilRoute {
if (!networkIsValid) {
res.status(400)
return res.json({
error: `Invalid network. Trying to use a testnet address on mainnet, or vice versa.`
error:
'Invalid network. Trying to use a testnet address on mainnet, or vice versa.'
})
}
}
wlogger.debug(`Executing util/validate with these addresses: `, addresses)
wlogger.debug('Executing util/validate with these addresses: ', addresses)
const {
BitboxHTTP,
username,
password,
// username,
// password,
requestConfig
} = routeUtils.setEnvVars()
// Loop through each address and creates an array of requests to call in parallel
const promises = addresses.map(async address => {
requestConfig.data.id = "validateaddress"
requestConfig.data.method = "validateaddress"
requestConfig.data.id = 'validateaddress'
requestConfig.data.method = 'validateaddress'
requestConfig.data.params = [address]
return await BitboxHTTP(requestConfig)
return BitboxHTTP(requestConfig)
})
// Wait for all parallel Insight requests to return.
@@ -187,7 +188,7 @@ class UtilRoute {
return res.json({ error: msg })
}
wlogger.error(`Error in util.ts/validateAddressSingle().`, err)
wlogger.error('Error in util.ts/validateAddressSingle().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
@@ -219,22 +220,22 @@ class UtilRoute {
const toAddr = req.body.toAddr
const balanceOnly = req.body.balanceOnly
if (typeof wif !== "string" || wif.length !== 52) {
if (typeof wif !== 'string' || wif.length !== 52) {
res.status(400)
return res.json({
error: "WIF needs to a proper compressed WIF starting with K or L"
error: 'WIF needs to a proper compressed WIF starting with K or L'
})
}
if (!balanceOnly) {
// Only throw error if balanceOnly is false or undefined.
if (!toAddr || toAddr === "") {
if (!toAddr || toAddr === '') {
res.status(400)
return res.json({ error: "address can not be empty" })
return res.json({ error: 'address can not be empty' })
}
}
wlogger.debug(`Executing util/sweepWif with this address: `, toAddr)
wlogger.debug('Executing util/sweepWif with this address: ', toAddr)
// Generate a private and public key pair from the WIF.
const ecPair = bchjs.ECPair.fromWIF(wif)
@@ -253,7 +254,7 @@ class UtilRoute {
// Exit if balance is zero.
if (isNaN(totalBalance) || totalBalance === 0) {
res.status(422)
return res.json({ error: "No balance found at BCH address." })
return res.json({ error: 'No balance found at BCH address.' })
}
// Exit if this is a balance-only call.
@@ -274,7 +275,7 @@ class UtilRoute {
// Exit if there are no UTXOs.
if (utxos.length === 0) {
res.status(422)
return res.json({ error: "No utxos found." })
return res.json({ error: 'No utxos found.' })
}
// Figure out which UTXOs are associated with SLP tokens.
@@ -295,7 +296,8 @@ class UtilRoute {
if (bchUtxos.length === 0 && tokenUtxos.length > 0) {
res.status(422)
return res.json({
error: `Tokens found, but no BCH UTXOs found. Add BCH to wallet to move tokens.`
error:
'Tokens found, but no BCH UTXOs found. Add BCH to wallet to move tokens.'
})
}
@@ -337,14 +339,14 @@ class UtilRoute {
// Catch the specific case of multiple tokens.
if (
err.message &&
err.message.indexOf("Multiple token classes detected") > -1
err.message.indexOf('Multiple token classes detected') > -1
) {
res.status(422)
return res.json({ error: err.message })
}
wlogger.error(`Error in util.js/sweepWif().`, err)
console.error(`Error in util.js/sweepWif().`, err)
wlogger.error('Error in util.js/sweepWif().', err)
console.error('Error in util.js/sweepWif().', err)
res.status(500)
return res.json({ error: err.message })
@@ -377,9 +379,9 @@ class UtilRoute {
// instance of transaction builder
let transactionBuilder
if (options.testnet)
transactionBuilder = new _this.bchjs.TransactionBuilder("testnet")
else transactionBuilder = new _this.bchjs.TransactionBuilder()
if (options.testnet) {
transactionBuilder = new _this.bchjs.TransactionBuilder('testnet')
} else transactionBuilder = new _this.bchjs.TransactionBuilder()
let originalAmount = 0
@@ -394,7 +396,7 @@ class UtilRoute {
if (originalAmount < 546) {
throw new Error(
`Original amount less than the dust limit. Not enough BCH to send.`
'Original amount less than the dust limit. Not enough BCH to send.'
)
}
@@ -435,7 +437,7 @@ class UtilRoute {
const hex = tx.toHex()
return hex
} catch (err) {
wlogger.error(`Error in util.js/sweepBCH().`)
wlogger.error('Error in util.js/sweepBCH().')
throw err
}
}
@@ -443,13 +445,16 @@ class UtilRoute {
// Sweep BCH and tokens from a WIF.
async _sweepTokens (options) {
try {
const { ecPair, utxos, fromAddr, toAddr, bchUtxos, tokenUtxos } = options
// const { ecPair, utxos, fromAddr, toAddr, bchUtxos, tokenUtxos } = options
const { ecPair, utxos, toAddr, bchUtxos, tokenUtxos } = options
// Input validation
if (!Array.isArray(bchUtxos) || bchUtxos.length === 0)
throw new Error(`bchUtxos need to be an array with one UTXO.`)
if (!Array.isArray(tokenUtxos) || tokenUtxos.length === 0)
throw new Error(`tokenUtxos need to be an array with one UTXO.`)
if (!Array.isArray(bchUtxos) || bchUtxos.length === 0) {
throw new Error('bchUtxos need to be an array with one UTXO.')
}
if (!Array.isArray(tokenUtxos) || tokenUtxos.length === 0) {
throw new Error('tokenUtxos need to be an array with one UTXO.')
}
// if (flags.testnet)
// this.BITBOX = new config.BCHLIB({ restURL: config.TESTNET_REST })
@@ -462,15 +467,15 @@ class UtilRoute {
const otherTokens = tokenUtxos.filter(x => x.tokenId !== tokenId)
if (otherTokens.length > 0) {
throw new Error(
`Multiple token classes detected. This function only supports a single class of token.`
'Multiple token classes detected. This function only supports a single class of token.'
)
}
// instance of transaction builder
let transactionBuilder
if (options.testnet)
transactionBuilder = new _this.bchjs.TransactionBuilder("testnet")
else transactionBuilder = new _this.bchjs.TransactionBuilder()
if (options.testnet) {
transactionBuilder = new _this.bchjs.TransactionBuilder('testnet')
} else transactionBuilder = new _this.bchjs.TransactionBuilder()
// Combine all the UTXOs into a single array.
const allUtxos = utxos
@@ -488,7 +493,7 @@ class UtilRoute {
if (originalAmount < 300) {
throw new Error(
`Not enough BCH to send. Send more BCH to the wallet to pay miner fees.`
'Not enough BCH to send. Send more BCH to the wallet to pay miner fees.'
)
}
@@ -506,14 +511,16 @@ class UtilRoute {
// amount to send back to the sending address. It's the original amount - 1 sat/byte for tx size
const remainder = originalAmount - txFee - 546
if (remainder < 1)
throw new Error(`Selected UTXO does not have enough satoshis`)
if (remainder < 1) {
throw new Error('Selected UTXO does not have enough satoshis')
}
// console.log(`remainder: ${remainder}`)
// Tally up the quantity of tokens
let tokenQty = 0
for (let i = 0; i < tokenUtxos.length; i++)
for (let i = 0; i < tokenUtxos.length; i++) {
tokenQty += tokenUtxos[i].tokenQty
}
// console.log(`tokenQty: ${tokenQty}`)
// Generate the OP_RETURN entry for an SLP SEND transaction.
@@ -529,7 +536,7 @@ class UtilRoute {
// is something unexpected happening.
if (outputs > 1) {
throw new Error(
`More than one class of token detected. Sweep feature not supported.`
'More than one class of token detected. Sweep feature not supported.'
)
}
@@ -575,7 +582,7 @@ class UtilRoute {
return hex
} catch (err) {
wlogger.error(`Error in util.js/sweepBCH().`)
wlogger.error('Error in util.js/sweepBCH().')
throw err
}
}
@@ -583,10 +590,10 @@ class UtilRoute {
const utilRoute = new UtilRoute()
router.get("/", utilRoute.root)
router.get("/validateAddress/:address", utilRoute.validateAddressSingle)
router.post("/validateAddress", utilRoute.validateAddressBulk)
router.post("/sweep", utilRoute.sweepWif)
router.get('/', utilRoute.root)
router.get('/validateAddress/:address', utilRoute.validateAddressSingle)
router.post('/validateAddress', utilRoute.validateAddressBulk)
router.post('/sweep', utilRoute.sweepWif)
module.exports = {
router,
+16 -16
View File
@@ -2,51 +2,51 @@
xpub route
*/
"use strict"
'use strict'
const express = require("express")
const axios = require("axios")
const routeUtils = require("./route-utils")
const wlogger = require("../../util/winston-logging")
const express = require('express')
// const axios = require('axios')
const routeUtils = require('./route-utils')
const wlogger = require('../../util/winston-logging')
// const router = express.Router()
const router = express.Router()
// Used for processing error messages before sending them to the user.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const BCHJS = require("@chris.troutner/bch-js")
const BCHJS = require('@chris.troutner/bch-js')
const bchjs = new BCHJS()
// Connect the route endpoints to their handler functions.
router.get("/", root)
router.get("/fromXPub/:xpub", fromXPubSingle)
router.get('/', root)
router.get('/fromXPub/:xpub', fromXPubSingle)
// Root API endpoint. Simply acknowledges that it exists.
function root (req, res, next) {
return res.json({ status: "address" })
return res.json({ status: 'address' })
}
async function fromXPubSingle (req, res, next) {
try {
const xpub = req.params.xpub
const hdPath = req.query.hdPath ? req.query.hdPath : "0"
const hdPath = req.query.hdPath ? req.query.hdPath : '0'
if (!xpub || xpub === "") {
if (!xpub || xpub === '') {
res.status(400)
return res.json({ error: "xpub can not be empty" })
return res.json({ error: 'xpub can not be empty' })
}
// Reject if xpub is an array.
if (Array.isArray(xpub)) {
res.status(400)
return res.json({
error: "xpub can not be an array. Use POST for bulk upload."
error: 'xpub can not be an array. Use POST for bulk upload.'
})
}
wlogger.debug(`Executing address/fromXPub with this xpub: `, xpub)
wlogger.debug('Executing address/fromXPub with this xpub: ', xpub)
const cashAddr = bchjs.Address.fromXPub(xpub, hdPath)
const legacyAddr = bchjs.Address.toLegacyAddress(cashAddr)
@@ -64,7 +64,7 @@ async function fromXPubSingle(req, res, next) {
}
// Write out error to error log.
wlogger.error(`Error in address.ts/fromXPubSingle().`, err)
wlogger.error('Error in address.ts/fromXPubSingle().', err)
res.status(500)
return res.json({ error: util.inspect(err) })
+8 -8
View File
@@ -8,7 +8,7 @@
Blockbook.
*/
"use strict"
'use strict'
class BlockbookPath {
constructor () {
@@ -19,14 +19,14 @@ class BlockbookPath {
}
toOpenBazaar () {
if (process.env.NETWORK === "testnet") {
this.addrPath = `https://tbch.blockbook.api.openbazaar.org/api/address/`
this.utxoPath = `https://tbch.blockbook.api.openbazaar.org/api/utxo/`
this.txPath = `https://tbch.blockbook.api.openbazaar.org/api/tx/`
if (process.env.NETWORK === 'testnet') {
this.addrPath = 'https://tbch.blockbook.api.openbazaar.org/api/address/'
this.utxoPath = 'https://tbch.blockbook.api.openbazaar.org/api/utxo/'
this.txPath = 'https://tbch.blockbook.api.openbazaar.org/api/tx/'
} else {
this.addrPath = `https://bch.blockbook.api.openbazaar.org/api/address/`
this.utxoPath = `https://bch.blockbook.api.openbazaar.org/api/utxo/`
this.txPath = `https://bch.blockbook.api.openbazaar.org/api/tx/`
this.addrPath = 'https://bch.blockbook.api.openbazaar.org/api/address/'
this.utxoPath = 'https://bch.blockbook.api.openbazaar.org/api/utxo/'
this.txPath = 'https://bch.blockbook.api.openbazaar.org/api/tx/'
}
}
+9 -9
View File
@@ -4,33 +4,33 @@
logging library.
*/
"use strict"
'use strict'
var winston = require("winston")
require("winston-daily-rotate-file")
var winston = require('winston')
require('winston-daily-rotate-file')
var NETWORK = process.env.NETWORK
// Configure daily-rotation transport.
var transport = new winston.transports.DailyRotateFile({
filename: `${__dirname}/../../logs/rest-${NETWORK}-%DATE%.log`,
datePattern: "YYYY-MM-DD",
datePattern: 'YYYY-MM-DD',
zippedArchive: false,
maxSize: "1m",
maxFiles: "5d",
maxSize: '1m',
maxFiles: '5d',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
)
})
transport.on("rotate", function(oldFilename, newFilename) {
wlogger.info("Rotating log files")
transport.on('rotate', function (oldFilename, newFilename) {
wlogger.info('Rotating log files')
})
// This controls what goes into the log FILES
var wlogger = winston.createLogger({
level: "verbose",
level: 'verbose',
format: winston.format.json(),
transports: [
//
+285 -285
View File
File diff suppressed because it is too large Load Diff
+536 -536
View File
File diff suppressed because it is too large Load Diff
+38 -38
View File
@@ -7,24 +7,24 @@
*/
"use strict"
'use strict'
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const controlRoute = require("../../src/routes/v3/full-node/control")
const nock = require("nock") // HTTP mocking
const controlRoute = require('../../src/routes/v3/full-node/control')
const nock = require('nock') // HTTP mocking
let originalEnvVars // Used during transition from integration to unit tests.
// Mocking data.
const { mockReq, mockRes } = require("./mocks/express-mocks")
const mockData = require("./mocks/control-mock")
const { mockReq, mockRes } = require('./mocks/express-mocks')
const mockData = require('./mocks/control-mock')
// Used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
describe("#ControlRouter", () => {
describe('#ControlRouter', () => {
let req, res
before(() => {
@@ -37,12 +37,12 @@ describe("#ControlRouter", () => {
}
// Set default environment variables for unit tests.
if (!process.env.TEST) process.env.TEST = "unit"
if (process.env.TEST === "unit") {
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
process.env.RPC_BASEURL = "http://fakeurl/api"
process.env.RPC_USERNAME = "fakeusername"
process.env.RPC_PASSWORD = "fakepassword"
if (!process.env.TEST) process.env.TEST = 'unit'
if (process.env.TEST === 'unit') {
process.env.BITCOINCOM_BASEURL = 'http://fakeurl/api/'
process.env.RPC_BASEURL = 'http://fakeurl/api'
process.env.RPC_USERNAME = 'fakeusername'
process.env.RPC_PASSWORD = 'fakepassword'
}
})
@@ -75,29 +75,29 @@ describe("#ControlRouter", () => {
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
})
describe("#root", async () => {
describe('#root', async () => {
// root route handler.
const root = controlRoute.testableComponents.root
it("should respond to GET for base route", async () => {
it('should respond to GET for base route', async () => {
const result = root(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(result.status, "control", "Returns static string")
assert.equal(result.status, 'control', 'Returns static string')
})
})
describe("#GetNetworkInfo", () => {
describe('#GetNetworkInfo', () => {
const getNetworkInfo = controlRoute.testableComponents.getNetworkInfo
it("should throw 500 when network issues", async () => {
it('should throw 500 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = "http://fakeurl/api/"
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await getNetworkInfo(req, res)
await getNetworkInfo(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Restore the saved URL.
@@ -106,16 +106,16 @@ describe("#ControlRouter", () => {
assert.isAbove(
res.statusCode,
499,
"HTTP status code 500 or greater expected."
'HTTP status code 500 or greater expected.'
)
// assert.include(result.error, "ENOTFOUND", "Error message expected")
})
it("should get info on the full node", async () => {
it('should get info on the full node', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.RPC_BASEURL}`)
.post(uri => uri.includes("/"))
.post(uri => uri.includes('/'))
.reply(200, { result: mockData.mockGetNetworkInfo })
}
@@ -123,19 +123,19 @@ describe("#ControlRouter", () => {
// console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
"version",
"subversion",
"protocolversion",
"localservices",
"localrelay",
"timeoffset",
"networkactive",
"connections",
"networks",
"relayfee",
"excessutxocharge",
"localaddresses",
"warnings"
'version',
'subversion',
'protocolversion',
'localservices',
'localrelay',
'timeoffset',
'networkactive',
'connections',
'networks',
'relayfee',
'excessutxocharge',
'localaddresses',
'warnings'
])
})
})
+10 -10
View File
@@ -3,11 +3,11 @@
These tests assume that the repo is running locally and pointed at TESTNET
*/
"use strict"
'use strict'
const rp = require("request-promise")
const rp = require('request-promise')
const rawtransactions = require("../../../dist/routes/v2/address")
// const rawtransactions = require('../../../dist/routes/v2/address')
/*
This unconfirmed utxo test needs to be expanded in the future to automatically
@@ -19,19 +19,19 @@ const rawtransactions = require("../../../dist/routes/v2/address")
3. Run this program with `node address.js`
4. If successful, it will return the unconfirmed UTXOs.
*/
const addr1 = "bchtest:qpdcp5pv7qphu5tsjfgwezld9n9aq9ue6swgqpf45c"
const addr2 = "bchtest:qzpvx999fagau0xqmvu3xvll9evapge7u5hcgeknzv"
const addr1 = 'bchtest:qpdcp5pv7qphu5tsjfgwezld9n9aq9ue6swgqpf45c'
const addr2 = 'bchtest:qzpvx999fagau0xqmvu3xvll9evapge7u5hcgeknzv'
async function testSingleUnconfirmed () {
try {
const options = {
method: "GET",
method: 'GET',
uri: `http://localhost:3000/v2/address/unconfirmed/${addr1}`,
resolveWithFullResponse: true,
json: true
}
const result = await rp(options)
await rp(options)
// console.log(`result.body: ${JSON.stringify(result.body, null, 2)}`)
} catch (err) {
// console.log(`Error: `, err)
@@ -42,8 +42,8 @@ testSingleUnconfirmed()
async function testDoubleUnconfirmed () {
try {
const options = {
method: "POST",
uri: `http://localhost:3000/v2/address/unconfirmed`,
method: 'POST',
uri: 'http://localhost:3000/v2/address/unconfirmed',
resolveWithFullResponse: true,
json: true,
body: {
@@ -51,7 +51,7 @@ async function testDoubleUnconfirmed() {
}
}
const result = await rp(options)
await rp(options)
// console.log(`result.body: ${JSON.stringify(result.body, null, 2)}`)
} catch (err) {
// console.log(`Error: `, err)
+3 -3
View File
@@ -1,9 +1,9 @@
"use strict"
'use strict'
/**
* Read more about panda here: https://panda-suite.github.io/
*/
const panda = require("pandacash-core")
const panda = require('pandacash-core')
const runLocalNode = done => {
const server = panda.server({
@@ -16,7 +16,7 @@ const runLocalNode = done => {
server.listen({
port: 48332,
walletPort: 48333,
walletPort: 48333
}, (err, pandaCashCore) => {
if (err) return console.error(err)
+32 -32
View File
@@ -4,26 +4,26 @@
in the tests below to match the rate limit setting in your own installation.
*/
"use strict"
'use strict'
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const axios = require("axios")
const axios = require('axios')
// Used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
// const SERVER = `http://192.168.0.36:12400/v3/`
const SERVER = `http://localhost:3000/v3/`
const SERVER = 'http://localhost:3000/v3/'
const TEST_JWT =
"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlM2EwNDE1ZWIyOWE5NjJkYTI3MDhiNCIsImFwaUxldmVsIjowLCJyYXRlTGltaXQiOjEwLCJpYXQiOjE1ODA4NjA0NjcsImV4cCI6MTU4MzQ1MjQ2N30.fuY5S-YrF0J11h5uyMjPe7wiVkYRnIyXi4dL9-V-C6pLJm33p0dSq_pSheVVWw78n5kAvL_9kFHngbnmQiOJYQ"
'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlM2EwNDE1ZWIyOWE5NjJkYTI3MDhiNCIsImFwaUxldmVsIjowLCJyYXRlTGltaXQiOjEwLCJpYXQiOjE1ODA4NjA0NjcsImV4cCI6MTU4MzQ1MjQ2N30.fuY5S-YrF0J11h5uyMjPe7wiVkYRnIyXi4dL9-V-C6pLJm33p0dSq_pSheVVWw78n5kAvL_9kFHngbnmQiOJYQ'
describe("#rate limits", () => {
it("should get control/getNetworkInfo() with no auth", async () => {
describe('#rate limits', () => {
it('should get control/getNetworkInfo() with no auth', async () => {
const options = {
method: "GET",
method: 'GET',
url: `${SERVER}control/getNetworkInfo`
}
@@ -32,14 +32,14 @@ describe("#rate limits", () => {
// console.log(`result.data: ${util.inspect(result.data)}`)
assert.equal(result.status, 200)
assert.hasAnyKeys(result.data, ["version"])
assert.hasAnyKeys(result.data, ['version'])
})
it("should trigger rate-limit handler if rate limits exceeds 30 request per minute", async () => {
it('should trigger rate-limit handler if rate limits exceeds 30 request per minute', async () => {
try {
// Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
const options = {
method: "GET",
method: 'GET',
url: `${SERVER}control/getNetworkInfo`
}
@@ -51,29 +51,29 @@ describe("#rate limits", () => {
await Promise.all(promises)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err.response: ${util.inspect(err.response)}`)
assert.equal(err.response.status, 429)
assert.include(err.response.data.error, "Too many requests")
assert.include(err.response.data.error, 'Too many requests')
}
})
it("should not trigger rate-limit handler if correct pro-tier password is used", async () => {
it('should not trigger rate-limit handler if correct pro-tier password is used', async () => {
try {
const username = "BITBOX"
const username = 'BITBOX'
// Pro-tier is accessed by using the right password.
const password = "BITBOX"
const password = 'BITBOX'
// const password = "something"
const combined = `${username}:${password}`
const base64Credential = Buffer.from(combined).toString("base64")
const base64Credential = Buffer.from(combined).toString('base64')
const readyCredential = `Basic ${base64Credential}`
const options = {
method: "GET",
method: 'GET',
url: `${SERVER}control/getNetworkInfo`,
headers: { Authorization: readyCredential }
}
@@ -86,33 +86,33 @@ describe("#rate limits", () => {
await Promise.all(promises)
assert.equal(true, true, "Not throwing an error is a pass!")
assert.equal(true, true, 'Not throwing an error is a pass!')
} catch (err) {
// console.log(`err.response: ${util.inspect(err.response)}`)
assert.equal(
true,
false,
"This error handler should not have been triggered. Is the password correct?"
'This error handler should not have been triggered. Is the password correct?'
)
}
})
it("should trigger rate-limit handler if rate limits exceeds pro-tier limit", async () => {
it('should trigger rate-limit handler if rate limits exceeds pro-tier limit', async () => {
try {
const username = "BITBOX"
const username = 'BITBOX'
// Pro-tier is accessed by using the right password.
const password = "BITBOX"
const password = 'BITBOX'
// const password = "something"
const combined = `${username}:${password}`
const base64Credential = Buffer.from(combined).toString("base64")
const base64Credential = Buffer.from(combined).toString('base64')
const readyCredential = `Basic ${base64Credential}`
// Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
const options = {
method: "GET",
method: 'GET',
url: `${SERVER}control/getNetworkInfo`,
headers: { Authorization: readyCredential }
}
@@ -125,20 +125,20 @@ describe("#rate limits", () => {
await Promise.all(promises)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err.response: ${util.inspect(err.response)}`)
assert.equal(err.response.status, 429)
assert.include(err.response.data.error, "Too many requests")
assert.include(err.response.data.error, 'Too many requests')
}
})
it("should unlock pro-tier for a valid JWT token", async () => {
it('should unlock pro-tier for a valid JWT token', async () => {
try {
// Actual rate limit is 60 per minute X 4 nodes = 240 rpm.
const options = {
method: "GET",
method: 'GET',
url: `${SERVER}control/`,
headers: {
Authorization: `Token ${TEST_JWT}`
@@ -154,11 +154,11 @@ describe("#rate limits", () => {
await Promise.all(promises)
// assert.equal(true, false, "Unexpected result!")
assert.equal(true, true, "Not throwing an error is a pass!")
assert.equal(true, true, 'Not throwing an error is a pass!')
} catch (err) {
console.log(`err.response: ${util.inspect(err.response)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
}
// Override default timeout for this test.
}).timeout(20000)
+49 -49
View File
@@ -9,25 +9,25 @@
so it is omitted here.
*/
"use strict"
'use strict'
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const rawtransactions = require("../../../dist/routes/v2/rawtransactions")
const rp = require("request-promise")
// const rawtransactions = require('../../../dist/routes/v2/rawtransactions')
const rp = require('request-promise')
// Used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const mockData = require("../mocks/raw-transactions-mocks")
// const mockData = require('../mocks/raw-transactions-mocks')
describe("#Raw-Transactions", () => {
describe("#root", () => {
it(`should return root`, async () => {
describe('#Raw-Transactions', () => {
describe('#root', () => {
it('should return root', async () => {
const options = {
method: "GET",
uri: `http://localhost:3000/v2/rawtransactions/`,
method: 'GET',
uri: 'http://localhost:3000/v2/rawtransactions/',
resolveWithFullResponse: true,
json: true
}
@@ -35,21 +35,21 @@ describe("#Raw-Transactions", () => {
const result = await rp(options)
// console.log(`result: ${JSON.stringify(result, null, 0)}`)
assert.equal(result.body.status, "rawtransactions")
assert.equal(result.body.status, 'rawtransactions')
})
})
describe("#whCreateTx", () => {
it(`should return tx hex`, async () => {
describe('#whCreateTx', () => {
it('should return tx hex', async () => {
const minIn = {
txid:
"f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2",
'f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2',
vout: 1
}
const options = {
method: "PUT",
uri: `http://localhost:3000/v2/rawtransactions/create`,
method: 'PUT',
uri: 'http://localhost:3000/v2/rawtransactions/create',
resolveWithFullResponse: true,
json: true,
body: {
@@ -64,21 +64,21 @@ describe("#Raw-Transactions", () => {
assert.equal(
result.body,
"0200000001b29af9aaf74f82ad7ff181fcc6f3d2cf5fa701a1c969620f9185ee3df29cedf70100000000ffffffff0000000000"
'0200000001b29af9aaf74f82ad7ff181fcc6f3d2cf5fa701a1c969620f9185ee3df29cedf70100000000ffffffff0000000000'
)
})
})
describe("#whOpReturn", () => {
it(`should return tx hex`, async () => {
describe('#whOpReturn', () => {
it('should return tx hex', async () => {
const options = {
method: "PUT",
uri: `http://localhost:3000/v2/rawtransactions/opreturn`,
method: 'PUT',
uri: 'http://localhost:3000/v2/rawtransactions/opreturn',
resolveWithFullResponse: true,
json: true,
body: {
rawtx: "01000000000000000000",
payload: "00000000000000020000000006dac2c0"
rawtx: '01000000000000000000',
payload: '00000000000000020000000006dac2c0'
}
}
@@ -87,22 +87,22 @@ describe("#Raw-Transactions", () => {
assert.equal(
result.body,
"0100000000010000000000000000166a140877686300000000000000020000000006dac2c000000000"
'0100000000010000000000000000166a140877686300000000000000020000000006dac2c000000000'
)
})
})
describe("#whReference", () => {
it(`should return tx hex`, async () => {
describe('#whReference', () => {
it('should return tx hex', async () => {
const options = {
method: "PUT",
uri: `http://localhost:3000/v2/rawtransactions/reference`,
method: 'PUT',
uri: 'http://localhost:3000/v2/rawtransactions/reference',
resolveWithFullResponse: true,
json: true,
body: {
rawtx:
"0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff03aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a5121f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000",
destination: "bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf",
'0100000001a7a9402ecd77f3c9f745793c9ec805bfa2e14b89877581c734c774864247e6f50400000000ffffffff03aa0a0000000000001976a9146d18edfe073d53f84dd491dae1379f8fb0dfe5d488ac5c0d0000000000004751210252ce4bdd3ce38b4ebbc5a6e1343608230da508ff12d23d85b58c964204c4cef3210294cc195fc096f87d0f813a337ae7e5f961b1c8a18f1f8604a909b3a5121f065b52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000',
destination: 'bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf',
amount: 0.005
}
}
@@ -114,24 +114,24 @@ describe("#Raw-Transactions", () => {
})
})
describe("#whChangeOutput", () => {
it(`should return tx hex`, async () => {
describe('#whChangeOutput', () => {
it('should return tx hex', async () => {
const options = {
method: "PUT",
uri: `http://localhost:3000/v2/rawtransactions/change`,
method: 'PUT',
uri: 'http://localhost:3000/v2/rawtransactions/change',
resolveWithFullResponse: true,
json: true,
body: {
rawtx:
"0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff025c0d00000000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000",
destination: "bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf",
'0100000001b15ee60431ef57ec682790dec5a3c0d83a0c360633ea8308fbf6d5fc10a779670400000000ffffffff025c0d00000000000047512102f3e471222bb57a7d416c82bf81c627bfcd2bdc47f36e763ae69935bba4601ece21021580b888ff56feb27f17f08802ebed26258c23697d6a462d43fc13b565fda2dd52aeaa0a0000000000001976a914946cb2e08075bcbaf157e47bcb67eb2b2339d24288ac00000000',
destination: 'bitcoincash:qrn60nerx5zug4u4hal06atep3lzhtecvy4pxk75lf',
prevtxs: [
{
txid:
"6779a710fcd5f6fb0883ea3306360c3ad8c0a3c5de902768ec57ef3104e65eb1",
'6779a710fcd5f6fb0883ea3306360c3ad8c0a3c5de902768ec57ef3104e65eb1',
vout: 4,
scriptPubKey:
"76a9147b25205fd98d462880a3e5b0541235831ae959e588ac",
'76a9147b25205fd98d462880a3e5b0541235831ae959e588ac',
value: 0.00068257
}
],
@@ -146,16 +146,16 @@ describe("#Raw-Transactions", () => {
})
})
describe("#whInput", () => {
it(`should return tx hex`, async () => {
describe('#whInput', () => {
it('should return tx hex', async () => {
const options = {
method: "PUT",
uri: `http://localhost:3000/v2/rawtransactions/input`,
method: 'PUT',
uri: 'http://localhost:3000/v2/rawtransactions/input',
resolveWithFullResponse: true,
json: true,
body: {
txid:
"b006729017df05eda586df9ad3f8ccfee5be340aadf88155b784d1fc0e8342ee",
'b006729017df05eda586df9ad3f8ccfee5be340aadf88155b784d1fc0e8342ee',
n: 0
}
}
@@ -167,16 +167,16 @@ describe("#Raw-Transactions", () => {
})
})
describe("#getRawTransaction", () => {
it(`should return tx hex`, async () => {
describe('#getRawTransaction', () => {
it('should return tx hex', async () => {
const options = {
method: "POST",
uri: `http://localhost:3000/v2/rawtransactions/getRawTransaction`,
method: 'POST',
uri: 'http://localhost:3000/v2/rawtransactions/getRawTransaction',
resolveWithFullResponse: true,
json: true,
body: {
txids: [
"0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"
'0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098'
],
verbose: true
}
+42 -42
View File
@@ -6,24 +6,24 @@
to 'integration' to run the tests against BCH mainnet.
*/
"use strict"
'use strict'
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const miningRoute = require("../../src/routes/v3/full-node/mining")
const nock = require("nock") // HTTP mocking
const miningRoute = require('../../src/routes/v3/full-node/mining')
const nock = require('nock') // HTTP mocking
let originalEnvVars // Used during transition from integration to unit tests.
// Mocking data.
const { mockReq, mockRes } = require("./mocks/express-mocks")
const mockData = require("./mocks/mining-mocks")
const { mockReq, mockRes } = require('./mocks/express-mocks')
const mockData = require('./mocks/mining-mocks')
// Used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
describe("#Mining", () => {
describe('#Mining', () => {
let req, res
before(() => {
@@ -36,12 +36,12 @@ describe("#Mining", () => {
}
// Set default environment variables for unit tests.
if (!process.env.TEST) process.env.TEST = "unit"
if (process.env.TEST === "unit") {
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
process.env.RPC_BASEURL = "http://fakeurl/api"
process.env.RPC_USERNAME = "fakeusername"
process.env.RPC_PASSWORD = "fakepassword"
if (!process.env.TEST) process.env.TEST = 'unit'
if (process.env.TEST === 'unit') {
process.env.BITCOINCOM_BASEURL = 'http://fakeurl/api/'
process.env.RPC_BASEURL = 'http://fakeurl/api'
process.env.RPC_USERNAME = 'fakeusername'
process.env.RPC_PASSWORD = 'fakepassword'
}
})
@@ -74,29 +74,29 @@ describe("#Mining", () => {
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
})
describe("#root", async () => {
describe('#root', async () => {
// root route handler.
const root = miningRoute.testableComponents.root
it("should respond to GET for base route", async () => {
it('should respond to GET for base route', async () => {
const result = root(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(result.status, "mining", "Returns static string")
assert.equal(result.status, 'mining', 'Returns static string')
})
})
describe("#getMiningInfo", async () => {
describe('#getMiningInfo', async () => {
const getMiningInfo = miningRoute.testableComponents.getMiningInfo
it("should throw 503 when network issues", async () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = "http://fakeurl/api/"
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await getMiningInfo(req, res)
await getMiningInfo(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Restore the saved URL.
@@ -105,16 +105,16 @@ describe("#Mining", () => {
assert.isAbove(
res.statusCode,
499,
"HTTP status code 500 or greater expected."
'HTTP status code 500 or greater expected.'
)
// assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
})
it("should GET mining information", async () => {
it('should GET mining information', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.RPC_BASEURL}`)
.post(uri => uri.includes("/"))
.post(uri => uri.includes('/'))
.reply(200, { result: mockData.mockMiningInfo })
}
@@ -122,30 +122,30 @@ describe("#Mining", () => {
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, [
"blocks",
"currentblocksize",
"currentblocktx",
"difficulty",
"blockprioritypercentage",
"warnings",
"networkhashps",
"pooledtx",
"chain"
'blocks',
'currentblocksize',
'currentblocktx',
'difficulty',
'blockprioritypercentage',
'warnings',
'networkhashps',
'pooledtx',
'chain'
])
})
})
describe("#getNetworkHashPS", async () => {
describe('#getNetworkHashPS', async () => {
const getNetworkHashPS = miningRoute.testableComponents.getNetworkHashPS
it("should throw 503 when network issues", async () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = "http://fakeurl/api/"
process.env.RPC_BASEURL = 'http://fakeurl/api/'
const result = await getNetworkHashPS(req, res)
await getNetworkHashPS(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Restore the saved URL.
@@ -154,16 +154,16 @@ describe("#Mining", () => {
assert.isAbove(
res.statusCode,
499,
"HTTP status code 500 or greater expected."
'HTTP status code 500 or greater expected.'
)
// assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
})
it("should GET Network Hash per second", async () => {
it('should GET Network Hash per second', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.RPC_BASEURL}`)
.post(uri => uri.includes("/"))
.post(uri => uri.includes('/'))
.reply(200, { result: 517604755.6648782 })
}
+33 -33
View File
@@ -2,10 +2,10 @@
This library contains mocking data for running unit tests on the address route.
*/
"use strict"
'use strict'
const mockAddressDetails = {
addrStr: "1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W",
addrStr: '1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W',
balance: 0.00126419,
balanceSat: 126419,
totalReceived: 0.02175868,
@@ -17,17 +17,17 @@ const mockAddressDetails = {
unconfirmedTxApperances: 0,
txApperances: 3,
transactions: [
"2dc053f55a666a3d2a08b1c680b704d62a55506d14ad884add87edcc56b9277d",
"544c15ce35c0f2e808d28f29d6587f1ec9276233e29856b7f2938cf0daef0026",
"81039b1d7b855b133f359f9dc65f776bd105650153a941675fedc504228ddbd3"
'2dc053f55a666a3d2a08b1c680b704d62a55506d14ad884add87edcc56b9277d',
'544c15ce35c0f2e808d28f29d6587f1ec9276233e29856b7f2938cf0daef0026',
'81039b1d7b855b133f359f9dc65f776bd105650153a941675fedc504228ddbd3'
],
legacyAddress: "1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W",
cashAddress: "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
legacyAddress: '1Fg4r9iDrEkCcDmHTy2T79EusNfhyQpu7W',
cashAddress: 'bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c'
}
const mockUtxoDetails = [
{
txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
txid: '15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e',
vout: 286,
amount: 0.00001,
satoshis: 1000,
@@ -35,7 +35,7 @@ const mockUtxoDetails = [
confirmations: 3490
},
{
txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
txid: '15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e',
vout: 287,
amount: 0.00001,
satoshis: 1000,
@@ -43,7 +43,7 @@ const mockUtxoDetails = [
confirmations: 3490
},
{
txid: "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
txid: '15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e',
vout: 288,
amount: 0.00001,
satoshis: 1000,
@@ -54,10 +54,10 @@ const mockUtxoDetails = [
const mockUnconfirmed = [
{
address: "1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp",
txid: "000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786",
address: '1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp',
txid: '000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786',
vout: 0,
scriptPubKey: "76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac",
scriptPubKey: '76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac',
amount: 0.00999626,
satoshis: 999626,
confirmations: 0,
@@ -69,40 +69,40 @@ const mockTransactions = {
pagesTotal: 1,
txs: [
{
txid: "000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786",
txid: '000c00a90fb5031da6e02f7625df2f8b35a4c16e6feb9fc72293e67e5ff75786',
version: 2,
locktime: 549565,
vin: [
{
txid:
"45c891c6d44619fc85716ba1b593aa83ebc1e500fe611b1ab98531ea203a0f21",
'45c891c6d44619fc85716ba1b593aa83ebc1e500fe611b1ab98531ea203a0f21',
vout: 209,
sequence: 4294967294,
n: 0,
scriptSig: {
hex:
"47304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe4477541210246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a",
'47304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe4477541210246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a',
asm:
"304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe44775[ALL|FORKID] 0246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a"
'304402205b136f348bedae61a87c0500979d47ab02c76f0e4aba866b94c4931fccb5d7dc0220757a141660475b0cd4cb8b1f54b1ace95105f5bea775e817b115fb589fe44775[ALL|FORKID] 0246daec651c506f353daa7468714399c773df42ac4d663022d0e446a3331ac64a'
},
addr: "14TdovsQUL69xL5g3zSzhLpmDb93d9rU9m",
addr: '14TdovsQUL69xL5g3zSzhLpmDb93d9rU9m',
valueSat: 1979534,
value: 0.01979534,
doubleSpentTxID: null
},
{
txid:
"6e5fa79547112a912adf6082c975dc80e282045193512ea369adb6bac7420674",
'6e5fa79547112a912adf6082c975dc80e282045193512ea369adb6bac7420674',
vout: 147,
sequence: 4294967294,
n: 1,
scriptSig: {
hex:
"473044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a4121038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e",
'473044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a4121038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e',
asm:
"3044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a[ALL|FORKID] 038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e"
'3044022056674ac83a37d54ffec2c6d33cfc2ae2256f821b8bd818e1b6783356b49f3d28022046d3dd147c8fc51f2da5d16996a3cea1d7314e327aa1ae1017418737ed20136a[ALL|FORKID] 038f23af565f68d8455e07e5c33c5cfc5114de2f478f035db23eb02f8ff5fe7f6e'
},
addr: "1CEtC2fjELvmAzTd6MWuHb1gvuSq8x3Xpb",
addr: '1CEtC2fjELvmAzTd6MWuHb1gvuSq8x3Xpb',
valueSat: 10466,
value: 0.00010466,
doubleSpentTxID: null
@@ -110,28 +110,28 @@ const mockTransactions = {
],
vout: [
{
value: "0.00999626",
value: '0.00999626',
n: 0,
scriptPubKey: {
hex: "76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac",
hex: '76a914997fabcd94a1e2aaa13a7664362e5e7b96c169a988ac',
asm:
"OP_DUP OP_HASH160 997fabcd94a1e2aaa13a7664362e5e7b96c169a9 OP_EQUALVERIFY OP_CHECKSIG",
addresses: ["1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp"],
type: "pubkeyhash"
'OP_DUP OP_HASH160 997fabcd94a1e2aaa13a7664362e5e7b96c169a9 OP_EQUALVERIFY OP_CHECKSIG',
addresses: ['1EzdL6TBbkNhnB2fYiBaKmcs5fxaoqwdAp'],
type: 'pubkeyhash'
},
spentTxId: null,
spentIndex: null,
spentHeight: null
},
{
value: "0.00990000",
value: '0.00990000',
n: 1,
scriptPubKey: {
hex: "76a914e3335e4d6babe61ea58311293c1c6bfe802801cb88ac",
hex: '76a914e3335e4d6babe61ea58311293c1c6bfe802801cb88ac',
asm:
"OP_DUP OP_HASH160 e3335e4d6babe61ea58311293c1c6bfe802801cb OP_EQUALVERIFY OP_CHECKSIG",
addresses: ["1MiKvgaQTFCTEZbSDMZgw9ahaB52Cr4ofb"],
type: "pubkeyhash"
'OP_DUP OP_HASH160 e3335e4d6babe61ea58311293c1c6bfe802801cb OP_EQUALVERIFY OP_CHECKSIG',
addresses: ['1MiKvgaQTFCTEZbSDMZgw9ahaB52Cr4ofb'],
type: 'pubkeyhash'
},
spentTxId: null,
spentIndex: null,
@@ -139,7 +139,7 @@ const mockTransactions = {
}
],
blockhash:
"00000000000000000158b1a2883688873ec5ea076e3b0f576bcdfe1fd277880f",
'00000000000000000158b1a2883688873ec5ea076e3b0f576bcdfe1fd277880f',
blockheight: 549601,
confirmations: 5,
time: 1537990026,
+8 -8
View File
@@ -2,7 +2,7 @@
This library contains mocking data for running unit tests on the bitcore route.
*/
"use strict"
'use strict'
const mockBalance = {
confirmed: 10000000,
@@ -12,18 +12,18 @@ const mockBalance = {
const mockUtxos = [
{
_id: "5cf2c31a33bd46a95ec7e730",
chain: "BCH",
network: "testnet",
_id: '5cf2c31a33bd46a95ec7e730',
chain: 'BCH',
network: 'testnet',
coinbase: false,
mintIndex: 1,
spentTxid: "",
spentTxid: '',
mintTxid:
"5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392",
'5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392',
mintHeight: 1265275,
spentHeight: -2,
address: "qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4",
script: "76a9140e5b4ad9008bb9a027b7e2d0ef958914e12db20788ac",
address: 'qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4',
script: '76a9140e5b4ad9008bb9a027b7e2d0ef958914e12db20788ac',
value: 10000000,
confirmations: -1
}
+13 -13
View File
@@ -2,39 +2,39 @@
This library contains mocking data for running unit tests on the address route.
*/
"use strict"
'use strict'
const mockBlockDetails = {
hash: "00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79",
hash: '00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79',
size: 1319,
height: 1267544,
version: 536870912,
merkleroot:
"c2cd01ec2cf149acc7631385f89ae103d1a2ad212ab810c862d9680a811618ce",
'c2cd01ec2cf149acc7631385f89ae103d1a2ad212ab810c862d9680a811618ce',
tx: [
"52bfa89d449fef8070ec33e7a61f5ec8b5417ff62b050cd6a144ebce9557e0fa",
"8988e8742d2523f667c2d1374861919e3a82903e059fec75c10795da2303b93b",
"41def004f22b196d675566a6983ecf97611e72c48375b8ba779983d5ccd369d7",
"8ca8efb06abb94395f8331f87e101504dcf66aee828f2111922f056971fa7502",
"9ab409cbb203be7cf22bd6598d787fcdd5b417d885b72207ecc7253470770649"
'52bfa89d449fef8070ec33e7a61f5ec8b5417ff62b050cd6a144ebce9557e0fa',
'8988e8742d2523f667c2d1374861919e3a82903e059fec75c10795da2303b93b',
'41def004f22b196d675566a6983ecf97611e72c48375b8ba779983d5ccd369d7',
'8ca8efb06abb94395f8331f87e101504dcf66aee828f2111922f056971fa7502',
'9ab409cbb203be7cf22bd6598d787fcdd5b417d885b72207ecc7253470770649'
],
time: 1542048973,
nonce: 3936284753,
bits: "1a03c148",
bits: '1a03c148',
difficulty: 4467892.99177529,
chainwork: "00000000000000000000000000000000000000000000003ee27b503a064045bd",
chainwork: '00000000000000000000000000000000000000000000003ee27b503a064045bd',
confirmations: 3,
previousblockhash:
"00000000000001891202cbe18729a02a8763cf04da0ca7aded6e6c7d9b500785",
'00000000000001891202cbe18729a02a8763cf04da0ca7aded6e6c7d9b500785',
nextblockhash:
"000000000000039b93b3f3403a0eb21150904b15229d998cf3788fd8bf192cc2",
'000000000000039b93b3f3403a0eb21150904b15229d998cf3788fd8bf192cc2',
reward: 0.78125,
isMainChain: true,
poolInfo: {}
}
const mockBlockHash =
"00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
'00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79'
module.exports = {
mockBlockDetails,
+25 -25
View File
@@ -2,70 +2,70 @@
This library contains mocking data for running unit tests on the blockbook route.
*/
"use strict"
'use strict'
const mockBalance = {
page: 1,
totalPages: 1,
itemsOnPage: 1000,
address: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
balance: "10000000",
totalReceived: "10000000",
totalSent: "0",
unconfirmedBalance: "0",
address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
balance: '10000000',
totalReceived: '10000000',
totalSent: '0',
unconfirmedBalance: '0',
unconfirmedTxs: 0,
txs: 1,
txids: ["5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392"]
txids: ['5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392']
}
const mockUtxos = [
{
txid: "5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392",
txid: '5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392',
vout: 1,
value: "10000000",
value: '10000000',
height: 1265275,
confirmations: 42704
}
]
const mockTx = {
txid: "5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392",
txid: '5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392',
version: 2,
vin: [
{
txid: "85ddb8215fc3701a493cf1c450644c5ef32c55aaa2f48ae2d008944394f3e4d3",
txid: '85ddb8215fc3701a493cf1c450644c5ef32c55aaa2f48ae2d008944394f3e4d3',
sequence: 4294967295,
n: 0,
addresses: ["bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35"],
value: "16983000648",
addresses: ['bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35'],
value: '16983000648',
hex:
"47304402202378e55f4d02bb932498deef22dfc1f7a4984858c3b55017e225dd567172252e0220373d27710b5d42a72ac9725959f1605a912fee0ae86a7ad36e7d6d796f14ca29412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792"
'47304402202378e55f4d02bb932498deef22dfc1f7a4984858c3b55017e225dd567172252e0220373d27710b5d42a72ac9725959f1605a912fee0ae86a7ad36e7d6d796f14ca29412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792'
}
],
vout: [
{
value: "16973000422",
value: '16973000422',
n: 0,
spent: true,
hex: "76a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac",
addresses: ["bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35"]
hex: '76a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac',
addresses: ['bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35']
},
{
value: "10000000",
value: '10000000',
n: 1,
hex: "76a9140e5b4ad9008bb9a027b7e2d0ef958914e12db20788ac",
addresses: ["bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4"]
hex: '76a9140e5b4ad9008bb9a027b7e2d0ef958914e12db20788ac',
addresses: ['bchtest:qq89kjkeqz9mngp8kl3dpmu43y2wztdjqu500gn4c4']
}
],
blockHash: "00000000005242edac4635ac2375a454e801cc1be8b131b622328089731e5e30",
blockHash: '00000000005242edac4635ac2375a454e801cc1be8b131b622328089731e5e30',
blockHeight: 1265275,
confirmations: 65402,
blockTime: 1540912733,
value: "16983000422",
valueIn: "16983000648",
fees: "226",
value: '16983000422',
valueIn: '16983000648',
fees: '226',
hex:
"0200000001d3e4f394439408d0e28af4a2aa552cf35e4c6450c4f13c491a70c35f21b8dd85000000006a47304402202378e55f4d02bb932498deef22dfc1f7a4984858c3b55017e225dd567172252e0220373d27710b5d42a72ac9725959f1605a912fee0ae86a7ad36e7d6d796f14ca29412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02e66eabf3030000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a9140e5b4ad9008bb9a027b7e2d0ef958914e12db20788ac00000000"
'0200000001d3e4f394439408d0e28af4a2aa552cf35e4c6450c4f13c491a70c35f21b8dd85000000006a47304402202378e55f4d02bb932498deef22dfc1f7a4984858c3b55017e225dd567172252e0220373d27710b5d42a72ac9725959f1605a912fee0ae86a7ad36e7d6d796f14ca29412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02e66eabf3030000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a9140e5b4ad9008bb9a027b7e2d0ef958914e12db20788ac00000000'
}
module.exports = {
+105 -105
View File
@@ -2,30 +2,30 @@
This library contains mocking data for running unit tests on the address route.
*/
"use strict"
'use strict'
const mockBlockHash =
"00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79"
'00000000000000645dec6503d3f5eafb0d2537a7a28f181d721dec7c44154c79'
const mockBlockchainInfo = {
chain: "test",
chain: 'test',
blocks: 1267694,
headers: 1267694,
bestblockhash:
"000000000000013eaf80d1e157e32804c36a58ad0bb26ca59833880c80298780",
'000000000000013eaf80d1e157e32804c36a58ad0bb26ca59833880c80298780',
difficulty: 4105763.969035785,
mediantime: 1542131305,
verificationprogress: 0.9999968911571566,
chainwork: "00000000000000000000000000000000000000000000003f0443b0b5f02ce255",
chainwork: '00000000000000000000000000000000000000000000003f0443b0b5f02ce255',
pruned: false,
softforks: [
{ id: "bip34", version: 2, reject: { status: true } },
{ id: "bip66", version: 3, reject: { status: true } },
{ id: "bip65", version: 4, reject: { status: true } }
{ id: 'bip34', version: 2, reject: { status: true } },
{ id: 'bip66', version: 3, reject: { status: true } },
{ id: 'bip65', version: 4, reject: { status: true } }
],
bip9_softforks: {
csv: {
status: "active",
status: 'active',
startTime: 1456790400,
timeout: 1493596800,
since: 770112
@@ -36,171 +36,171 @@ const mockBlockchainInfo = {
const mockChainTips = [
{
height: 1267696,
hash: "000000000000035bfc43a642ebbff8cfc1e88b1d564de8b0a6c7e2797eeafb21",
hash: '000000000000035bfc43a642ebbff8cfc1e88b1d564de8b0a6c7e2797eeafb21',
branchlen: 0,
status: "active"
status: 'active'
},
{
height: 1267581,
hash: "000000000001bd12e4124207682563135b21353ca3087bc6b0c409f7f9e1da91",
hash: '000000000001bd12e4124207682563135b21353ca3087bc6b0c409f7f9e1da91',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1267375,
hash: "00000000702036979df70236bcc45dfc72d43d5d0e6834007afa1fa627e49587",
hash: '00000000702036979df70236bcc45dfc72d43d5d0e6834007afa1fa627e49587',
branchlen: 1036,
status: "headers-only"
status: 'headers-only'
},
{
height: 1266979,
hash: "00000000e851abbde2174ccdc5c2508b909f81f23c4b7abeac864eee1a4891c7",
hash: '00000000e851abbde2174ccdc5c2508b909f81f23c4b7abeac864eee1a4891c7',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266973,
hash: "000000007e1324d2900ed70947f89ab8fd4a267e87c9244c333215659a7370d5",
hash: '000000007e1324d2900ed70947f89ab8fd4a267e87c9244c333215659a7370d5',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266967,
hash: "000000000f37f12843d4800f50ec4de44dce0432e4d448242d43ff04a7a2948d",
hash: '000000000f37f12843d4800f50ec4de44dce0432e4d448242d43ff04a7a2948d',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266963,
hash: "00000000ae11ec99e88898cbd72567cb4cb79e7fc13243357bef79632769deb4",
hash: '00000000ae11ec99e88898cbd72567cb4cb79e7fc13243357bef79632769deb4',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266962,
hash: "000000004f97851259b4460a049e44fa5bd4beadee04a85bf81bd2e90c4f24f9",
hash: '000000004f97851259b4460a049e44fa5bd4beadee04a85bf81bd2e90c4f24f9',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266950,
hash: "00000000d12a0e4a827f73ecaadb563df7e99817294939f2be8e943079dc60b2",
hash: '00000000d12a0e4a827f73ecaadb563df7e99817294939f2be8e943079dc60b2',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266944,
hash: "00000000612d16af273217818e8e7ac5014a19f68ed04e1bc897b1be0a9c744f",
hash: '00000000612d16af273217818e8e7ac5014a19f68ed04e1bc897b1be0a9c744f',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266941,
hash: "0000000000002b91cdb15cacf3368da2c9ffce511d64092193b507dad75f4a27",
hash: '0000000000002b91cdb15cacf3368da2c9ffce511d64092193b507dad75f4a27',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266896,
hash: "000000000002745f67a66617b1f9f65c2dfb4c4b8a9ed9b1320b98d3ca46cbe5",
hash: '000000000002745f67a66617b1f9f65c2dfb4c4b8a9ed9b1320b98d3ca46cbe5',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266481,
hash: "0000000000036babee3ba7654cddb29a9fe5e85c9fbeb44bb53d5ffb694b9670",
hash: '0000000000036babee3ba7654cddb29a9fe5e85c9fbeb44bb53d5ffb694b9670',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266452,
hash: "00000000502c3ab1490e0839780a4b441bbe21507c454545941e6adcde73c2ff",
hash: '00000000502c3ab1490e0839780a4b441bbe21507c454545941e6adcde73c2ff',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1266336,
hash: "000000001c9a0b7cd9eb2210f69d5a9a3f4546ba3707deb40993d729190582d7",
hash: '000000001c9a0b7cd9eb2210f69d5a9a3f4546ba3707deb40993d729190582d7',
branchlen: 10,
status: "headers-only"
status: 'headers-only'
},
{
height: 1266097,
hash: "000000000028ac0fbd18afe6f001f70cb7549bd2b3082d754dde88ee236368a2",
hash: '000000000028ac0fbd18afe6f001f70cb7549bd2b3082d754dde88ee236368a2',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1265522,
hash: "00000000000000c6df7a2063030e6ce51399e470cc46e4bf6d67aa3f0feca98d",
hash: '00000000000000c6df7a2063030e6ce51399e470cc46e4bf6d67aa3f0feca98d',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1265470,
hash: "0000000000168e6442a595a02340fccf8dc2b0e8912c632d39e1f870685f6d7c",
hash: '0000000000168e6442a595a02340fccf8dc2b0e8912c632d39e1f870685f6d7c',
branchlen: 2,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1265275,
hash: "000000008bc2b37ae6af1b886b52e7e1c1122c12badc4ae6c13df64f789267cf",
hash: '000000008bc2b37ae6af1b886b52e7e1c1122c12badc4ae6c13df64f789267cf',
branchlen: 11027,
status: "headers-only"
status: 'headers-only'
},
{
height: 1265257,
hash: "00000000005bc3e9973d7273211eab02ae02549c7ebae48764c0bd648d4d7bbe",
hash: '00000000005bc3e9973d7273211eab02ae02549c7ebae48764c0bd648d4d7bbe',
branchlen: 114,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1265254,
hash: "0000000000e5b909d3541857315e9ee103b042d9ba661f25cc3e8fb25a96c8ce",
hash: '0000000000e5b909d3541857315e9ee103b042d9ba661f25cc3e8fb25a96c8ce',
branchlen: 111,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1265245,
hash: "000000000066eb8832f6f990baceb379536f437216e22475a6c1b9133d250cb8",
hash: '000000000066eb8832f6f990baceb379536f437216e22475a6c1b9133d250cb8',
branchlen: 102,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1264455,
hash: "00000000000001befc1bb17a23208d0b77b2449e37093ce8fbb5e346b19cafcc",
hash: '00000000000001befc1bb17a23208d0b77b2449e37093ce8fbb5e346b19cafcc',
branchlen: 1,
status: "valid-headers"
status: 'valid-headers'
},
{
height: 1264373,
hash: "00000000000001ed3747e04fb95054cac0358fb4d8009d1999fc3ea34413e84a",
hash: '00000000000001ed3747e04fb95054cac0358fb4d8009d1999fc3ea34413e84a',
branchlen: 175,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1263912,
hash: "00000000000004635aecbcb97edcd6f5396483338838cb40da804eb354c68bde",
hash: '00000000000004635aecbcb97edcd6f5396483338838cb40da804eb354c68bde',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1262906,
hash: "00000000b31643d92a3e7c38e9755844fc8607e3f1055580a8ff28854e8a8ece",
hash: '00000000b31643d92a3e7c38e9755844fc8607e3f1055580a8ff28854e8a8ece',
branchlen: 1,
status: "valid-fork"
status: 'valid-fork'
},
{
height: 1255749,
hash: "000000001dde5b015a99137f4cba87871370f4b6fcfbcc8b126547e6c33177da",
hash: '000000001dde5b015a99137f4cba87871370f4b6fcfbcc8b126547e6c33177da',
branchlen: 129,
status: "headers-only"
status: 'headers-only'
},
{
height: 1188789,
hash: "00000000af942ce4eb60b3213cbcb7c98a7330f1f8f1adb4b6376f5e822e15b2",
hash: '00000000af942ce4eb60b3213cbcb7c98a7330f1f8f1adb4b6376f5e822e15b2',
branchlen: 92,
status: "headers-only"
status: 'headers-only'
}
]
@@ -213,76 +213,76 @@ const mockMempoolInfo = {
}
const mockRawMempool = [
"db045bc3bd1088fa91f5ebb05c35cb9e2a91a22377f79b465cc6920b9893123c",
"6b3df7febf2b9834f1409155f88b866dd516b36376eae00e2b455df82e290405"
'db045bc3bd1088fa91f5ebb05c35cb9e2a91a22377f79b465cc6920b9893123c',
'6b3df7febf2b9834f1409155f88b866dd516b36376eae00e2b455df82e290405'
]
const mockBlockHeaderConcise =
"000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c"
'000000202ed2723e7590e2b937f6821a99d6764cb8799bf30f8e300000000000000000001d311c02df9a1e3f57b8dbdcf97ec8dbc3109a26779724c63e560b29ad9ea501e2af955d286403183049e39c'
const mockBlockHeader = {
hash: "00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900",
hash: '00000000000008c3679777df34f1a09565f98b2400a05b7c8da72525fdca3900',
confirmations: 7,
height: 1272859,
version: 2147418112,
versionHex: "7fff0000",
versionHex: '7fff0000',
merkleroot:
"846f45604ec6cde2528933305dba80971e9ff0874f74d2811c7c690b2c32706d",
'846f45604ec6cde2528933305dba80971e9ff0874f74d2811c7c690b2c32706d',
time: 1544207139,
mediantime: 1544202884,
nonce: 641041470,
bits: "1a09faea",
bits: '1a09faea',
difficulty: 1681035.704111868,
chainwork: "00000000000000000000000000000000000000000000003fc4752e608403be04",
chainwork: '00000000000000000000000000000000000000000000003fc4752e608403be04',
previousblockhash:
"0000000000003e467ebcb7e906645676c2f71b9ac520d6508bea45789b7c217d",
'0000000000003e467ebcb7e906645676c2f71b9ac520d6508bea45789b7c217d',
nextblockhash:
"00000000000006899041cdfd6c0b73a97730c362346dde479b77414ad7f25ace"
'00000000000006899041cdfd6c0b73a97730c362346dde479b77414ad7f25ace'
}
const mockTxOut = {
bestblock: "00000000003a7f19730dd9f172d7466658a5c8833dd03ed8f4ba36e3d857b5e7",
bestblock: '00000000003a7f19730dd9f172d7466658a5c8833dd03ed8f4ba36e3d857b5e7',
confirmations: 10,
value: 0.0001,
scriptPubKey: {
asm:
"OP_DUP OP_HASH160 0ee020c07f39526ac5505c54fa1ab98490979b83 OP_EQUALVERIFY OP_CHECKSIG",
hex: "76a9140ee020c07f39526ac5505c54fa1ab98490979b8388ac",
'OP_DUP OP_HASH160 0ee020c07f39526ac5505c54fa1ab98490979b83 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a9140ee020c07f39526ac5505c54fa1ab98490979b8388ac',
reqSigs: 1,
type: "pubkeyhash",
addresses: ["bchtest:qq8wqgxq0uu4y6k92pw9f7s6hxzfp9umsvtg39pzqf"]
type: 'pubkeyhash',
addresses: ['bchtest:qq8wqgxq0uu4y6k92pw9f7s6hxzfp9umsvtg39pzqf']
},
coinbase: false
}
const mockTxOutProof =
"000000200798039affceb7a381e15dc62443c286efe7cae852393b656807000000000000cf9a7d6c654fd1c4558229a619a550ff749b373fa0f0027eed68b1abf6175d5c07c50f5cffff001d0452403b34000000070d0765da76980d542b5670d27ccda9e717073270f8921ad017deb7ee83fe6c4c22830a48cc8392197f1742a3d81805bd2aa4eb7469f38c74f674429d682cb87efcff1713fd0c388a50f0d11adf05363397ef79d16cdb786d47c941c2cb89f2588f42aced9c05f4203b4440616a9e4266ec47909b9580a643f402b5d4e82cc3cddd73df05a33abf6af3975d973d3033d10c4168a73d58d01f685a96d5a2519cd0de9c77faf3f8725ddf155cbdc8ab8102f173e2d0a0d74767f3bff22f588158d6d5bc71c079c7659cc864819c43877635007650502eb4060fcc9feec3280a41d602ad0a"
'000000200798039affceb7a381e15dc62443c286efe7cae852393b656807000000000000cf9a7d6c654fd1c4558229a619a550ff749b373fa0f0027eed68b1abf6175d5c07c50f5cffff001d0452403b34000000070d0765da76980d542b5670d27ccda9e717073270f8921ad017deb7ee83fe6c4c22830a48cc8392197f1742a3d81805bd2aa4eb7469f38c74f674429d682cb87efcff1713fd0c388a50f0d11adf05363397ef79d16cdb786d47c941c2cb89f2588f42aced9c05f4203b4440616a9e4266ec47909b9580a643f402b5d4e82cc3cddd73df05a33abf6af3975d973d3033d10c4168a73d58d01f685a96d5a2519cd0de9c77faf3f8725ddf155cbdc8ab8102f173e2d0a0d74767f3bff22f588158d6d5bc71c079c7659cc864819c43877635007650502eb4060fcc9feec3280a41d602ad0a'
const mockAncestors = [
"070504de968fba8a23a1362fd7fc0546a420663f2bcc18099d894a41ecf9cce5",
"20af6b7fcd21a3f38bb65d32fe2d66fb1ae554ed9c00eaf1b17d7e81362381a9",
"227e08663a812cf44d91106b09fc8493fe1a2b7c146f30ca09ebd86c9b84b2a5",
"228833be79d4a833165ea199be160efcaeb9325e71e9455f424b27abc9688ba8",
"2de27df02001e7243435cef6d41ea2312b94a5964912eb21466b936852c0b822",
"2ef76ae690d6f6c9559e20358a75a0ce02250b9b8e80e0aa6f782576239f292a",
"3e314678f52d52694726e6da88b94c9f0ea086d2f9af297b01d014b62247839f",
"4773f840d5255f16c0e5effce48316d8b8824a1d3ddd5da275c5fd99e7b3ee42",
"4804b97112da07e2c187516a915dd4cbd4a3814f3c900b8d08eb1d508ab0ac47",
"4ca69f31081a256cb4711315336fe4358d8f04b67792ca5ee17b5f4089a2446a",
"6ac17dce10ae3a3d1d8e6f42546ad9a4bb981e62cba8d48bab03e01b9ea38ae3",
"6ce71182ef341c481a90d8b081a99d9788bdd91a917f9a6594fdfad2c2024a14",
"8413343ac973fb0968ae1809faa8f0ddf18252975481daa683e88b04afa66ccd",
"9430300f3d7ecdabe39671b6fd0e9c36f763f01a202e619c070554ddc5e8713e",
"94f82b5a2cd1647d8168807ccfdebe41931ea1ab789a050d615f08000a63b624",
"9848db6a7d2835002ca7e1097a685d75eb629f44df94007674635b45d0e97199",
"98d809993353df6c4d55fda5e7b0ed2e383601cef1180a9aa9c87e67e8f4dd94",
"9f5513a35ae8fad3dd061865a97d8127c914e3464527641c089993c06d092535",
"a7201ac90abd2aa42112faa809181c45047b6988a2f649a70a1d5bfb95f46884",
"a9f1284710c655357412a062b01efaeb174820613784ccbfe44b33b86a8bdbc4",
"b814f44c9c8ee24a218b9f295a8c1831106b70c15ffe8aeb7534e10d99935fd0",
"e130ccdcc94dc5eaa4ae37fa50e3ee96283b0e157616bc6e28454b64bae34f48",
"e68dad4a7292105cfa84fcaef7f99e5d4f2ece9613ca625d4d2ebf61efa84118",
"fe94caf5da672be3772d2304a6272eb8bc3d3f5cb4a886f39b7981e1485cf74b"
'070504de968fba8a23a1362fd7fc0546a420663f2bcc18099d894a41ecf9cce5',
'20af6b7fcd21a3f38bb65d32fe2d66fb1ae554ed9c00eaf1b17d7e81362381a9',
'227e08663a812cf44d91106b09fc8493fe1a2b7c146f30ca09ebd86c9b84b2a5',
'228833be79d4a833165ea199be160efcaeb9325e71e9455f424b27abc9688ba8',
'2de27df02001e7243435cef6d41ea2312b94a5964912eb21466b936852c0b822',
'2ef76ae690d6f6c9559e20358a75a0ce02250b9b8e80e0aa6f782576239f292a',
'3e314678f52d52694726e6da88b94c9f0ea086d2f9af297b01d014b62247839f',
'4773f840d5255f16c0e5effce48316d8b8824a1d3ddd5da275c5fd99e7b3ee42',
'4804b97112da07e2c187516a915dd4cbd4a3814f3c900b8d08eb1d508ab0ac47',
'4ca69f31081a256cb4711315336fe4358d8f04b67792ca5ee17b5f4089a2446a',
'6ac17dce10ae3a3d1d8e6f42546ad9a4bb981e62cba8d48bab03e01b9ea38ae3',
'6ce71182ef341c481a90d8b081a99d9788bdd91a917f9a6594fdfad2c2024a14',
'8413343ac973fb0968ae1809faa8f0ddf18252975481daa683e88b04afa66ccd',
'9430300f3d7ecdabe39671b6fd0e9c36f763f01a202e619c070554ddc5e8713e',
'94f82b5a2cd1647d8168807ccfdebe41931ea1ab789a050d615f08000a63b624',
'9848db6a7d2835002ca7e1097a685d75eb629f44df94007674635b45d0e97199',
'98d809993353df6c4d55fda5e7b0ed2e383601cef1180a9aa9c87e67e8f4dd94',
'9f5513a35ae8fad3dd061865a97d8127c914e3464527641c089993c06d092535',
'a7201ac90abd2aa42112faa809181c45047b6988a2f649a70a1d5bfb95f46884',
'a9f1284710c655357412a062b01efaeb174820613784ccbfe44b33b86a8bdbc4',
'b814f44c9c8ee24a218b9f295a8c1831106b70c15ffe8aeb7534e10d99935fd0',
'e130ccdcc94dc5eaa4ae37fa50e3ee96283b0e157616bc6e28454b64bae34f48',
'e68dad4a7292105cfa84fcaef7f99e5d4f2ece9613ca625d4d2ebf61efa84118',
'fe94caf5da672be3772d2304a6272eb8bc3d3f5cb4a886f39b7981e1485cf74b'
]
module.exports = {
+5 -5
View File
@@ -2,7 +2,7 @@
This library contains mocking data for running unit tests on the address route.
*/
"use strict"
'use strict'
const mockGetInfo = {
version: 170200,
@@ -12,21 +12,21 @@ const mockGetInfo = {
blocks: 1266726,
timeoffset: 0,
connections: 8,
proxy: "",
proxy: '',
difficulty: 1,
testnet: true,
keypoololdest: 1536331195,
keypoolsize: 2000,
paytxfee: 0,
relayfee: 0.00001,
errors: "Warning: unknown new rules activated (versionbit 28)"
errors: 'Warning: unknown new rules activated (versionbit 28)'
}
const mockGetNetworkInfo = {
version: 190700,
subversion: "/Bitcoin ABC:0.19.7(EB32.0)/",
subversion: '/Bitcoin ABC:0.19.7(EB32.0)/',
protocolversion: 70015,
localservices: "0000000000000425",
localservices: '0000000000000425',
localrelay: true,
timeoffset: 0,
networkactive: true,
+3 -4
View File
@@ -2,12 +2,12 @@
Contains mocks of Express req and res objects.
*/
"use strict"
'use strict'
const sinon = require("sinon")
const sinon = require('sinon')
// Inspect JS Objects.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true
@@ -55,7 +55,6 @@ const mockRes = {
cookie: sinon.stub().returns({}),
download: sinon.stub().returns({}),
end: sinon.stub().returns({}),
format: {},
get: sinon.stub().returns({}),
headersSent: sinon.stub().returns({}),
json: sinon.stub().callsFake(fakeJson),
+2 -2
View File
@@ -2,7 +2,7 @@
This library contains mocking data for running unit tests on the address route.
*/
"use strict"
'use strict'
const mockMiningInfo = {
blocks: 1270185,
@@ -14,7 +14,7 @@ const mockMiningInfo = {
"Warning: Unknown block versions being mined! It's possible unknown rules are in effect",
networkhashps: 517410290.9365583,
pooledtx: 5,
chain: "test"
chain: 'test'
}
module.exports = {
+43 -43
View File
@@ -2,23 +2,23 @@
This library contains mocking data for running unit tests.
*/
"use strict"
'use strict'
const mockDecodeRawTransaction = {
txid: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988",
hash: "a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988",
txid: 'a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988',
hash: 'a332237d82a2543af1b0e1ae3c8cea1610c290ebcaf084a7e9894a61de0be988',
size: 226,
version: 2,
locktime: 0,
vin: [
{
txid: "21cced645eab150585ed7ca7c96edebab5793cc0a3b3b286c42fd7d6d798b5b9",
txid: '21cced645eab150585ed7ca7c96edebab5793cc0a3b3b286c42fd7d6d798b5b9',
vout: 1,
scriptSig: {
asm:
"3045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd41390[ALL|FORKID] 0360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d",
'3045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd41390[ALL|FORKID] 0360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d',
hex:
"483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d"
'483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413d'
},
sequence: 4294967295
}
@@ -29,10 +29,10 @@ const mockDecodeRawTransaction = {
n: 0,
scriptPubKey: {
asm:
"OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG",
hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac",
'OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac',
reqSigs: 1,
type: "pubkeyhash",
type: 'pubkeyhash',
addresses: [Array]
}
},
@@ -41,10 +41,10 @@ const mockDecodeRawTransaction = {
n: 1,
scriptPubKey: {
asm:
"OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG",
hex: "76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac",
'OP_DUP OP_HASH160 eb4b180def88e3f5625b2d8ae2c098ff7d85f664 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac',
reqSigs: 1,
type: "pubkeyhash",
type: 'pubkeyhash',
addresses: [Array]
}
}
@@ -53,31 +53,31 @@ const mockDecodeRawTransaction = {
const mockDecodeScript = {
asm:
"0 0 -57 OP_NOP6 OP_LSHIFT OP_UNKNOWN OP_UNKNOWN OP_UNKNOWN c486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa OP_2OVER OP_NUMEQUALVERIFY OP_OR OP_INVERT OP_UNKNOWN OP_UNKNOWN 2ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab 67c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b [error]",
type: "nonstandard",
p2sh: "bchtest:pzy6dwfy6yf373w0dr05a6flfqksurjhwcl3awhdvm"
'0 0 -57 OP_NOP6 OP_LSHIFT OP_UNKNOWN OP_UNKNOWN OP_UNKNOWN c486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa OP_2OVER OP_NUMEQUALVERIFY OP_OR OP_INVERT OP_UNKNOWN OP_UNKNOWN 2ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab 67c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b [error]',
type: 'nonstandard',
p2sh: 'bchtest:pzy6dwfy6yf373w0dr05a6flfqksurjhwcl3awhdvm'
}
const mockRawTransactionConcise =
"02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000"
'02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000'
const mockRawTransactionVerbose = {
hex:
"02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000",
txid: "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971",
hash: "bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971",
'02000000014e6b52500110b1c30315b85805fb274f0f4afceffc1589f889b27709e59e987d000000006a473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792ffffffff02d1778f950a0000001976a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac80969800000000001976a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac00000000',
txid: 'bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971',
hash: 'bd320377db7026a3dd5c7ec444596c0ee18fc25c4f34ee944adc03e432ce1971',
size: 225,
version: 2,
locktime: 0,
vin: [
{
txid: "7d989ee50977b289f88915fceffc4a0f4f27fb0558b81503c3b1100150526b4e",
txid: '7d989ee50977b289f88915fceffc4a0f4f27fb0558b81503c3b1100150526b4e',
vout: 0,
scriptSig: {
asm:
"3044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7[ALL|FORKID] 03c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792",
'3044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7[ALL|FORKID] 03c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792',
hex:
"473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792"
'473044022052762770baa71c1a0b9544ad0f1ea343d32c22aa87c5f8397b6852f464c15b1e02201f4390745cb470e21e0e3c14229f39fef55ea0643a4c997f99d9f3501eae09b7412103c346eee77a77a8d3e073dacc0532ca7a5b9747bc06d88bf091cac9f4bc8bb792'
},
sequence: 4294967295
}
@@ -88,11 +88,11 @@ const mockRawTransactionVerbose = {
n: 0,
scriptPubKey: {
asm:
"OP_DUP OP_HASH160 36d2f27bbd826a86db1e93618ce3de89ef331693 OP_EQUALVERIFY OP_CHECKSIG",
hex: "76a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac",
'OP_DUP OP_HASH160 36d2f27bbd826a86db1e93618ce3de89ef331693 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a91436d2f27bbd826a86db1e93618ce3de89ef33169388ac',
reqSigs: 1,
type: "pubkeyhash",
addresses: ["bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35"]
type: 'pubkeyhash',
addresses: ['bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35']
}
},
{
@@ -100,34 +100,34 @@ const mockRawTransactionVerbose = {
n: 1,
scriptPubKey: {
asm:
"OP_DUP OP_HASH160 152ea3cd65f18cb8fa9146c84ea1a97af8f051de OP_EQUALVERIFY OP_CHECKSIG",
hex: "76a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac",
'OP_DUP OP_HASH160 152ea3cd65f18cb8fa9146c84ea1a97af8f051de OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914152ea3cd65f18cb8fa9146c84ea1a97af8f051de88ac',
reqSigs: 1,
type: "pubkeyhash",
addresses: ["bchtest:qq2jag7dvhccew86j9rvsn4p49a03uz3mcpw3d6aca"]
type: 'pubkeyhash',
addresses: ['bchtest:qq2jag7dvhccew86j9rvsn4p49a03uz3mcpw3d6aca']
}
}
],
blockhash: "000000000000026fa244de975ca89ea08008aa566564ce2e8ebb3144361b601b",
blockhash: '000000000000026fa244de975ca89ea08008aa566564ce2e8ebb3144361b601b',
confirmations: 125,
time: 1542646373,
blocktime: 1542646373
}
const mockWHDecode = {
txid: "f8a9857fe3b8a288b5fcafb1b0fc196731f433add6d962f77acd7c10b970ff89",
fee: "500",
sendingaddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
referenceaddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
txid: 'f8a9857fe3b8a288b5fcafb1b0fc196731f433add6d962f77acd7c10b970ff89',
fee: '500',
sendingaddress: 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr',
referenceaddress: 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr',
ismine: false,
version: 0,
type_int: 0,
type: "Simple Send",
type: 'Simple Send',
propertyid: 368,
precision: "8",
amount: "10.00000000",
precision: '8',
amount: '10.00000000',
valid: true,
blockhash: "0000000046ba0bcef78caaa4492622176bbc563cf249ab52340a0449bc8e26f6",
blockhash: '0000000046ba0bcef78caaa4492622176bbc563cf249ab52340a0449bc8e26f6',
blocktime: 1542814183,
positioninblock: 57,
block: 1269008,
@@ -135,15 +135,15 @@ const mockWHDecode = {
}
const mockWHCreateInput = {
txid: "f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2",
txid: 'f7ed9cf23dee85910f6269c9a101a75fcfd2f3c6fc81f17fad824ff7aaf99ab2',
vout: 1,
scriptPubKey: "76a914a4b98b0c118de83e7d39c834445f51dce62425f588ac",
scriptPubKey: '76a914a4b98b0c118de83e7d39c834445f51dce62425f588ac',
amount: 0.09984138,
satoshis: 9984138,
height: 1269011,
confirmations: 4,
legacyAddress: "mvXwPH74hW2yVTWwDwzsjGoaUAqJvWk7ZJ",
cashAddress: "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
legacyAddress: 'mvXwPH74hW2yVTWwDwzsjGoaUAqJvWk7ZJ',
cashAddress: 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr',
value: 0.09984138
}
+99 -99
View File
@@ -2,27 +2,27 @@
This library contains mocking data for running unit tests.
*/
"use strict"
'use strict'
const mockList = {
t: [
{
tokenDetails: {
tokenIdHex:
"df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
documentUri: "",
documentSha256: "",
symbol: "NAKAMOTO",
name: "NAKAMOTO",
'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
documentUri: '',
documentSha256: '',
symbol: 'NAKAMOTO',
name: 'NAKAMOTO',
decimals: 8
},
tokenStats: {
qty_valid_txns_since_genesis: 241,
qty_valid_token_utxos: 151,
qty_valid_token_addresses: 113,
qty_token_circulating_supply: "20995990",
qty_token_burned: "4010",
qty_token_minted: "21000000",
qty_token_circulating_supply: '20995990',
qty_token_burned: '4010',
qty_token_minted: '21000000',
qty_satoshis_locked_up: 81900
}
}
@@ -35,18 +35,18 @@ const mockSingleToken = {
tokenDetails: {
decimals: 0,
tokenIdHex:
"38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0",
timestamp: "2019-06-14 06:31:37",
'38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
timestamp: '2019-06-14 06:31:37',
timestamp_unix: 1560493897,
transactionType: "GENESIS",
transactionType: 'GENESIS',
versionType: 1,
documentUri: "ot@ot.com",
documentUri: 'ot@ot.com',
documentSha256Hex: null,
symbol: "OT",
name: "Test First SLP oasis Token",
symbol: 'OT',
name: 'Test First SLP oasis Token',
batonVout: 2,
containsBaton: true,
genesisOrMintQuantity: "10000",
genesisOrMintQuantity: '10000',
sendOutputs: null
},
tokenStats: {
@@ -56,11 +56,11 @@ const mockSingleToken = {
qty_valid_txns_since_genesis: 11,
qty_valid_token_utxos: 9,
qty_valid_token_addresses: 2,
qty_token_minted: "20000",
qty_token_burned: "0",
qty_token_circulating_supply: "20000",
qty_token_minted: '20000',
qty_token_burned: '0',
qty_token_circulating_supply: '20000',
qty_satoshis_locked_up: 4914,
minting_baton_status: "ALIVE"
minting_baton_status: 'ALIVE'
}
}
]
@@ -73,14 +73,14 @@ const mockSingleTokenError = {
const mockSingleAddress = {
a: [
{
_id: "5c93ed62a19119333d1595bc",
_id: '5c93ed62a19119333d1595bc',
tokenDetails: {
tokenIdHex:
"6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29"
'6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29'
},
address: "slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7",
address: 'slptest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqv7sq3kk7',
satoshis_balance: 546,
token_balance: "4616984"
token_balance: '4616984'
}
],
t: [
@@ -88,17 +88,17 @@ const mockSingleAddress = {
tokenDetails: {
decimals: 8,
tokenIdHex:
"6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29",
timestamp: "2019-02-25 10:05",
transactionType: "GENESIS",
'6b081fcd1f78b187be1464313dac8ff257251b727a42b613552a4040870aeb29',
timestamp: '2019-02-25 10:05',
transactionType: 'GENESIS',
versionType: 1,
documentUri: "https://developer.bitcoin.com",
documentSha256Hex: "",
symbol: "DEV",
name: "DEVCOIN",
documentUri: 'https://developer.bitcoin.com',
documentSha256Hex: '',
symbol: 'DEV',
name: 'DEVCOIN',
batonVout: 2,
containsBaton: true,
genesisOrMintQuantity: "500000000",
genesisOrMintQuantity: '500000000',
sendOutputs: null
},
tokenStats: {
@@ -108,125 +108,125 @@ const mockSingleAddress = {
qty_valid_txns_since_genesis: 172,
qty_valid_token_utxos: 170,
qty_valid_token_addresses: 170,
qty_token_minted: "1000000000",
qty_token_burned: "4.99999995",
qty_token_circulating_supply: "999999995.00000005",
qty_token_minted: '1000000000',
qty_token_burned: '4.99999995',
qty_token_circulating_supply: '999999995.00000005',
qty_satoshis_locked_up: 92820,
minting_baton_status: "ALIVE"
minting_baton_status: 'ALIVE'
}
}
]
}
const mockTx = {
txid: "57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457822d446",
txid: '57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457822d446',
version: 2,
locktime: 0,
vin: [
{
txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
txid: '61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49',
vout: 2,
sequence: 4294967295,
n: 0,
scriptSig: {
hex:
"4730440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
'4730440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585',
asm:
"30440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
'30440220409e79fec552f01203f41d3d621ae3db89c720af261c8268ce5f0453de009f5d022001e7ffefeba7b0716d32ea55cb6ace267b6ee9cbcc8a017bb9c3b6acf7889418[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585'
},
value: 546,
legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
legacyAddress: 'mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL',
cashAddress: 'bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09'
},
{
txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
txid: '61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49',
vout: 1,
sequence: 4294967295,
n: 1,
scriptSig: {
hex:
"483045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
'483045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585',
asm:
"3045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
'3045022100a743bee56c99bd103be48a78fa4c7342100815d9d2448dbe6e1d338c3a13b241022066728b5279fc22eef5cd019582ff34771e29175835fc98aa3168a1548fd78ac8[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585'
},
value: 546,
legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
legacyAddress: 'mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL',
cashAddress: 'bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09'
},
{
txid: "61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49",
txid: '61e71554a3dc18158f30d9e8f5c9b6641a789690b32302899f81cbea9fe3bb49',
vout: 3,
sequence: 4294967295,
n: 2,
scriptSig: {
hex:
"483045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585",
'483045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec412103c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585',
asm:
"3045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585"
'3045022100821473902eec5f1ce7d43b1ba7f9ec453bfe8b8dfc3de3e0723c883ab109922f02206162960e80618531fab2c16aee260fddd7979bab62471c8686af7de75f8732ec[ALL|FORKID] 03c87f0ec048a0771bdb60533d45cac88c6974afeb055a65edd663c2f947335585'
},
value: 9997521,
legacyAddress: "mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL",
cashAddress: "bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09"
legacyAddress: 'mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL',
cashAddress: 'bchtest:qz4qnxcxwvmacgye8wlakhz0835x0w3vtvaga95c09'
}
],
vout: [
{
value: "0.00000000",
value: '0.00000000',
n: 0,
scriptPubKey: {
hex:
"6a04534c500001010453454e44207ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796080000000049504f80080000001c71e64280",
'6a04534c500001010453454e44207ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796080000000049504f80080000001c71e64280',
asm:
"OP_RETURN 5262419 1 1145980243 7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796 0000000049504f80 0000001c71e64280"
'OP_RETURN 5262419 1 1145980243 7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796 0000000049504f80 0000001c71e64280'
},
spentTxId: null,
spentIndex: null,
spentHeight: null
},
{
value: "0.00000546",
value: '0.00000546',
n: 1,
scriptPubKey: {
hex: "76a914396b8e57ad0cb58d30e2992f22047b3c20377aa688ac",
hex: '76a914396b8e57ad0cb58d30e2992f22047b3c20377aa688ac',
asm:
"OP_DUP OP_HASH160 396b8e57ad0cb58d30e2992f22047b3c20377aa6 OP_EQUALVERIFY OP_CHECKSIG",
addresses: ["mkkZf7T3fU3vHSzNPy51HBmM46ghN1gnN9"],
type: "pubkeyhash"
'OP_DUP OP_HASH160 396b8e57ad0cb58d30e2992f22047b3c20377aa6 OP_EQUALVERIFY OP_CHECKSIG',
addresses: ['mkkZf7T3fU3vHSzNPy51HBmM46ghN1gnN9'],
type: 'pubkeyhash'
},
spentTxId: null,
spentIndex: null,
spentHeight: null
},
{
value: "0.00000546",
value: '0.00000546',
n: 2,
scriptPubKey: {
hex: "76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac",
hex: '76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac',
asm:
"OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG",
addresses: ["mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL"],
type: "pubkeyhash"
'OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG',
addresses: ['mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL'],
type: 'pubkeyhash'
},
spentTxId: null,
spentIndex: null,
spentHeight: null
},
{
value: "0.09996891",
value: '0.09996891',
n: 3,
scriptPubKey: {
hex: "76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac",
hex: '76a914aa099b067337dc20993bbfdb5c4f3c6867ba2c5b88ac',
asm:
"OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG",
addresses: ["mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL"],
type: "pubkeyhash"
'OP_DUP OP_HASH160 aa099b067337dc20993bbfdb5c4f3c6867ba2c5b OP_EQUALVERIFY OP_CHECKSIG',
addresses: ['mw22g57T9YA7MZQQu5eBDKj3PKTdt99oDL'],
type: 'pubkeyhash'
},
spentTxId: null,
spentIndex: null,
spentHeight: null
}
],
blockhash: "000000000000ce978accc64a6bb567acf0c653c202309a0f8e220149bf0c6968",
blockhash: '000000000000ce978accc64a6bb567acf0c653c202309a0f8e220149bf0c6968',
blockheight: 1287490,
confirmations: 746,
time: 1550855104,
@@ -237,28 +237,28 @@ const mockTx = {
fees: 0.0000063,
tokenInfo: {
versionType: 1,
transactionType: "SEND",
transactionType: 'SEND',
tokenIdHex:
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796",
sendOutputs: ["0", "1230000000", "122170000000"]
'7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796',
sendOutputs: ['0', '1230000000', '122170000000']
},
tokenIsValid: true
}
const mockConvert = {
slpAddress: "slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5",
cashAddress: "bchtest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2svtllzmlf",
legacyAddress: "mvQPGnzRT6gMWASZBMg7NcT3vmvsSKSQtf"
slpAddress: 'slptest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2shlcycvd5',
cashAddress: 'bchtest:qz35h5mfa8w2pqma2jq06lp7dnv5fxkp2svtllzmlf',
legacyAddress: 'mvQPGnzRT6gMWASZBMg7NcT3vmvsSKSQtf'
}
const mockTokenDetails = {
tokenIdHex:
"df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
documentUri: "",
symbol: "NAKAMOTO",
name: "NAKAMOTO",
'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
documentUri: '',
symbol: 'NAKAMOTO',
name: 'NAKAMOTO',
decimals: 8,
timestamp: "",
timestamp: '',
containsBaton: true,
versionType: 1
}
@@ -267,29 +267,29 @@ const mockTokenStats = {
qty_valid_txns_since_genesis: 241,
qty_valid_token_utxos: 151,
qty_valid_token_addresses: 113,
qty_token_circulating_supply: "20995990",
qty_token_burned: "4010",
qty_token_minted: "21000000",
qty_token_circulating_supply: '20995990',
qty_token_burned: '4010',
qty_token_minted: '21000000',
qty_satoshis_locked_up: 81900
}
const mockBalance = {
slpAddress: "simpleledger:qp9d8mn8ypryfvea2mev0ggc3wg6plpn4suuaeuss3",
slpAddress: 'simpleledger:qp9d8mn8ypryfvea2mev0ggc3wg6plpn4suuaeuss3',
satoshis_balance: 546,
token_balance: "1000"
token_balance: '1000'
}
const mockTransactions = [
{
txid: "a302f045be8efa1cd982833a7f187ff4fac8baac36da0c887eb2787d8b45e2af",
txid: 'a302f045be8efa1cd982833a7f187ff4fac8baac36da0c887eb2787d8b45e2af',
tokenDetails: {
valid: true,
detail: {
decimals: null,
tokenIdHex:
"495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a",
'495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a',
timestamp: null,
transactionType: "MINT",
transactionType: 'MINT',
versionType: 1,
documentUri: null,
documentSha256Hex: null,
@@ -298,7 +298,7 @@ const mockTransactions = [
batonVout: 2,
containsBaton: true,
genesisOrMintQuantity: {
$numberDecimal: "1000"
$numberDecimal: '1000'
},
sendOutputs: null
},
@@ -316,9 +316,9 @@ const mockFoobar = {
const mockSingleValidTxid = {
c: [
{
_id: "5d965fc27f1cf2184ca2fe73",
_id: '5d965fc27f1cf2184ca2fe73',
tx: {
h: "77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d"
h: '77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d'
},
slp: {
valid: true,
@@ -332,9 +332,9 @@ const mockSingleValidTxid = {
const mockTwoValidTxid = {
c: [
{
_id: "5d965fc27f1cf2184ca2fe73",
_id: '5d965fc27f1cf2184ca2fe73',
tx: {
h: "77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d"
h: '77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d'
},
slp: {
valid: true,
@@ -342,9 +342,9 @@ const mockTwoValidTxid = {
}
},
{
_id: "5d71e69758380a002c492a90",
_id: '5d71e69758380a002c492a90',
tx: {
h: "552112f9e458dc7d1d8b328b0a6685e8af74a64b60b6846e7c86407f27f47e42"
h: '552112f9e458dc7d1d8b328b0a6685e8af74a64b60b6846e7c86407f27f47e42'
},
slp: {
valid: true,
@@ -358,9 +358,9 @@ const mockTwoValidTxid = {
const mockTwoRedundentTxid = {
c: [
{
_id: "5db99c72a391ae2afd604bde",
_id: '5db99c72a391ae2afd604bde',
tx: {
h: "d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56"
h: 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56'
},
slp: {
valid: true,
+12 -12
View File
@@ -2,16 +2,16 @@
Mocks used for unit tests that interact with slpjs.
*/
"use strict"
'use strict'
const sinon = require("sinon")
const proxyquire = require("proxyquire")
const BigNumber = require("bignumber.js")
const slpMocks = require("./slp-mocks")
// const sinon = require('sinon')
// const proxyquire = require('proxyquire')
const BigNumber = require('bignumber.js')
const slpMocks = require('./slp-mocks')
// Mock the BitboxNetwork class.
class BitboxNetwork {
constructor() {}
// constructor () {}
async getAllSlpBalancesAndUtxos (address) {
return {
@@ -21,15 +21,15 @@ class BitboxNetwork {
satoshis_in_invalid_token_dag: 0,
satoshis_in_invalid_baton_dag: 0,
slpTokenBalances: {
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": new BigNumber(
'7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796': new BigNumber(
123400000000
)
},
slpTokenUtxos: {
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": []
'7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796': []
},
slpBatonUtxos: {
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796": []
'7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796': []
},
nonSlpUtxos: [{}],
invalidTokenUtxos: [],
@@ -43,9 +43,9 @@ class BitboxNetwork {
const obj = {
versionType: 1,
transactionType: 0,
symbol: "SLPSDK",
name: "SLP SDK example using BITBOX",
documentUri: "developer.bitcoin.com",
symbol: 'SLPSDK',
name: 'SLP SDK example using BITBOX',
documentUri: 'developer.bitcoin.com',
documentSha256: null,
decimals: 8,
batonVout: 2,
+7 -7
View File
@@ -2,7 +2,7 @@
This library contains mocking data for running unit tests on the address route.
*/
"use strict"
'use strict'
/*
const mockDetails = {
@@ -24,17 +24,17 @@ const mockDetails = {
*/
const mockDetails = {
txid: "6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40",
txid: '6f235bd3a689f03c11969cd649ccad592462ca958bc519a30194e7a67b349a40',
version: 2,
locktime: 0,
vin: [
{
txid: "273d616d1c48f4b075c497f36ffdc79da5c8d6ed75485808b3599aac504f8525",
txid: '273d616d1c48f4b075c497f36ffdc79da5c8d6ed75485808b3599aac504f8525',
vout: 0,
sequence: 4294967295,
n: 0,
scriptSig: [{}],
addr: "bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35",
addr: 'bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35',
valueSat: 45078867559,
value: 450.78867559,
doubleSpentTxID: null
@@ -42,7 +42,7 @@ const mockDetails = {
],
vout: [
{
value: "450.68867333",
value: '450.68867333',
n: 0,
scriptPubKey: [{}],
spentTxId: null,
@@ -50,7 +50,7 @@ const mockDetails = {
spentHeight: null
},
{
value: "0.10000000",
value: '0.10000000',
n: 1,
scriptPubKey: [{}],
spentTxId: null,
@@ -58,7 +58,7 @@ const mockDetails = {
spentHeight: null
}
],
blockhash: "00000000e7232ff12462dedf9c11985f5b54202515277c337ccc59812758f28b",
blockhash: '00000000e7232ff12462dedf9c11985f5b54202515277c337ccc59812758f28b',
blockheight: 1270188,
confirmations: 3,
time: 1543436253,
+38 -38
View File
@@ -2,12 +2,12 @@
This library contains mocking data for running unit tests on the address route.
*/
"use strict"
'use strict'
const mockAddress = {
isvalid: true,
address: "bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y",
scriptPubKey: "76a914016a935f87e8deeab04501889b22d87e4e52db0988ac",
address: 'bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y',
scriptPubKey: '76a914016a935f87e8deeab04501889b22d87e4e52db0988ac',
ismine: false,
iswatchonly: false,
isscript: false
@@ -17,32 +17,32 @@ const mockBalance = {
page: 1,
totalPages: 1,
itemsOnPage: 1000,
address: "bitcoincash:qzp7gdl52edm24xlpkyqnza9rv33u3mdxyc77j3u6k",
balance: "2546",
totalReceived: "2546",
totalSent: "0",
unconfirmedBalance: "0",
address: 'bitcoincash:qzp7gdl52edm24xlpkyqnza9rv33u3mdxyc77j3u6k',
balance: '2546',
totalReceived: '2546',
totalSent: '0',
unconfirmedBalance: '0',
unconfirmedTxs: 0,
txs: 2,
txids: [
"e190d13b88578132608ab912a4d2be3e55aa2792d6042d481ae21d700639de56",
"44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6"
'e190d13b88578132608ab912a4d2be3e55aa2792d6042d481ae21d700639de56',
'44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6'
]
}
const mockUtxos = [
{
txid: "e190d13b88578132608ab912a4d2be3e55aa2792d6042d481ae21d700639de56",
txid: 'e190d13b88578132608ab912a4d2be3e55aa2792d6042d481ae21d700639de56',
vout: 0,
value: "2000",
value: '2000',
height: 605873,
confirmations: 298,
satoshis: 2000
},
{
txid: "44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6",
txid: '44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6',
vout: 1,
value: "546",
value: '546',
height: 605873,
confirmations: 298,
satoshis: 546
@@ -51,25 +51,25 @@ const mockUtxos = [
const mockThreeUtxos = [
{
txid: "e190d13b88578132608ab912a4d2be3e55aa2792d6042d481ae21d700639de56",
txid: 'e190d13b88578132608ab912a4d2be3e55aa2792d6042d481ae21d700639de56',
vout: 0,
value: "2000",
value: '2000',
height: 605873,
confirmations: 298,
satoshis: 2000
},
{
txid: "44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6",
txid: '44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6',
vout: 1,
value: "546",
value: '546',
height: 605873,
confirmations: 298,
satoshis: 546
},
{
txid: "44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6",
txid: '44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6',
vout: 1,
value: "546",
value: '546',
height: 605873,
confirmations: 298,
satoshis: 546
@@ -79,38 +79,38 @@ const mockThreeUtxos = [
const mockIsTokenUtxos = [
false,
{
txid: "44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6",
txid: '44e1f48c4093fc61db1a8fa206aa402fc34e482b3f788cb38c123ca0e1a35db6',
vout: 1,
value: "546",
value: '546',
height: 605873,
confirmations: 298,
satoshis: 546,
utxoType: "token",
transactionType: "send",
tokenId: "497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7",
tokenTicker: "TOK-CH",
tokenName: "TokyoCash",
tokenDocumentUrl: "",
tokenDocumentHash: "",
utxoType: 'token',
transactionType: 'send',
tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
tokenTicker: 'TOK-CH',
tokenName: 'TokyoCash',
tokenDocumentUrl: '',
tokenDocumentHash: '',
decimals: 8,
tokenQty: 2
}
]
const tapUtxo = {
txid: "2e030df12390186baf817fa2760540b886511e04bc520e88f6b4c2124cc2a7d4",
txid: '2e030df12390186baf817fa2760540b886511e04bc520e88f6b4c2124cc2a7d4',
vout: 1,
value: "546",
value: '546',
height: 606564,
confirmations: 3,
satoshis: 546,
utxoType: "token",
transactionType: "send",
tokenId: "dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d",
tokenTicker: "TAP",
tokenName: "Thoughts and Prayers",
tokenDocumentUrl: "",
tokenDocumentHash: "",
utxoType: 'token',
transactionType: 'send',
tokenId: 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d',
tokenTicker: 'TAP',
tokenName: 'Thoughts and Prayers',
tokenDocumentUrl: '',
tokenDocumentHash: '',
decimals: 0,
tokenQty: 1
}
+198 -199
View File
@@ -1,45 +1,44 @@
"use strict"
'use strict'
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const nock = require("nock") // HTTP mocking
const sinon = require("sinon")
// const nock = require('nock') // HTTP mocking
const sinon = require('sinon')
// Used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
// Mocking data.
const { mockReq, mockRes, mockNext } = require("./mocks/express-mocks")
const { mockReq, mockRes, mockNext } = require('./mocks/express-mocks')
// Libraries under test
const RateLimits = require("../../src/middleware/route-ratelimit")
const RateLimits = require('../../src/middleware/route-ratelimit')
let rateLimits = new RateLimits()
let rateLimitMiddleware = rateLimits.routeRateLimit
const controlRoute = require("../../src/routes/v3/full-node/control")
const jwtAuth = require("../../src/middleware/jwt-auth")
// const controlRoute = require('../../src/routes/v3/full-node/control')
const jwtAuth = require('../../src/middleware/jwt-auth')
let req, res, next
let originalEnvVars // Used during transition from integration to unit tests.
// let originalEnvVars // Used during transition from integration to unit tests.
// JWT token used in tests.
const jwt = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWRlM2Y1NzM5ZTZjMGZmMDM0YjlhMSIsImlhdCI6MTU3MTY3NzQ1MCwiZXhwIjoxNTc0MjY5NDUwfQ.SSz7F7ETyBB3eoNG2VKCzPOhddtB-vrtmEoj7PxicrQ`
const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWRlM2Y1NzM5ZTZjMGZmMDM0YjlhMSIsImlhdCI6MTU3MTY3NzQ1MCwiZXhwIjoxNTc0MjY5NDUwfQ.SSz7F7ETyBB3eoNG2VKCzPOhddtB-vrtmEoj7PxicrQ'
describe("#route-ratelimits & jwt-auth", () => {
describe('#route-ratelimits & jwt-auth', () => {
let sandbox
before(() => {
// Save existing environment variables.
originalEnvVars = {
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
RPC_BASEURL: process.env.RPC_BASEURL,
RPC_USERNAME: process.env.RPC_USERNAME,
RPC_PASSWORD: process.env.RPC_PASSWORD
}
// 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
// }
if (!process.env.JWT_AUTH_SERVER)
process.env.JWT_AUTH_SERVER = `http://fakeurl.com/`
if (!process.env.JWT_AUTH_SERVER) { process.env.JWT_AUTH_SERVER = 'http://fakeurl.com/' }
})
// Setup the mocks before each test.
@@ -66,9 +65,9 @@ describe("#route-ratelimits & jwt-auth", () => {
rateLimits.closeRedis()
})
describe("#jwt-auth.js", () => {
describe("#getTokenFromHeaders", () => {
it(`should populate the req.locals object correctly`, () => {
describe('#jwt-auth.js', () => {
describe('#getTokenFromHeaders', () => {
it('should populate the req.locals object correctly', () => {
// Initialize req.locals
req.locals = {
proLimit: false,
@@ -82,23 +81,23 @@ describe("#route-ratelimits & jwt-auth", () => {
// console.log(`req.locals: ${JSON.stringify(req.locals, null, 2)}`)
assert.property(req.locals, "proLimit")
assert.property(req.locals, "apiLevel")
assert.property(req.locals, "jwtToken")
assert.property(req.locals, 'proLimit')
assert.property(req.locals, 'apiLevel')
assert.property(req.locals, 'jwtToken')
assert.equal(req.locals.jwtToken, jwt)
})
})
})
describe("#routeRateLimit", () => {
describe('#routeRateLimit', () => {
rateLimitMiddleware = new RateLimits()
let routeRateLimit = rateLimitMiddleware.routeRateLimit
const getInfo = controlRoute.testableComponents.getInfo
// const getInfo = controlRoute.testableComponents.getInfo
it("should pass through rate-limit middleware", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
it('should pass through rate-limit middleware', async () => {
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.method = 'GET'
// Call the route twice to trigger the rate handling.
await routeRateLimit(req, res, next)
@@ -108,10 +107,10 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(next.called, true)
})
it("should trigger rate-limit handler if rate limits exceeds 5 request per minute", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
it('should trigger rate-limit handler if rate limits exceeds 5 request per minute', async () => {
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.method = 'GET'
for (let i = 0; i < 5; i++) {
next.reset() // reset the stubbed next() function.
@@ -124,11 +123,11 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
false,
`next should not be called if rate limit was triggered.`
'next should not be called if rate limit was triggered.'
)
})
it("should NOT trigger rate-limit for free-tier at 5 RPM", async () => {
it('should NOT trigger rate-limit for free-tier at 5 RPM', async () => {
// Clear the require cache before running this test.
// delete require.cache[
// require.resolve("../../src/middleware/route-ratelimit")
@@ -137,9 +136,9 @@ describe("#route-ratelimits & jwt-auth", () => {
rateLimitMiddleware = new RateLimits()
routeRateLimit = rateLimitMiddleware.routeRateLimit
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.method = 'GET'
req.locals.proLimit = true
req.locals.apiLevel = 0
@@ -157,14 +156,14 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
true,
`next should be called if rate limit was not triggered.`
'next should be called if rate limit was not triggered.'
)
})
it("should trigger rate-limit for free tier after 10 RPM", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
it('should trigger rate-limit for free tier after 10 RPM', async () => {
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.method = 'GET'
req.locals.proLimit = true
req.locals.apiLevel = 0
@@ -180,11 +179,11 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
false,
`next should not be called if rate limit was triggered.`
'next should not be called if rate limit was triggered.'
)
})
it("should NOT trigger rate-limit handler for pro-tier at 25 RPM", async () => {
it('should NOT trigger rate-limit handler for pro-tier at 25 RPM', async () => {
// Clear the require cache before running this test.
// delete require.cache[
// require.resolve("../../src/middleware/route-ratelimit")
@@ -193,9 +192,9 @@ describe("#route-ratelimits & jwt-auth", () => {
rateLimitMiddleware = new RateLimits()
routeRateLimit = rateLimitMiddleware.routeRateLimit
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.method = 'GET'
req.locals.proLimit = true
req.locals.apiLevel = 10
@@ -213,11 +212,11 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
true,
`next should be called if rate limit was not triggered.`
'next should be called if rate limit was not triggered.'
)
})
it("rate-limiting should still kick in at a higher RPM for pro-tier", async () => {
it('rate-limiting should still kick in at a higher RPM for pro-tier', async () => {
// Clear the require cache before running this test.
// delete require.cache[
// require.resolve("../../src/middleware/route-ratelimit")
@@ -226,9 +225,9 @@ describe("#route-ratelimits & jwt-auth", () => {
rateLimitMiddleware = new RateLimits()
routeRateLimit = rateLimitMiddleware.routeRateLimit
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.method = "GET"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.method = 'GET'
req.locals.proLimit = true
req.locals.apiLevel = 10
@@ -246,157 +245,157 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
false,
`next should NOT be called if rate limit was triggered.`
'next should NOT be called if rate limit was triggered.'
)
})
})
describe("#getResource", () => {
it("should decode a blockchain request", () => {
describe('#getResource', () => {
it('should decode a blockchain request', () => {
const url =
"/blockchain/getTxOut/62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8/0?include_mempool=true"
'/blockchain/getTxOut/62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8/0?include_mempool=true'
const result = rateLimits.getResource(url)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, "blockchain")
assert.equal(result, 'blockchain')
})
})
describe("#calcPoints", () => {
it("should return 30 points for anonymous user", () => {
describe('#calcPoints', () => {
it('should return 30 points for anonymous user', () => {
const result = rateLimits.calcPoints()
// console.log(`result: ${result}`)
assert.equal(result, 30)
})
it("should return 10 points for free tier requesting full node access", () => {
it('should return 10 points for free tier requesting full node access', () => {
const jwtInfo = {
apiLevel: 10,
resource: "blockchain",
id: "5e3a0415eb29a962da2708b4"
resource: 'blockchain',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 10)
})
it("should return 10 points for free tier requesting indexer access", () => {
it('should return 10 points for free tier requesting indexer access', () => {
const jwtInfo = {
apiLevel: 10,
resource: "blockbook",
id: "5e3a0415eb29a962da2708b4"
resource: 'blockbook',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 10)
})
it("should return 10 points for free tier requesting SLPDB access", () => {
it('should return 10 points for free tier requesting SLPDB access', () => {
const jwtInfo = {
apiLevel: 10,
resource: "slp",
id: "5e3a0415eb29a962da2708b4"
resource: 'slp',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 10)
})
it("should return 1 point for full node tier requesting full node access", () => {
it('should return 1 point for full node tier requesting full node access', () => {
const jwtInfo = {
apiLevel: 20,
resource: "blockchain",
id: "5e3a0415eb29a962da2708b4"
resource: 'blockchain',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 1)
})
it("should return 10 points for full-node tier requesting indexer access", () => {
it('should return 10 points for full-node tier requesting indexer access', () => {
const jwtInfo = {
apiLevel: 20,
resource: "blockbook",
id: "5e3a0415eb29a962da2708b4"
resource: 'blockbook',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 10)
})
it("should return 10 points for full node tier requesting SLPDB access", () => {
it('should return 10 points for full node tier requesting SLPDB access', () => {
const jwtInfo = {
apiLevel: 20,
resource: "slp",
id: "5e3a0415eb29a962da2708b4"
resource: 'slp',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 10)
})
it("should return 1 point for indexer tier requesting full node access", () => {
it('should return 1 point for indexer tier requesting full node access', () => {
const jwtInfo = {
apiLevel: 30,
resource: "blockchain",
id: "5e3a0415eb29a962da2708b4"
resource: 'blockchain',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 1)
})
it("should return 1 points for indexer tier requesting indexer access", () => {
it('should return 1 points for indexer tier requesting indexer access', () => {
const jwtInfo = {
apiLevel: 30,
resource: "blockbook",
id: "5e3a0415eb29a962da2708b4"
resource: 'blockbook',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 1)
})
it("should return 10 points for indexer tier requesting SLPDB access", () => {
it('should return 10 points for indexer tier requesting SLPDB access', () => {
const jwtInfo = {
apiLevel: 30,
resource: "slp",
id: "5e3a0415eb29a962da2708b4"
resource: 'slp',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 10)
})
it("should return 1 point for SLP tier requesting full node access", () => {
it('should return 1 point for SLP tier requesting full node access', () => {
const jwtInfo = {
apiLevel: 40,
resource: "blockchain",
id: "5e3a0415eb29a962da2708b4"
resource: 'blockchain',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 1)
})
it("should return 1 points for SLP tier requesting indexer access", () => {
it('should return 1 points for SLP tier requesting indexer access', () => {
const jwtInfo = {
apiLevel: 40,
resource: "blockbook",
id: "5e3a0415eb29a962da2708b4"
resource: 'blockbook',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
assert.equal(result, 1)
})
it("should return 1 points for SLP tier requesting SLPDB access", () => {
it('should return 1 points for SLP tier requesting SLPDB access', () => {
const jwtInfo = {
apiLevel: 40,
resource: "slp",
id: "5e3a0415eb29a962da2708b4"
resource: 'slp',
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints(jwtInfo)
@@ -404,28 +403,28 @@ describe("#route-ratelimits & jwt-auth", () => {
})
})
describe("#calcPoints2", () => {
it("should return 30 points for anonymous user", () => {
describe('#calcPoints2', () => {
it('should return 30 points for anonymous user', () => {
const result = rateLimits.calcPoints2({})
// console.log(`result: ${result}`)
assert.equal(result, 30)
})
it("should return 10 point for free tier", () => {
it('should return 10 point for free tier', () => {
const jwtInfo = {
rateLimit: 10,
id: "5e3a0415eb29a962da2708b4"
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints2(jwtInfo)
assert.equal(result, 10)
})
it("should return 1 point for pro tier", () => {
it('should return 1 point for pro tier', () => {
const jwtInfo = {
rateLimit: 100,
id: "5e3a0415eb29a962da2708b4"
id: '5e3a0415eb29a962da2708b4'
}
const result = rateLimits.calcPoints2(jwtInfo)
@@ -433,12 +432,12 @@ describe("#route-ratelimits & jwt-auth", () => {
})
})
describe("#rateLimitByResource", () => {
it("should pass through rate-limit middleware", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
describe('#rateLimitByResource', () => {
it('should pass through rate-limit middleware', async () => {
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
// Call the route twice to trigger the rate handling.
await rateLimits.rateLimitByResource(req, res, next)
@@ -448,11 +447,11 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(next.called, true)
})
it("should trigger rate-limit handler if rate limits exceeds 5 request per minute", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
it('should trigger rate-limit handler if rate limits exceeds 5 request per minute', async () => {
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
for (let i = 0; i < 5; i++) {
next.reset() // reset the stubbed next() function.
@@ -465,28 +464,28 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
false,
`next should not be called if rate limit was triggered.`
'next should not be called if rate limit was triggered.'
)
})
it("should NOT trigger rate-limit for free-tier at 5 RPM", async () => {
it('should NOT trigger rate-limit for free-tier at 5 RPM', async () => {
// Create a new instance of the rate limit so we start with zeroed tracking.
rateLimits = new RateLimits()
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
req.locals.jwtToken = "some-token"
req.locals.jwtToken = 'some-token'
const jwtInfo = {
apiLevel: 10,
id: "5e3a0415eb29a962da2708b1"
id: '5e3a0415eb29a962da2708b1'
}
// Mock the call to the jwt library.
sandbox.stub(rateLimits.jwt, "verify").returns(jwtInfo)
sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo)
for (let i = 0; i < 5; i++) {
next.reset() // reset the stubbed next() function.
@@ -501,28 +500,28 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
true,
`next should be called if rate limit was not triggered.`
'next should be called if rate limit was not triggered.'
)
})
it("should trigger rate-limit for free tier after 10 RPM", async () => {
it('should trigger rate-limit for free tier after 10 RPM', async () => {
// Create a new instance of the rate limit so we start with zeroed tracking.
rateLimits = new RateLimits()
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
req.locals.jwtToken = "some-token"
req.locals.jwtToken = 'some-token'
const jwtInfo = {
apiLevel: 10,
id: "5e3a0415eb29a962da2708b2"
id: '5e3a0415eb29a962da2708b2'
}
// Mock the call to the jwt library.
sandbox.stub(rateLimits.jwt, "verify").returns(jwtInfo)
sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo)
for (let i = 0; i < 12; i++) {
next.reset() // reset the stubbed next() function.
@@ -535,28 +534,28 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
false,
`next should not be called if rate limit was triggered.`
'next should not be called if rate limit was triggered.'
)
})
it("should NOT trigger rate-limit handler for indexer-tier at 25 RPM", async () => {
it('should NOT trigger rate-limit handler for indexer-tier at 25 RPM', async () => {
// Create a new instance of the rate limit so we start with zeroed tracking.
rateLimits = new RateLimits()
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
req.locals.jwtToken = "some-token"
req.locals.jwtToken = 'some-token'
const jwtInfo = {
apiLevel: 20,
id: "5e3a0415eb29a962da2708b3"
id: '5e3a0415eb29a962da2708b3'
}
// Mock the call to the jwt library.
sandbox.stub(rateLimits.jwt, "verify").returns(jwtInfo)
sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo)
for (let i = 0; i < 25; i++) {
next.reset() // reset the stubbed next() function.
@@ -571,28 +570,28 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
true,
`next should be called if rate limit was not triggered.`
'next should be called if rate limit was not triggered.'
)
})
it("should still rate-limit at a higher RPM for pro-tier", async () => {
it('should still rate-limit at a higher RPM for pro-tier', async () => {
// Create a new instance of the rate limit so we start with zeroed tracking.
rateLimits = new RateLimits()
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
req.locals.jwtToken = "some-token"
req.locals.jwtToken = 'some-token'
const jwtInfo = {
apiLevel: 20,
id: "5e3a0415eb29a962da2708b5"
id: '5e3a0415eb29a962da2708b5'
}
// Mock the call to the jwt library.
sandbox.stub(rateLimits.jwt, "verify").returns(jwtInfo)
sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo)
for (let i = 0; i < 150; i++) {
next.reset() // reset the stubbed next() function.
@@ -607,17 +606,17 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
false,
`next should NOT be called if rate limit was triggered.`
'next should NOT be called if rate limit was triggered.'
)
})
})
describe("#rateLimitSimple", () => {
it("should pass through rate-limit middleware", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
describe('#rateLimitSimple', () => {
it('should pass through rate-limit middleware', async () => {
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
// Call the route twice to trigger the rate handling.
await rateLimits.rateLimitSimple(req, res, next)
@@ -627,11 +626,11 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(next.called, true)
})
it("should trigger rate-limit handler if rate limits exceeds 5 request per minute", async () => {
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
it('should trigger rate-limit handler if rate limits exceeds 5 request per minute', async () => {
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
for (let i = 0; i < 5; i++) {
next.reset() // reset the stubbed next() function.
@@ -644,28 +643,28 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
false,
`next should not be called if rate limit was triggered.`
'next should not be called if rate limit was triggered.'
)
})
it("should NOT trigger rate-limit for free-tier at 5 RPM", async () => {
it('should NOT trigger rate-limit for free-tier at 5 RPM', async () => {
// Create a new instance of the rate limit so we start with zeroed tracking.
rateLimits = new RateLimits()
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
req.locals.jwtToken = "some-token"
req.locals.jwtToken = 'some-token'
const jwtInfo = {
rateLimit: 10,
id: "5e3a0415eb29a962da2708c1"
id: '5e3a0415eb29a962da2708c1'
}
// Mock the call to the jwt library.
sandbox.stub(rateLimits.jwt, "verify").returns(jwtInfo)
sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo)
for (let i = 0; i < 5; i++) {
next.reset() // reset the stubbed next() function.
@@ -680,28 +679,28 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
true,
`next should be called if rate limit was not triggered.`
'next should be called if rate limit was not triggered.'
)
})
it("should trigger rate-limit for free tier after 10 RPM", async () => {
it('should trigger rate-limit for free tier after 10 RPM', async () => {
// Create a new instance of the rate limit so we start with zeroed tracking.
rateLimits = new RateLimits()
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
req.locals.jwtToken = "some-token"
req.locals.jwtToken = 'some-token'
const jwtInfo = {
rateLimit: 10,
id: "5e3a0415eb29a962da2708c2"
id: '5e3a0415eb29a962da2708c2'
}
// Mock the call to the jwt library.
sandbox.stub(rateLimits.jwt, "verify").returns(jwtInfo)
sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo)
for (let i = 0; i < 12; i++) {
next.reset() // reset the stubbed next() function.
@@ -714,28 +713,28 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
false,
`next should not be called if rate limit was triggered.`
'next should not be called if rate limit was triggered.'
)
})
it("should NOT trigger rate-limit handler for pro-tier at 25 RPM", async () => {
it('should NOT trigger rate-limit handler for pro-tier at 25 RPM', async () => {
// Create a new instance of the rate limit so we start with zeroed tracking.
rateLimits = new RateLimits()
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
req.locals.jwtToken = "some-token"
req.locals.jwtToken = 'some-token'
const jwtInfo = {
rateLimit: 100,
id: "5e3a0415eb29a962da2708c3"
id: '5e3a0415eb29a962da2708c3'
}
// Mock the call to the jwt library.
sandbox.stub(rateLimits.jwt, "verify").returns(jwtInfo)
sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo)
for (let i = 0; i < 25; i++) {
next.reset() // reset the stubbed next() function.
@@ -750,28 +749,28 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
true,
`next should be called if rate limit was not triggered.`
'next should be called if rate limit was not triggered.'
)
})
it("should still rate-limit at a higher RPM for pro-tier", async () => {
it('should still rate-limit at a higher RPM for pro-tier', async () => {
// Create a new instance of the rate limit so we start with zeroed tracking.
rateLimits = new RateLimits()
req.baseUrl = "/v3"
req.path = "/control/getNetworkInfo"
req.baseUrl = '/v3'
req.path = '/control/getNetworkInfo'
req.url = req.path
req.method = "GET"
req.method = 'GET'
req.locals.jwtToken = "some-token"
req.locals.jwtToken = 'some-token'
const jwtInfo = {
rateLimit: 100,
id: "5e3a0415eb29a962da2708c4"
id: '5e3a0415eb29a962da2708c4'
}
// Mock the call to the jwt library.
sandbox.stub(rateLimits.jwt, "verify").returns(jwtInfo)
sandbox.stub(rateLimits.jwt, 'verify').returns(jwtInfo)
for (let i = 0; i < 150; i++) {
next.reset() // reset the stubbed next() function.
@@ -786,20 +785,20 @@ describe("#route-ratelimits & jwt-auth", () => {
assert.equal(
next.called,
false,
`next should NOT be called if rate limit was triggered.`
'next should NOT be called if rate limit was triggered.'
)
})
})
})
// Generates a Basic authorization header.
function generateAuthHeader(pass) {
// https://en.wikipedia.org/wiki/Basic_access_authentication
const username = "BITBOX"
const combined = `${username}:${pass}`
var base64Credential = Buffer.from(combined).toString("base64")
var readyCredential = `Basic ${base64Credential}`
return readyCredential
}
// function generateAuthHeader (pass) {
// // https://en.wikipedia.org/wiki/Basic_access_authentication
// const username = 'BITBOX'
// const combined = `${username}:${pass}`
//
// var base64Credential = Buffer.from(combined).toString('base64')
// var readyCredential = `Basic ${base64Credential}`
//
// return readyCredential
// }
File diff suppressed because it is too large Load Diff
+167 -168
View File
@@ -9,50 +9,50 @@
-See listSingleToken() tests.
*/
"use strict"
'use strict'
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const nock = require("nock") // HTTP mocking
const sinon = require("sinon")
const proxyquire = require("proxyquire").noPreserveCache()
const axios = require("axios")
const nock = require('nock') // HTTP mocking
const sinon = require('sinon')
// const proxyquire = require('proxyquire').noPreserveCache()
// const axios = require('axios')
// Save existing environment variables.
// Used during transition from integration to unit tests.
let originalEnvVars, mockServerUrl
originalEnvVars = {
let mockServerUrl
const originalEnvVars = {
BITDB_URL: process.env.BITDB_URL,
BITCOINCOM_BASEURL: process.env.BITCOINCOM_BASEURL,
SLPDB_URL: process.env.SLPDB_URL
}
// Set default environment variables for unit tests.
if (!process.env.TEST) process.env.TEST = "unit"
if (!process.env.TEST) process.env.TEST = 'unit'
// Block network connections for unit tests.
if (process.env.TEST === "unit") {
process.env.BITDB_URL = "http://fakeurl/"
process.env.BITCOINCOM_BASEURL = "http://fakeurl/"
process.env.SLPDB_URL = "http://fakeurl/"
mockServerUrl = `http://fakeurl`
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'
}
// Prepare the slpRoute for stubbing dependcies on slpjs.
const slpRoute = require("../../src/routes/v3/slp")
const pathStub = {} // Used to stub methods within slpjs.
const slpRouteStub = proxyquire("../../src/routes/v3/slp", { slpjs: pathStub })
const slpRoute = require('../../src/routes/v3/slp')
// const pathStub = {} // Used to stub methods within slpjs.
// const slpRouteStub = proxyquire('../../src/routes/v3/slp', { slpjs: pathStub })
// Mocking data.
const { mockReq, mockRes } = require("./mocks/express-mocks")
const mockData = require("./mocks/slp-mocks")
const slpjsMock = require("./mocks/slpjs-mocks")
const { mockReq, mockRes } = require('./mocks/express-mocks')
const mockData = require('./mocks/slp-mocks')
// const slpjsMock = require('./mocks/slpjs-mocks')
// Used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
describe("#SLP", () => {
describe('#SLP', () => {
let req, res
let sandbox
@@ -91,15 +91,15 @@ describe("#SLP", () => {
process.env.SLPDB_URL = originalEnvVars.SLPDB_URL
})
describe("#root", async () => {
describe('#root', async () => {
// root route handler.
const root = slpRoute.testableComponents.root
it("should respond to GET for base route", async () => {
it('should respond to GET for base route', async () => {
const result = root(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(result.status, "slp", "Returns static string")
assert.equal(result.status, 'slp', 'Returns static string')
})
})
/*
@@ -430,46 +430,46 @@ describe("#SLP", () => {
})
})
*/
describe("balancesForAddress()", () => {
describe('balancesForAddress()', () => {
const balancesForAddress = slpRoute.testableComponents.balancesForAddress
it("should throw 400 if address is empty", async () => {
it('should throw 400 if address is empty', async () => {
const result = await balancesForAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "address can not be empty")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'address can not be empty')
})
it("should throw 400 if address is invalid", async () => {
req.params.address = "badAddress"
it('should throw 400 if address is invalid', async () => {
req.params.address = 'badAddress'
const result = await balancesForAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "Invalid BCH address.")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Invalid BCH address.')
})
it("should throw 400 if address network mismatch", async () => {
req.params.address = "slptest:qzcvpw3ah7r880d49wsqzrsl90pg0rqjjurmj3g4nk"
it('should throw 400 if address network mismatch', async () => {
req.params.address = 'slptest:qzcvpw3ah7r880d49wsqzrsl90pg0rqjjurmj3g4nk'
const result = await balancesForAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "Invalid")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Invalid')
})
it("should throw 5XX error when network issues", async () => {
it('should throw 5XX error when network issues', async () => {
// Save the existing SLPDB_URL.
const savedUrl2 = process.env.SLPDB_URL
// Manipulate the URL to cause a 500 network error.
process.env.SLPDB_URL = "http://fakeurl/api/"
process.env.SLPDB_URL = 'http://fakeurl/api/'
req.params.address =
"simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn"
'simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn'
const result = await balancesForAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
@@ -480,83 +480,83 @@ describe("#SLP", () => {
assert.isAbove(
res.statusCode,
499,
"HTTP status code 500 or greater expected."
'HTTP status code 500 or greater expected.'
)
assert.include(
result.error,
"Network error: Could not communicate",
"Error message expected"
'Network error: Could not communicate',
'Error message expected'
)
})
it("should get token balance for an address", async () => {
it('should get token balance for an address', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(mockServerUrl)
.get(uri => uri.includes("/"))
.get(uri => uri.includes('/'))
.times(2)
.reply(200, mockData.mockSingleAddress)
}
req.params.address =
"simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn"
'simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn'
const result = await balancesForAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAllKeys(result[0], [
"tokenId",
"balance",
"slpAddress",
"decimalCount"
'tokenId',
'balance',
'slpAddress',
'decimalCount'
])
})
})
describe("balancesForAddressBulk()", () => {
describe('balancesForAddressBulk()', () => {
const balancesForAddressBulk =
slpRoute.testableComponents.balancesForAddressBulk
it("should throw 400 if addresses is empty", async () => {
it('should throw 400 if addresses is empty', async () => {
const result = await balancesForAddressBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "addresses needs to be an array")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'addresses needs to be an array')
})
it("should throw 400 if address is invalid", async () => {
req.body.addresses = ["badAddress"]
it('should throw 400 if address is invalid', async () => {
req.body.addresses = ['badAddress']
const result = await balancesForAddressBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "Invalid BCH address.")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Invalid BCH address.')
})
it("should throw 400 if address network mismatch", async () => {
it('should throw 400 if address network mismatch', async () => {
req.body.addresses = [
"slptest:qzcvpw3ah7r880d49wsqzrsl90pg0rqjjurmj3g4nk"
'slptest:qzcvpw3ah7r880d49wsqzrsl90pg0rqjjurmj3g4nk'
]
const result = await balancesForAddressBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "Invalid")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Invalid')
})
it("should throw 5XX error when network issues", async () => {
it('should throw 5XX error when network issues', async () => {
// Save the existing SLPDB_URL.
const savedUrl2 = process.env.SLPDB_URL
// Manipulate the URL to cause a 500 network error.
process.env.SLPDB_URL = "http://fakeurl/api/"
process.env.SLPDB_URL = 'http://fakeurl/api/'
req.body.addresses = [
"simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn"
'simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn'
]
const result = await balancesForAddressBulk(req, res)
@@ -568,20 +568,20 @@ describe("#SLP", () => {
assert.isAbove(
res.statusCode,
499,
"HTTP status code 500 or greater expected."
'HTTP status code 500 or greater expected.'
)
assert.include(
result.error,
"Network error: Could not communicate",
"Error message expected"
'Network error: Could not communicate',
'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 () => {
if (process.env.TEST !== 'unit') {
it('should get token balance for an address', async () => {
req.body.addresses = [
"simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn"
'simpleledger:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5me5fdrdn'
]
const result = await balancesForAddressBulk(req, res)
@@ -590,11 +590,11 @@ describe("#SLP", () => {
assert.isArray(result)
assert.isArray(result[0])
assert.hasAnyKeys(result[0][0], [
"tokenId",
"balance",
"balanceString",
"slpAddress",
"decimalCount"
'tokenId',
'balance',
'balanceString',
'slpAddress',
'decimalCount'
])
})
}
@@ -807,112 +807,112 @@ describe("#SLP", () => {
})
})
*/
describe("validateBulk()", () => {
describe('validateBulk()', () => {
const validateBulk = slpRoute.testableComponents.validateBulk
it("should throw 400 if txid array is empty", async () => {
it('should throw 400 if txid array is empty', async () => {
const result = await validateBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "txids needs to be an array")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'txids needs to be an array')
assert.equal(res.statusCode, 400)
})
it("should throw 400 error if array is too large", async () => {
it('should throw 400 error if array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push("")
for (var i = 0; i < 25; i++) testArray.push('')
req.body.txids = testArray
const result = await validateBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "Array too large")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Array too large')
})
it("should validate array with single element", async () => {
it('should validate array with single element', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.SLPDB_URL}`)
.get(uri => uri.includes("/"))
.get(uri => uri.includes('/'))
.reply(200, mockData.mockSingleValidTxid)
}
req.body.txids = [
"77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d"
'77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d'
]
const result = await validateBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAllKeys(result[0], ["txid", "valid"])
assert.hasAllKeys(result[0], ['txid', 'valid'])
})
it("should validate array with two elements", async () => {
it('should validate array with two elements', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.SLPDB_URL}`)
.get(uri => uri.includes("/"))
.get(uri => uri.includes('/'))
.reply(200, mockData.mockTwoValidTxid)
}
req.body.txids = [
"77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d",
"552112f9e458dc7d1d8b328b0a6685e8af74a64b60b6846e7c86407f27f47e42"
'77872738b6bddee6c0cbdb9509603de20b15d4f6b26602f629417aec2f5d5e8d',
'552112f9e458dc7d1d8b328b0a6685e8af74a64b60b6846e7c86407f27f47e42'
]
const result = await validateBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAllKeys(result[0], ["txid", "valid"])
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 () => {
it('should return two elements if given two elements', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.SLPDB_URL}`)
.get(uri => uri.includes("/"))
.get(uri => uri.includes('/'))
.reply(200, mockData.mockTwoRedundentTxid)
}
req.body.txids = [
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56"
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56'
]
const result = await validateBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAllKeys(result[0], ["txid", "valid"])
assert.hasAllKeys(result[0], ['txid', 'valid'])
assert.equal(result.length, 2)
})
})
describe("tokenStatsSingle()", () => {
describe('tokenStatsSingle()', () => {
const tokenStatsSingle = slpRoute.testableComponents.tokenStats
it("should throw 400 if tokenID is empty", async () => {
req.params.tokenId = ""
it('should throw 400 if tokenID is empty', async () => {
req.params.tokenId = ''
const result = await tokenStatsSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "tokenId can not be empty")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'tokenId can not be empty')
})
//
it("should get token stats for tokenId", async () => {
it('should get token stats for tokenId', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.SLPDB_URL}`)
.get(uri => uri.includes("/"))
.get(uri => uri.includes('/'))
.reply(200, {
t: [
{
@@ -924,106 +924,106 @@ describe("#SLP", () => {
}
req.params.tokenId =
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
const result = await tokenStatsSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
"blockCreated",
"blockLastActiveMint",
"blockLastActiveSend",
"containsBaton",
"initialTokenQty",
"mintingBatonStatus",
"circulatingSupply",
"decimals",
"documentHash",
"versionType",
"timestamp",
"documentUri",
"name",
"symbol",
"id",
"totalBurned",
"totalMinted",
"txnsSinceGenesis",
"validAddresses"
'blockCreated',
'blockLastActiveMint',
'blockLastActiveSend',
'containsBaton',
'initialTokenQty',
'mintingBatonStatus',
'circulatingSupply',
'decimals',
'documentHash',
'versionType',
'timestamp',
'documentUri',
'name',
'symbol',
'id',
'totalBurned',
'totalMinted',
'txnsSinceGenesis',
'validAddresses'
])
})
})
describe("balancesForTokenSingle()", () => {
describe('balancesForTokenSingle()', () => {
const balancesForTokenSingle =
slpRoute.testableComponents.balancesForTokenSingle
it("should throw 400 if tokenID is empty", async () => {
req.params.tokenId = ""
it('should throw 400 if tokenID is empty', async () => {
req.params.tokenId = ''
const result = await balancesForTokenSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "tokenId can not be empty")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'tokenId can not be empty')
})
it("should get balances for tokenId", async () => {
it('should get balances for tokenId', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.SLPDB_URL}`)
.get(uri => uri.includes("/"))
.get(uri => uri.includes('/'))
.reply(200, {
a: [mockData.mockBalance]
})
}
req.params.tokenId =
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
const result = await balancesForTokenSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result[0], ["tokenId", "slpAddress", "tokenBalance"])
assert.hasAllKeys(result[0], ['tokenId', 'slpAddress', 'tokenBalance'])
})
})
describe("txDetails()", () => {
describe('txDetails()', () => {
const txDetails = slpRoute.testableComponents.txDetails
it("should throw 400 if txid is empty", async () => {
it('should throw 400 if txid is empty', async () => {
const result = await txDetails(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "txid can not be empty")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'txid can not be empty')
})
it("should throw 400 for malformed txid", async () => {
it('should throw 400 for malformed txid', async () => {
req.params.txid =
"57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457"
'57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b9457'
const result = await txDetails(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "This is not a txid")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'This is not a txid')
})
it("should throw 400 for non-existant txid", async () => {
it('should throw 400 for non-existant txid', async () => {
// Integration test
if (process.env.TEST !== "unit") {
if (process.env.TEST !== 'unit') {
req.params.txid =
"57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b94578223333"
'57b3082a2bf269b3d6f40fee7fb9c664e8256a88ca5ee2697c05b94578223333'
const result = await txDetails(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "TXID not found")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'TXID not found')
}
})
if (process.env.TEST === "integration") {
it("should get tx details with token info", async () => {
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?
@@ -1034,38 +1034,38 @@ describe("#SLP", () => {
// }
req.params.txid =
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
const result = await txDetails(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, ["tokenIsValid", "tokenInfo"])
assert.hasAnyKeys(result, ['tokenIsValid', 'tokenInfo'])
})
}
})
describe("txsTokenIdAddressSingle()", () => {
describe('txsTokenIdAddressSingle()', () => {
const txsTokenIdAddressSingle =
slpRoute.testableComponents.txsTokenIdAddressSingle
it("should throw 400 if tokenId is empty", async () => {
req.params.tokenId = ""
it('should throw 400 if tokenId is empty', async () => {
req.params.tokenId = ''
const result = await txsTokenIdAddressSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "tokenId can not be empty")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'tokenId can not be empty')
})
it("should throw 400 if address is empty", async () => {
it('should throw 400 if address is empty', async () => {
req.params.tokenId =
"495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a"
req.params.address = ""
'495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a'
req.params.address = ''
const result = await txsTokenIdAddressSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "address can not be empty")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'address can not be empty')
})
/*
it("should get tx details with tokenId and address", async () => {
@@ -1085,7 +1085,6 @@ describe("#SLP", () => {
"7ac7f4bb50b019fe0f5c81e3fc13fc0720e130282ea460768cafb49785eb2796"
req.params.address = "slptest:qpwa35xq0q0cnmdu0rwzkct369hddzsqpsqdzw6h9h"
const result = await txsTokenIdAddressSingle(req, res)
console.log(`result: ${JSON.stringify(result, null, 2)}`)
+150 -150
View File
@@ -6,27 +6,27 @@
to 'integration' to run the tests against BCH mainnet.
*/
"use strict"
'use strict'
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const utilRoute = require("../../src/routes/v3/util")
const nock = require("nock") // HTTP mocking
const sinon = require("sinon")
const utilRoute = require('../../src/routes/v3/util')
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/util-mocks")
const { mockReq, mockRes } = require('./mocks/express-mocks')
const mockData = require('./mocks/util-mocks')
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
const UtilRoute = utilRoute.UtilRoute
// const UtilRoute = utilRoute.UtilRoute
const utilRouteInst = new utilRoute.UtilRoute()
describe("#Util", () => {
describe('#Util', () => {
let req, res
let sandbox
@@ -40,12 +40,12 @@ describe("#Util", () => {
}
// Set default environment variables for unit tests.
if (!process.env.TEST) process.env.TEST = "unit"
if (process.env.TEST === "unit") {
process.env.BITCOINCOM_BASEURL = "http://fakeurl/api/"
process.env.RPC_BASEURL = "http://fakeurl/api"
process.env.RPC_USERNAME = "fakeusername"
process.env.RPC_PASSWORD = "fakepassword"
if (!process.env.TEST) process.env.TEST = 'unit'
if (process.env.TEST === 'unit') {
process.env.BITCOINCOM_BASEURL = 'http://fakeurl/api/'
process.env.RPC_BASEURL = 'http://fakeurl/api'
process.env.RPC_USERNAME = 'fakeusername'
process.env.RPC_PASSWORD = 'fakepassword'
}
})
@@ -82,42 +82,42 @@ describe("#Util", () => {
process.env.RPC_PASSWORD = originalEnvVars.RPC_PASSWORD
})
describe("#root", async () => {
describe('#root', async () => {
// root route handler.
const root = utilRouteInst.root
it("should respond to GET for base route", async () => {
it('should respond to GET for base route', async () => {
const result = root(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(result.status, "util", "Returns static string")
assert.equal(result.status, 'util', 'Returns static string')
})
})
describe("#validateAddressSingle", async () => {
describe('#validateAddressSingle', async () => {
const validateAddress = utilRouteInst.validateAddressSingle
it("should throw an error for an empty address", async () => {
it('should throw an error for an empty address', async () => {
const result = await validateAddress(req, res)
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
"address can not be empty",
"Proper error message"
'address can not be empty',
'Proper error message'
)
})
it("should throw 503 when network issues", async () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = "http://fakeurl/api/"
process.env.RPC_BASEURL = 'http://fakeurl/api/'
req.params.address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
req.params.address = 'bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y'
const result = await validateAddress(req, res)
await validateAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Restore the saved URL.
@@ -126,119 +126,119 @@ describe("#Util", () => {
assert.isAbove(
res.statusCode,
499,
"HTTP status code 500 or greater expected."
'HTTP status code 500 or greater expected.'
)
// assert.include(result.error,"Network error: Could not communicate with full node","Error message expected")
})
it("should validate address", async () => {
it('should validate address', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.RPC_BASEURL}`)
.post(uri => uri.includes("/"))
.post(uri => uri.includes('/'))
.reply(200, { result: mockData.mockAddress })
}
req.params.address = `bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd`
req.params.address = 'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd'
const result = await validateAddress(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
"isvalid",
"address",
"scriptPubKey",
"ismine",
"iswatchonly",
"isscript"
'isvalid',
'address',
'scriptPubKey',
'ismine',
'iswatchonly',
'isscript'
])
})
})
describe("#validateAddressBulk", async () => {
describe('#validateAddressBulk', async () => {
const validateAddressBulk = utilRouteInst.validateAddressBulk
it("should throw an error for an empty body", async () => {
it('should throw an error for an empty body', async () => {
const result = await validateAddressBulk(req, res)
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
"addresses needs to be an array. Use GET for single address.",
"Proper error message"
'addresses needs to be an array. Use GET for single address.',
'Proper error message'
)
})
it("should error on non-array single address", async () => {
it('should error on non-array single address', async () => {
req.body = {
addresses: `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
addresses: 'bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y'
}
const result = await validateAddressBulk(req, res)
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
"addresses needs to be an array. Use GET for single address.",
"Proper error message"
'addresses needs to be an array. Use GET for single address.',
'Proper error message'
)
})
it("should throw 400 error if addresses array is too large", async () => {
it('should throw 400 error if addresses array is too large', async () => {
const testArray = []
for (var i = 0; i < 25; i++) testArray.push("")
for (var i = 0; i < 25; i++) testArray.push('')
req.body.addresses = testArray
const result = await validateAddressBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "Array too large")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'Array too large')
})
it("should error on invalid address", async () => {
it('should error on invalid address', async () => {
req.body = {
addresses: [`bchtest:qqqk4y6lsl5da64sg5qc3xezmpl`]
addresses: ['bchtest:qqqk4y6lsl5da64sg5qc3xezmpl']
}
const result = await validateAddressBulk(req, res)
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
"Invalid BCH address. Double check your address is valid",
"Proper error message"
'Invalid BCH address. Double check your address is valid',
'Proper error message'
)
})
it("should error on mainnet address when using testnet", async () => {
it('should error on mainnet address when using testnet', async () => {
req.body = {
addresses: [`bchtest:qrls6vzjkkxlds7aqv9075u0fttwc7u9jvczn5fdt9`]
addresses: ['bchtest:qrls6vzjkkxlds7aqv9075u0fttwc7u9jvczn5fdt9']
}
const result = await validateAddressBulk(req, res)
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
"Invalid network. Trying to use a testnet address on mainnet, or vice versa.",
"Proper error message"
'Invalid network. Trying to use a testnet address on mainnet, or vice versa.',
'Proper error message'
)
})
it("should throw 503 when network issues", async () => {
it('should throw 503 when network issues', async () => {
// Save the existing RPC URL.
const savedUrl2 = process.env.RPC_BASEURL
// Manipulate the URL to cause a 500 network error.
process.env.RPC_BASEURL = "http://fakeurl/api/"
process.env.RPC_BASEURL = 'http://fakeurl/api/'
req.body.addresses = [
`bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd`
'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd'
]
const result = await validateAddressBulk(req, res)
await validateAddressBulk(req, res)
// console.log(`result: ${util.inspect(result)}`)
// Restore the saved URL.
@@ -247,20 +247,20 @@ describe("#Util", () => {
assert.isAbove(
res.statusCode,
499,
"HTTP status code 500 or greater expected."
'HTTP status code 500 or greater expected.'
)
})
it("should validate a single address", async () => {
it('should validate a single address', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.RPC_BASEURL}`)
.post(uri => uri.includes("/"))
.post(uri => uri.includes('/'))
.reply(200, { result: mockData.mockAddress })
}
req.body.addresses = [
`bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd`
'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd'
]
const result = await validateAddressBulk(req, res)
@@ -268,27 +268,27 @@ describe("#Util", () => {
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"isvalid",
"address",
"scriptPubKey",
"ismine",
"iswatchonly",
"isscript"
'isvalid',
'address',
'scriptPubKey',
'ismine',
'iswatchonly',
'isscript'
])
})
it("should validate a multiple addresses", async () => {
it('should validate a multiple addresses', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
nock(`${process.env.RPC_BASEURL}`)
.post(uri => uri.includes("/"))
.post(uri => uri.includes('/'))
.times(2)
.reply(200, { result: mockData.mockAddress })
}
req.body.addresses = [
`bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd`,
`bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd`
'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd',
'bitcoincash:qpujxqra3jmdlzzapwmmt7uspr7q0c9ff5hzljcrnd'
]
const result = await validateAddressBulk(req, res)
@@ -296,108 +296,108 @@ describe("#Util", () => {
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"isvalid",
"address",
"scriptPubKey",
"ismine",
"iswatchonly",
"isscript"
'isvalid',
'address',
'scriptPubKey',
'ismine',
'iswatchonly',
'isscript'
])
})
})
describe("#sweepWif", () => {
it("should throw 400 if WIF is not included", async () => {
describe('#sweepWif', () => {
it('should throw 400 if WIF is not included', async () => {
req.body = {}
const result = await utilRouteInst.sweepWif(req, res)
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
"WIF needs to a proper compressed WIF starting with K or L",
"Proper error message"
'WIF needs to a proper compressed WIF starting with K or L',
'Proper error message'
)
})
it("should throw 400 if WIF is malformed", async () => {
it('should throw 400 if WIF is malformed', async () => {
req.body = {
wif: `abc123`
wif: 'abc123'
}
const result = await utilRouteInst.sweepWif(req, res)
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
"WIF needs to a proper compressed WIF starting with K or L",
"Proper error message"
'WIF needs to a proper compressed WIF starting with K or L',
'Proper error message'
)
})
it("should throw 400 if destination address is not included", async () => {
it('should throw 400 if destination address is not included', async () => {
req.body = {
wif: "L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt"
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt'
}
const result = await utilRouteInst.sweepWif(req, res)
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
"address can not be empty",
"Proper error message"
'address can not be empty',
'Proper error message'
)
})
// Unit test only.
if (process.env.TEST === "unit") {
it("should generate transaction for valid token sweep", async () => {
if (process.env.TEST === 'unit') {
it('should generate transaction for valid token sweep', async () => {
// Mock the RPC call for unit tests.
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
"balanceFromBlockbook"
'balanceFromBlockbook'
)
.resolves(mockData.mockBalance)
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
"utxosFromBlockbook"
'utxosFromBlockbook'
)
.resolves(mockData.mockUtxos)
sandbox
.stub(utilRouteInst.bchjs.SLP.Utils, "tokenUtxoDetails")
.stub(utilRouteInst.bchjs.SLP.Utils, 'tokenUtxoDetails')
.resolves(mockData.mockIsTokenUtxos)
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRouteInst.bchjs.RawTransactions, "sendRawTransaction")
.resolves("test-txid")
.stub(utilRouteInst.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: "L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt",
toAddr: "bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p"
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt',
toAddr: 'bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p'
}
const result = await utilRouteInst.sweepWif(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, "test-txid")
assert.equal(result, 'test-txid')
})
}
it("should return balance if balance-only is true", async () => {
it('should return balance if balance-only is true', async () => {
// Mock the RPC call for unit tests.
if (process.env.TEST === "unit") {
if (process.env.TEST === 'unit') {
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
"balanceFromBlockbook"
'balanceFromBlockbook'
)
.resolves(mockData.mockBalance)
}
@@ -405,11 +405,11 @@ describe("#Util", () => {
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRouteInst.bchjs.RawTransactions, "sendRawTransaction")
.resolves("test-txid")
.stub(utilRouteInst.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: "L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt",
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt',
balanceOnly: true
}
@@ -420,125 +420,125 @@ describe("#Util", () => {
})
// Unit tests only
if (process.env.TEST === "unit") {
it("should generate transaction for valid BCH-only sweep", async () => {
if (process.env.TEST === 'unit') {
it('should generate transaction for valid BCH-only sweep', async () => {
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
"balanceFromBlockbook"
'balanceFromBlockbook'
)
.resolves(mockData.mockBalance)
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
"utxosFromBlockbook"
'utxosFromBlockbook'
)
.resolves(mockData.mockUtxos)
// Force token utxo to appear as regular BCH utxo.
sandbox
.stub(utilRouteInst.bchjs.SLP.Utils, "tokenUtxoDetails")
.stub(utilRouteInst.bchjs.SLP.Utils, 'tokenUtxoDetails')
.resolves([false, false])
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRouteInst.bchjs.RawTransactions, "sendRawTransaction")
.resolves("test-txid")
.stub(utilRouteInst.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: "L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt",
toAddr: "bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p"
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt',
toAddr: 'bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p'
}
const result = await utilRouteInst.sweepWif(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, "test-txid")
assert.equal(result, 'test-txid')
})
it("should throw 422 error if no non-token UTXOs", async () => {
it('should throw 422 error if no non-token UTXOs', async () => {
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
"balanceFromBlockbook"
'balanceFromBlockbook'
)
.resolves(mockData.mockBalance)
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
"utxosFromBlockbook"
'utxosFromBlockbook'
)
.resolves(mockData.mockUtxos)
// Force token utxo to appear as regular BCH utxo.
sandbox
.stub(utilRouteInst.bchjs.SLP.Utils, "tokenUtxoDetails")
.stub(utilRouteInst.bchjs.SLP.Utils, 'tokenUtxoDetails')
.resolves(mockData.tokensOnly)
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRouteInst.bchjs.RawTransactions, "sendRawTransaction")
.resolves("test-txid")
.stub(utilRouteInst.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: "L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt",
toAddr: "bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p"
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt',
toAddr: 'bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p'
}
const result = await utilRouteInst.sweepWif(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(res.statusCode, 422)
assert.property(result, "error")
assert.property(result, 'error')
assert.include(
result.error,
"Tokens found, but no BCH UTXOs found. Add BCH to wallet to move tokens"
'Tokens found, but no BCH UTXOs found. Add BCH to wallet to move tokens'
)
})
it("should detect and throw error for multiple token classes", async () => {
it('should detect and throw error for multiple token classes', async () => {
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
"balanceFromBlockbook"
'balanceFromBlockbook'
)
.resolves(mockData.mockBalance)
sandbox
.stub(
utilRouteInst.blockbook.testableComponents,
"utxosFromBlockbook"
'utxosFromBlockbook'
)
.resolves(mockData.mockThreeUtxos)
// Force token utxo to appear as regular BCH utxo.
sandbox
.stub(utilRouteInst.bchjs.SLP.Utils, "tokenUtxoDetails")
.stub(utilRouteInst.bchjs.SLP.Utils, 'tokenUtxoDetails')
.resolves(mockData.multipleTokens)
// Mock sendRawTransaction() so that the hex does not actually get broadcast
// to the network.
sandbox
.stub(utilRouteInst.bchjs.RawTransactions, "sendRawTransaction")
.resolves("test-txid")
.stub(utilRouteInst.bchjs.RawTransactions, 'sendRawTransaction')
.resolves('test-txid')
req.body = {
wif: "L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt",
toAddr: "bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p"
wif: 'L5GEFg1tETLWBugmhSo9Zc4ms968qVmfmTroDxsJ982AiudAQGyt',
toAddr: 'bitcoincash:qz2qn6zt4qmacf4r6c0e2pdcqsgnkxaa3ql2xpee6p'
}
const result = await utilRouteInst.sweepWif(req, res)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(res.statusCode, 422)
assert.property(result, "error")
assert.property(result, 'error')
assert.include(
result.error,
"Multiple token classes detected. This function only supports a single class of token"
'Multiple token classes detected. This function only supports a single class of token'
)
})
}
+24 -24
View File
@@ -6,29 +6,29 @@
to 'integration' to run the tests against BCH mainnet.
*/
"use strict"
'use strict'
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const xpubRoute = require("../../src/routes/v3/xpub")
const nock = require("nock") // HTTP mocking
const xpubRoute = require('../../src/routes/v3/xpub')
const nock = require('nock') // HTTP mocking
let originalUrl // Used during transition from integration to unit tests.
// let originalUrl // Used during transition from integration to unit tests.
// Mocking data.
const { mockReq, mockRes } = require("./mocks/express-mocks")
const mockData = require("./mocks/address-mock")
const { mockReq, mockRes } = require('./mocks/express-mocks')
// const mockData = require('./mocks/address-mock')
// Used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
describe("#XPUBRouter", () => {
describe('#XPUBRouter', () => {
let req, res
before(() => {
// Set default environment variables for unit tests.
if (!process.env.TEST) process.env.TEST = "unit"
if (!process.env.TEST) process.env.TEST = 'unit'
// if (process.env.TEST === "unit")
// process.env.BITCOINCOM_BASEURL = "http://fakeurl/api
})
@@ -58,41 +58,41 @@ describe("#XPUBRouter", () => {
// process.env.BITCOINCOM_BASEURL = originalUrl
})
describe("#root", () => {
describe('#root', () => {
// root route handler.
const root = xpubRoute.testableComponents.root
it("should respond to GET for base route", async () => {
it('should respond to GET for base route', async () => {
const result = root(req, res)
assert.equal(result.status, "address", "Returns static string")
assert.equal(result.status, 'address', 'Returns static string')
})
})
describe("#FromXPubSingle", () => {
describe('#FromXPubSingle', () => {
// details route handler.
const fromXPubSingle = xpubRoute.testableComponents.fromXPubSingle
it("should throw 400 if xpub is empty", async () => {
it('should throw 400 if xpub is empty', async () => {
const result = await fromXPubSingle(req, res)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAllKeys(result, ["error"])
assert.include(result.error, "xpub can not be empty")
assert.hasAllKeys(result, ['error'])
assert.include(result.error, 'xpub can not be empty')
})
it("should error on an array", async () => {
it('should error on an array', async () => {
req.params.xpub = [
`tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
'tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM'
]
const result = await fromXPubSingle(req, res)
assert.equal(res.statusCode, 400, "HTTP status code 400 expected.")
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
assert.include(
result.error,
"xpub can not be an array",
"Proper error message"
'xpub can not be an array',
'Proper error message'
)
})
/*
@@ -118,8 +118,8 @@ describe("#XPUBRouter", () => {
}
})
*/
it("should create an address from xpub", async () => {
req.params.xpub = `tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM`
it('should create an address from xpub', async () => {
req.params.xpub = 'tpubDHTK2jqg73w3GwoiHfAMbMYML1HN8FhrUxD9rFgbSgHXdwwrY6pAFqKDfUHhqw7vreaZty5hPGjb1S7ZPQeMmu6TFHAKfY9tJpYbvaGjPRM'
// Mock the Insight URL for unit tests.
// TODO add unit test