Browse Source

Microoptimizations and JSdoc improvements

Pavel Ševčík 4 years ago
parent
commit
1ace9d6fe9
No known key found for this signature in database GPG Key ID: CFA54E4C0CD58DF0
  1. 2
      accounts/fees-rest-api.js
  2. 2
      accounts/headers-rest-api.js
  3. 51
      accounts/multiaddr-rest-api.js
  4. 14
      accounts/notifications-service.js
  5. 2
      accounts/status-rest-api.js
  6. 6
      accounts/status.js
  7. 18
      accounts/support-rest-api.js
  8. 4
      accounts/transactions-rest-api.js
  9. 2
      accounts/unspent-rest-api.js
  10. 2
      accounts/wallet-rest-api.js
  11. 16
      accounts/xpub-rest-api.js
  12. 2
      docker/my-dojo/node/keys.index.js
  13. 6
      lib/auth/authorizations-manager.js
  14. 3
      lib/auth/localapikey-strategy-configurator.js
  15. 36
      lib/bitcoin/addresses-helper.js
  16. 12
      lib/bitcoin/addresses-service.js
  17. 46
      lib/bitcoin/hd-accounts-helper.js
  18. 32
      lib/bitcoin/hd-accounts-service.js
  19. 10
      lib/bitcoin/parallel-address-derivation.js
  20. 4
      lib/bitcoind-rpc/fees.js
  21. 2
      lib/bitcoind-rpc/rpc-client.js
  22. 12
      lib/bitcoind-rpc/transactions.js
  23. 159
      lib/db/mysql-db-wrapper.js
  24. 3
      lib/http-server/http-server.js
  25. 11
      lib/indexer-rpc/rpc-client.js
  26. 4
      lib/remote-importer/esplora-wrapper.js
  27. 2
      lib/remote-importer/local-indexer-wrapper.js
  28. 2
      lib/remote-importer/local-rest-indexer-wrapper.js
  29. 4
      lib/remote-importer/oxt-wrapper.js
  30. 14
      lib/remote-importer/remote-importer.js
  31. 6
      lib/remote-importer/sources-mainnet.js
  32. 6
      lib/remote-importer/sources-testnet.js
  33. 3
      lib/remote-importer/wrapper.js
  34. 118
      lib/util.js
  35. 34
      lib/wallet/address-info.js
  36. 37
      lib/wallet/hd-account-info.js
  37. 21
      lib/wallet/wallet-entities.js
  38. 48
      lib/wallet/wallet-info.js
  39. 28
      lib/wallet/wallet-service.js
  40. 8
      pushtx/orchestrator.js
  41. 4
      pushtx/pushtx-processor.js
  42. 4
      pushtx/pushtx-rest-api.js
  43. 8
      pushtx/transactions-scheduler.js
  44. 14
      scripts/patches/revert-hd-accounts.js
  45. 20
      scripts/patches/translate-hd-accounts.js
  46. 2
      static/admin/dmt/index.js
  47. 10
      static/admin/dmt/status/status.js
  48. 8
      static/admin/dmt/xpubs-tools/xpubs-tools.js
  49. 4
      static/admin/lib/auth-utils.js
  50. 8
      static/admin/lib/common-script.js
  51. 2
      static/admin/lib/errors-utils.js
  52. 2
      static/admin/lib/format-utils.js
  53. 10
      tracker/block-worker.js
  54. 16
      tracker/block.js
  55. 26
      tracker/blockchain-processor.js
  56. 8
      tracker/blocks-processor.js
  57. 15
      tracker/mempool-processor.js
  58. 2
      tracker/tracker.js
  59. 16
      tracker/transaction.js
  60. 17
      tracker/transactions-bundle.js

2
accounts/fees-rest-api.js

@ -9,7 +9,7 @@ const rpcFees = require('../lib/bitcoind-rpc/fees')
const authMgr = require('../lib/auth/authorizations-manager') const authMgr = require('../lib/auth/authorizations-manager')
const HttpServer = require('../lib/http-server/http-server') const HttpServer = require('../lib/http-server/http-server')
const debugApi = !!(process.argv.indexOf('api-debug') > -1) const debugApi = process.argv.indexOf('api-debug') > -1
/** /**

2
accounts/headers-rest-api.js

@ -12,7 +12,7 @@ const authMgr = require('../lib/auth/authorizations-manager')
const HttpServer = require('../lib/http-server/http-server') const HttpServer = require('../lib/http-server/http-server')
const apiHelper = require('./api-helper') const apiHelper = require('./api-helper')
const debugApi = !!(process.argv.indexOf('api-debug') > -1) const debugApi = process.argv.indexOf('api-debug') > -1
/** /**

51
accounts/multiaddr-rest-api.js

@ -12,7 +12,7 @@ const authMgr = require('../lib/auth/authorizations-manager')
const HttpServer = require('../lib/http-server/http-server') const HttpServer = require('../lib/http-server/http-server')
const apiHelper = require('./api-helper') const apiHelper = require('./api-helper')
const debugApi = !!(process.argv.indexOf('api-debug') > -1) const debugApi = process.argv.indexOf('api-debug') > -1
/** /**
@ -32,18 +32,20 @@ class MultiaddrRestApi {
const urlencodedParser = bodyParser.urlencoded({ extended: true }) const urlencodedParser = bodyParser.urlencoded({ extended: true })
this.httpServer.app.get( this.httpServer.app.get(
'/multiaddr', '/multiaddr',
authMgr.checkAuthentication.bind(authMgr), authMgr.checkAuthentication.bind(authMgr),
apiHelper.validateEntitiesParams.bind(apiHelper), apiHelper.validateEntitiesParams.bind(apiHelper),
this.getMultiaddr.bind(this), this.getMultiaddr.bind(this),
HttpServer.sendAuthError
) )
this.httpServer.app.post( this.httpServer.app.post(
'/multiaddr', '/multiaddr',
urlencodedParser, urlencodedParser,
authMgr.checkAuthentication.bind(authMgr), authMgr.checkAuthentication.bind(authMgr),
apiHelper.validateEntitiesParams.bind(apiHelper), apiHelper.validateEntitiesParams.bind(apiHelper),
this.postMultiaddr.bind(this), this.postMultiaddr.bind(this),
HttpServer.sendAuthError
) )
} }
@ -57,16 +59,19 @@ class MultiaddrRestApi {
// Check request params // Check request params
if (!apiHelper.checkEntitiesParams(req.query)) if (!apiHelper.checkEntitiesParams(req.query))
return HttpServer.sendError(res, errors.multiaddr.NOACT) return HttpServer.sendError(res, errors.multiaddr.NOACT)
//return HttpServer.sendError(res, '')
// Parse params // Parse params
const entities = apiHelper.parseEntitiesParams(req.query) const entities = apiHelper.parseEntitiesParams(req.query)
if (entities.active.addrs.length === 1 || entities.active.addrs.length === 2 || entities.active.xpubs.length === 1)
return HttpServer.sendError(res, '')
const result = await walletService.getWalletInfo( const result = await walletService.getWalletInfo(
entities.active, entities.active,
entities.legacy, entities.legacy,
entities.bip49, entities.bip49,
entities.bip84, entities.bip84,
entities.pubkey entities.pubkey
) )
const ret = JSON.stringify(result, null, 2) const ret = JSON.stringify(result, null, 2)
@ -78,7 +83,7 @@ class MultiaddrRestApi {
} finally { } finally {
if (debugApi) { if (debugApi) {
const strParams = const strParams =
`${req.query.active ? req.query.active : ''} \ `${req.query.active ? req.query.active : ''} \
${req.query.new ? req.query.new : ''} \ ${req.query.new ? req.query.new : ''} \
${req.query.pubkey ? req.query.pubkey : ''} \ ${req.query.pubkey ? req.query.pubkey : ''} \
${req.query.bip49 ? req.query.bip49 : ''} \ ${req.query.bip49 ? req.query.bip49 : ''} \
@ -104,11 +109,11 @@ class MultiaddrRestApi {
const entities = apiHelper.parseEntitiesParams(req.body) const entities = apiHelper.parseEntitiesParams(req.body)
const result = await walletService.getWalletInfo( const result = await walletService.getWalletInfo(
entities.active, entities.active,
entities.legacy, entities.legacy,
entities.bip49, entities.bip49,
entities.bip84, entities.bip84,
entities.pubkey entities.pubkey
) )
HttpServer.sendOkDataOnly(res, result) HttpServer.sendOkDataOnly(res, result)
@ -119,7 +124,7 @@ class MultiaddrRestApi {
} finally { } finally {
if (debugApi) { if (debugApi) {
const strParams = const strParams =
`${req.body.active ? req.body.active : ''} \ `${req.body.active ? req.body.active : ''} \
${req.body.new ? req.body.new : ''} \ ${req.body.new ? req.body.new : ''} \
${req.body.pubkey ? req.body.pubkey : ''} \ ${req.body.pubkey ? req.body.pubkey : ''} \
${req.body.bip49 ? req.body.bip49 : ''} \ ${req.body.bip49 ? req.body.bip49 : ''} \

14
accounts/notifications-service.js

@ -14,7 +14,7 @@ const apiHelper = require('./api-helper')
const status = require('./status') const status = require('./status')
const authMgr = require('../lib/auth/authorizations-manager') const authMgr = require('../lib/auth/authorizations-manager')
const debug = !!(process.argv.indexOf('ws-debug') > -1) const debug = process.argv.indexOf('ws-debug') > -1
/** /**
@ -80,7 +80,7 @@ class NotificationsService {
}) })
conn.on('message', msg => { conn.on('message', msg => {
if (msg.type == 'utf8') if (msg.type === 'utf8')
this._handleWSMessage(msg.utf8Data, conn) this._handleWSMessage(msg.utf8Data, conn)
else else
this._closeWSConnection(conn, true) this._closeWSConnection(conn, true)
@ -229,7 +229,7 @@ class NotificationsService {
/** /**
* Unsubscribe from a topic * Unsubscribe from a topic
* @param {string} topic - topic * @param {string} topic - topic
* @param {int} cid - client id * @param {number} cid - client id
*/ */
_unsub(topic, cid) { _unsub(topic, cid) {
if (!this.subs[topic]) if (!this.subs[topic])
@ -241,7 +241,7 @@ class NotificationsService {
this.subs[topic].splice(index, 1) this.subs[topic].splice(index, 1)
if (this.subs[topic].length == 0) { if (this.subs[topic].length === 0) {
delete this.subs[topic] delete this.subs[topic]
if (this.cachePubKeys.hasOwnProperty(topic)) if (this.cachePubKeys.hasOwnProperty(topic))
delete this.cachePubKeys[topic] delete this.cachePubKeys[topic]
@ -391,7 +391,7 @@ class NotificationsService {
for (let cid of this.subs[topic]) { for (let cid of this.subs[topic]) {
if (!clients[cid]) if (!clients[cid])
clients[cid] = [] clients[cid] = []
if (clients[cid].indexOf(topic) == -1) if (clients[cid].indexOf(topic) === -1)
clients[cid].push(topic) clients[cid].push(topic)
} }
} }
@ -429,7 +429,7 @@ class NotificationsService {
} }
// Move on if the custom transaction has no inputs or outputs // Move on if the custom transaction has no inputs or outputs
if (ctx.inputs.length == 0 && ctx.out.length == 0) if (ctx.inputs.length === 0 && ctx.out.length === 0)
continue continue
// Send custom transaction to client // Send custom transaction to client
@ -454,7 +454,7 @@ class NotificationsService {
/** /**
* Dispatch notification for an authentication error * Dispatch notification for an authentication error
* @param {string} err - error * @param {string} err - error
* @param {integer} cid - connection id * @param {number} cid - connection id
*/ */
notifyAuthError(err, cid) { notifyAuthError(err, cid) {
const data = { const data = {

2
accounts/status-rest-api.js

@ -11,7 +11,7 @@ const authMgr = require('../lib/auth/authorizations-manager')
const HttpServer = require('../lib/http-server/http-server') const HttpServer = require('../lib/http-server/http-server')
const status = require('./status') const status = require('./status')
const debugApi = !!(process.argv.indexOf('api-debug') > -1) const debugApi = process.argv.indexOf('api-debug') > -1
/** /**

6
accounts/status.js

@ -29,7 +29,7 @@ class Status {
/** /**
* Get current status * Get current status
* @returns {Promise - object} status object * @returns {Promise<object>} status object
*/ */
async getCurrent() { async getCurrent() {
const uptime = util.timePeriod((Date.now() - this.t0) / 1000, false) const uptime = util.timePeriod((Date.now() - this.t0) / 1000, false)
@ -49,8 +49,8 @@ class Status {
let indexerMaxHeight = null let indexerMaxHeight = null
let indexerUrl = null let indexerUrl = null
if (indexerType == 'third_party_explorer') { if (indexerType === 'third_party_explorer') {
indexerUrl = (network.key == 'bitcoin') indexerUrl = (network.key === 'bitcoin')
? keys.indexer.oxt ? keys.indexer.oxt
: keys.indexer.esplora : keys.indexer.esplora
} }

18
accounts/support-rest-api.js

@ -19,7 +19,7 @@ const AddressInfo = require('../lib/wallet/address-info')
const apiHelper = require('./api-helper') const apiHelper = require('./api-helper')
const keys = require('../keys')[network.key] const keys = require('../keys')[network.key]
const debugApi = !!(process.argv.indexOf('api-debug') > -1) const debugApi = process.argv.indexOf('api-debug') > -1
/** /**
@ -94,7 +94,7 @@ class SupportRestApi {
try { try {
// Parse the entities passed as url params // Parse the entities passed as url params
const entities = apiHelper.parseEntities(req.params.addr).addrs const entities = apiHelper.parseEntities(req.params.addr).addrs
if (entities.length == 0) if (entities.length === 0)
return HttpServer.sendError(res, errors.address.INVALID) return HttpServer.sendError(res, errors.address.INVALID)
const address = entities[0] const address = entities[0]
@ -133,7 +133,7 @@ class SupportRestApi {
try { try {
// Parse the entities passed as url params // Parse the entities passed as url params
const entities = apiHelper.parseEntities(req.params.addr).addrs const entities = apiHelper.parseEntities(req.params.addr).addrs
if (entities.length == 0) if (entities.length === 0)
return HttpServer.sendError(res, errors.address.INVALID) return HttpServer.sendError(res, errors.address.INVALID)
const address = entities[0] const address = entities[0]
@ -162,7 +162,7 @@ class SupportRestApi {
try { try {
// Parse the entities passed as url params // Parse the entities passed as url params
const entities = apiHelper.parseEntities(req.params.xpub).xpubs const entities = apiHelper.parseEntities(req.params.xpub).xpubs
if (entities.length == 0) if (entities.length === 0)
return HttpServer.sendError(res, errors.xpub.INVALID) return HttpServer.sendError(res, errors.xpub.INVALID)
const xpub = entities[0] const xpub = entities[0]
@ -174,7 +174,7 @@ class SupportRestApi {
const ret = this._formatXpubInfoResult(info) const ret = this._formatXpubInfoResult(info)
HttpServer.sendRawData(res, ret) HttpServer.sendRawData(res, ret)
} catch(e) { } catch(e) {
if(e == errors.db.ERROR_NO_HD_ACCOUNT) { if(e === errors.db.ERROR_NO_HD_ACCOUNT) {
const ret = this._formatXpubInfoResult(info) const ret = this._formatXpubInfoResult(info)
HttpServer.sendRawData(res, ret) HttpServer.sendRawData(res, ret)
} else { } else {
@ -210,7 +210,7 @@ class SupportRestApi {
try { try {
// Parse the entities passed as url params // Parse the entities passed as url params
const entities = apiHelper.parseEntities(req.params.xpub).xpubs const entities = apiHelper.parseEntities(req.params.xpub).xpubs
if (entities.length == 0) if (entities.length === 0)
return HttpServer.sendError(res, errors.xpub.INVALID) return HttpServer.sendError(res, errors.xpub.INVALID)
const xpub = entities[0] const xpub = entities[0]
@ -226,10 +226,10 @@ class SupportRestApi {
await hdaService.rescan(xpub, gapLimit, startIndex) await hdaService.rescan(xpub, gapLimit, startIndex)
HttpServer.sendRawData(res, JSON.stringify(ret, null, 2)) HttpServer.sendRawData(res, JSON.stringify(ret, null, 2))
} catch(e) { } catch(e) {
if (e == errors.db.ERROR_NO_HD_ACCOUNT) { if (e === errors.db.ERROR_NO_HD_ACCOUNT) {
ret.status = 'Error: Not tracking xpub' ret.status = 'Error: Not tracking xpub'
HttpServer.sendRawData(res, JSON.stringify(ret, null, 2)) HttpServer.sendRawData(res, JSON.stringify(ret, null, 2))
} else if (e == errors.xpub.OVERLAP) { } else if (e === errors.xpub.OVERLAP) {
ret.status = 'Error: Rescan in progress' ret.status = 'Error: Rescan in progress'
HttpServer.sendRawData(res, JSON.stringify(ret, null, 2)) HttpServer.sendRawData(res, JSON.stringify(ret, null, 2))
} else { } else {
@ -256,7 +256,7 @@ class SupportRestApi {
try { try {
// Parse the entities passed as url params // Parse the entities passed as url params
const entities = apiHelper.parseEntities(req.params.xpub).xpubs const entities = apiHelper.parseEntities(req.params.xpub).xpubs
if (entities.length == 0) if (entities.length === 0)
return HttpServer.sendError(res, errors.xpub.INVALID) return HttpServer.sendError(res, errors.xpub.INVALID)
const xpub = entities[0] const xpub = entities[0]

4
accounts/transactions-rest-api.js

@ -15,7 +15,7 @@ const network = require('../lib/bitcoin/network')
const apiHelper = require('./api-helper') const apiHelper = require('./api-helper')
const keys = require('../keys')[network.key] const keys = require('../keys')[network.key]
const debugApi = !!(process.argv.indexOf('api-debug') > -1) const debugApi = process.argv.indexOf('api-debug') > -1
/** /**
@ -86,7 +86,7 @@ class TransactionsRestApi {
const result = await walletService.getWalletTransactions(active, page, count) const result = await walletService.getWalletTransactions(active, page, count)
if (excludeNullXfer) { if (excludeNullXfer) {
result.txs = result.txs.filter(tx => { result.txs = result.txs.filter(tx => {
return tx['result'] != 0 return tx['result'] !== 0
}) })
} }

2
accounts/unspent-rest-api.js

@ -12,7 +12,7 @@ const authMgr = require('../lib/auth/authorizations-manager')
const HttpServer = require('../lib/http-server/http-server') const HttpServer = require('../lib/http-server/http-server')
const apiHelper = require('./api-helper') const apiHelper = require('./api-helper')
const debugApi = !!(process.argv.indexOf('api-debug') > -1) const debugApi = process.argv.indexOf('api-debug') > -1
/** /**

2
accounts/wallet-rest-api.js

@ -12,7 +12,7 @@ const authMgr = require('../lib/auth/authorizations-manager')
const HttpServer = require('../lib/http-server/http-server') const HttpServer = require('../lib/http-server/http-server')
const apiHelper = require('./api-helper') const apiHelper = require('./api-helper')
const debugApi = !!(process.argv.indexOf('api-debug') > -1) const debugApi = process.argv.indexOf('api-debug') > -1
/** /**

16
accounts/xpub-rest-api.js

@ -113,9 +113,9 @@ class XPubRestApi {
if (argSegwit) { if (argSegwit) {
const segwit = argSegwit.toLowerCase() const segwit = argSegwit.toLowerCase()
if (segwit == 'bip49') if (segwit === 'bip49')
scheme = hdaHelper.BIP49 scheme = hdaHelper.BIP49
else if (segwit == 'bip84') else if (segwit === 'bip84')
scheme = hdaHelper.BIP84 scheme = hdaHelper.BIP84
else else
return HttpServer.sendError(res, errors.xpub.SEGWIT) return HttpServer.sendError(res, errors.xpub.SEGWIT)
@ -125,7 +125,7 @@ class XPubRestApi {
const forceOverride = argForceOverride ? argForceOverride : false const forceOverride = argForceOverride ? argForceOverride : false
// Process action // Process action
if (argAction == 'new') { if (argAction === 'new') {
// New hd account // New hd account
try { try {
await hdaService.createHdAccount(xpub, scheme) await hdaService.createHdAccount(xpub, scheme)
@ -133,7 +133,7 @@ class XPubRestApi {
} catch(e) { } catch(e) {
HttpServer.sendError(res, e) HttpServer.sendError(res, e)
} }
} else if (argAction == 'restore') { } else if (argAction === 'restore') {
// Restore hd account // Restore hd account
try { try {
await hdaService.restoreHdAccount(xpub, scheme, forceOverride) await hdaService.restoreHdAccount(xpub, scheme, forceOverride)
@ -229,7 +229,7 @@ class XPubRestApi {
if (status != null) { if (status != null) {
ret['import_in_progress'] = true ret['import_in_progress'] = true
ret['status'] = status['status'] ret['status'] = status['status']
if (ret['status'] == remoteImporter.STATUS_RESCAN) if (ret['status'] === remoteImporter.STATUS_RESCAN)
ret['hits'] = status['txs_int'] + status['txs_ext'] ret['hits'] = status['txs_int'] + status['txs_ext']
else else
ret['hits'] = status['txs'] ret['hits'] = status['txs']
@ -268,7 +268,7 @@ class XPubRestApi {
if (!req.body.message) if (!req.body.message)
return HttpServer.sendError(res, errors.body.NOMSG) return HttpServer.sendError(res, errors.body.NOMSG)
if (!(req.body.message == 'lock' || req.body.message == 'unlock')) if (!(req.body.message === 'lock' || req.body.message === 'unlock'))
return HttpServer.sendError(res, errors.sig.INVMSG) return HttpServer.sendError(res, errors.sig.INVMSG)
// Extract arguments // Extract arguments
@ -289,7 +289,7 @@ class XPubRestApi {
try { try {
// Check the signature and process the request // Check the signature and process the request
await hdaService.verifyXpubSignature(xpub, argAddr, argSig, argMsg, scheme) await hdaService.verifyXpubSignature(xpub, argAddr, argSig, argMsg, scheme)
const lock = (argMsg == 'unlock') ? false : true const lock = argMsg !== 'unlock'
const ret = await hdaService.lockHdAccount(xpub, lock) const ret = await hdaService.lockHdAccount(xpub, lock)
HttpServer.sendOkData(res, {derivation: ret}) HttpServer.sendOkData(res, {derivation: ret})
} catch(e) { } catch(e) {
@ -385,7 +385,7 @@ class XPubRestApi {
} }
} catch(e) { } catch(e) {
const err = (e == errors.xpub.PRIVKEY) ? e : errors.xpub.INVALID const err = (e === errors.xpub.PRIVKEY) ? e : errors.xpub.INVALID
throw err throw err
} }
} }

2
docker/my-dojo/node/keys.index.js

@ -14,7 +14,7 @@ const bitcoinNetwork = (process.env.COMMON_BTC_NETWORK == 'testnet')
let explorerActive = 'oxt' let explorerActive = 'oxt'
let explorerUrl = 'https://oxt.me' let explorerUrl = 'https://oxt.me'
let explorerPassword = '' let explorerPassword = ''
if (process.env.EXPLORER_INSTALL == 'on') { if (process.env.EXPLORER_INSTALL === 'on') {
try { try {
explorerUrl = fs.readFileSync('/var/lib/tor/hsv3explorer/hostname', 'utf8').replace('\n', '') explorerUrl = fs.readFileSync('/var/lib/tor/hsv3explorer/hostname', 'utf8').replace('\n', '')
explorerPassword = process.env.EXPLORER_KEY explorerPassword = process.env.EXPLORER_KEY

6
lib/auth/authorizations-manager.js

@ -162,7 +162,7 @@ class AuthorizationsManager {
try { try {
const decodedToken = this.isAuthenticated(token) const decodedToken = this.isAuthenticated(token)
if (decodedToken['prf'] == this.TOKEN_PROFILE_ADMIN) { if (decodedToken['prf'] === this.TOKEN_PROFILE_ADMIN) {
req.authorizations = {decoded_access_token: decodedToken} req.authorizations = {decoded_access_token: decodedToken}
next() next()
} else { } else {
@ -249,7 +249,7 @@ class AuthorizationsManager {
{algorithms: [this.JWT_ALGO]} {algorithms: [this.JWT_ALGO]}
) )
if (payload['type'] != this.TOKEN_TYPE_ACCESS) if (payload['type'] !== this.TOKEN_TYPE_ACCESS)
throw errors.auth.INVALID_JWT throw errors.auth.INVALID_JWT
return payload return payload
@ -309,7 +309,7 @@ class AuthorizationsManager {
{algorithms: [this.JWT_ALGO]} {algorithms: [this.JWT_ALGO]}
) )
if (payload['type'] != this.TOKEN_TYPE_REFRESH) if (payload['type'] !== this.TOKEN_TYPE_REFRESH)
throw errors.auth.INVALID_JWT throw errors.auth.INVALID_JWT
return payload return payload

3
lib/auth/localapikey-strategy-configurator.js

@ -33,7 +33,6 @@ class LocalApiKeyStrategyConfigurator {
/** /**
* Authentication * Authentication
* @param {object} req - http request object
* @param {string} apiKey - api key received * @param {string} apiKey - api key received
* @param {function} done - callback * @param {function} done - callback
*/ */
@ -41,7 +40,7 @@ class LocalApiKeyStrategyConfigurator {
const _adminKey = keys.auth.strategies[LocalApiKeyStrategyConfigurator.NAME].adminKey const _adminKey = keys.auth.strategies[LocalApiKeyStrategyConfigurator.NAME].adminKey
const _apiKeys = keys.auth.strategies[LocalApiKeyStrategyConfigurator.NAME].apiKeys const _apiKeys = keys.auth.strategies[LocalApiKeyStrategyConfigurator.NAME].apiKeys
if (apiKey == _adminKey) { if (apiKey === _adminKey) {
// Check if received key is a valid api key // Check if received key is a valid api key
Logger.info('Auth : Successful authentication with an admin key') Logger.info('Auth : Successful authentication with an admin key')
return done(null, {'profile': authorzMgr.TOKEN_PROFILE_ADMIN}) return done(null, {'profile': authorzMgr.TOKEN_PROFILE_ADMIN})

36
lib/bitcoin/addresses-helper.js

@ -77,7 +77,7 @@ class AddressesHelper {
* @returns {boolean} return true if str is a supported pubkey format, false otherwise * @returns {boolean} return true if str is a supported pubkey format, false otherwise
*/ */
isSupportedPubKey(str) { isSupportedPubKey(str) {
return (str.length == 66 && (str.startsWith('02') || str.startsWith('03'))) return (str.length === 66 && (str.startsWith('02') || str.startsWith('03')))
} }
/** /**
@ -97,7 +97,7 @@ class AddressesHelper {
/** /**
* Get the script hash associated to a Bech32 address * Get the script hash associated to a Bech32 address
* @param {string} str - bech32 address * @param {string} str - bech32 address
* @returns {string} script hash in hex format * @returns {string | null} script hash in hex format
*/ */
getScriptHashFromBech32(str) { getScriptHashFromBech32(str) {
try { try {
@ -114,12 +114,12 @@ class AddressesHelper {
* @returns {boolean} return true if output is a P2PKH script, otherwise return false * @returns {boolean} return true if output is a P2PKH script, otherwise return false
*/ */
isP2pkhScript(scriptpubkey) { isP2pkhScript(scriptpubkey) {
return scriptpubkey.length == 25 return scriptpubkey.length === 25
&& scriptpubkey[0] == OPS.OP_DUP && scriptpubkey[0] === OPS.OP_DUP
&& scriptpubkey[1] == OPS.OP_HASH160 && scriptpubkey[1] === OPS.OP_HASH160
&& scriptpubkey[2] == 0x14 && scriptpubkey[2] === 0x14
&& scriptpubkey[23] == OPS.OP_EQUALVERIFY && scriptpubkey[23] === OPS.OP_EQUALVERIFY
&& scriptpubkey[24] == OPS.OP_CHECKSIG && scriptpubkey[24] === OPS.OP_CHECKSIG
} }
/** /**
@ -128,10 +128,10 @@ class AddressesHelper {
* @returns {boolean} return true if output is a P2SH script, otherwise return false * @returns {boolean} return true if output is a P2SH script, otherwise return false
*/ */
isP2shScript(scriptpubkey) { isP2shScript(scriptpubkey) {
return scriptpubkey.length == 23 return scriptpubkey.length === 23
&& scriptpubkey[0] == OPS.OP_HASH160 && scriptpubkey[0] === OPS.OP_HASH160
&& scriptpubkey[1] == 0x14 && scriptpubkey[1] === 0x14
&& scriptpubkey[22] == OPS.OP_EQUAL && scriptpubkey[22] === OPS.OP_EQUAL
} }
/** /**
@ -140,9 +140,9 @@ class AddressesHelper {
* @returns {boolean} return true if output is a P2WPKH script, otherwise return false * @returns {boolean} return true if output is a P2WPKH script, otherwise return false
*/ */
isP2wpkhScript(scriptpubkey) { isP2wpkhScript(scriptpubkey) {
return scriptpubkey.length == 22 return scriptpubkey.length === 22
&& scriptpubkey[0] == OPS.OP_0 && scriptpubkey[0] === OPS.OP_0
&& scriptpubkey[1] == 0x14 && scriptpubkey[1] === 0x14
} }
/** /**
@ -151,9 +151,9 @@ class AddressesHelper {
* @returns {boolean} return true if output is a P2WSH script, otherwise return false * @returns {boolean} return true if output is a P2WSH script, otherwise return false
*/ */
isP2wshScript(scriptpubkey) { isP2wshScript(scriptpubkey) {
return scriptpubkey.length == 34 return scriptpubkey.length === 34
&& scriptpubkey[0] == OPS.OP_0 && scriptpubkey[0] === OPS.OP_0
&& scriptpubkey[1] == 0x20 && scriptpubkey[1] === 0x20
} }
/** /**

12
lib/bitcoin/addresses-service.js

@ -21,24 +21,24 @@ class AddressesService {
/** /**
* Rescan the blockchain for an address * Rescan the blockchain for an address
* @param {string} address - bitcoin address * @param {string} address - bitcoin address
* @returns {Promise} * @returns {Promise<boolean | undefined>}
*/ */
async rescan(address) { async rescan(address) {
const hdaccount = await db.getUngroupedHDAccountsByAddresses([address]) const hdaccount = await db.getUngroupedHDAccountsByAddresses([address])
// Don't filter addresses associated to an HDAccount // Don't filter addresses associated to an HDAccount
const filterAddr = !(hdaccount.length > 0 && hdaccount[0]['hdID']) const filterAddr = !(hdaccount.length > 0 && hdaccount[0]['hdID'])
return remote.importAddresses([address], filterAddr) return await remote.importAddresses([address], filterAddr)
} }
/** /**
* Restore an address in db * Restore an address in db
* @param {string[]} addresses - array of bitcoin addresses * @param {string[]} addresses - array of bitcoin addresses
* @param {boolean} filterAddr - true if addresses should be filter, false otherwise * @param {boolean} filterAddr - true if addresses should be filter, false otherwise
* @returns {Promise} * @returns {Promise<boolean | undefined>}
*/ */
async restoreAddresses(address, filterAddr) { async restoreAddresses(addresses, filterAddr) {
return remote.importAddresses(address, filterAddr) return await remote.importAddresses(addresses, filterAddr)
} }
} }
module.exports = new AddressesService() module.exports = new AddressesService()

46
lib/bitcoin/hd-accounts-helper.js

@ -81,7 +81,7 @@ class HDAccountsHelper {
* @returns {boolean} returns true if xpub encodes a xpub/tpub, false otherwise * @returns {boolean} returns true if xpub encodes a xpub/tpub, false otherwise
*/ */
isXpub(xpub) { isXpub(xpub) {
return (xpub.indexOf('xpub') == 0) || (xpub.indexOf('tpub') == 0) return (xpub.indexOf('xpub') === 0) || (xpub.indexOf('tpub') === 0)
} }
/** /**
@ -90,7 +90,7 @@ class HDAccountsHelper {
* @returns {boolean} returns true if xpub encodes a ypub/upub, false otherwise * @returns {boolean} returns true if xpub encodes a ypub/upub, false otherwise
*/ */
isYpub(xpub) { isYpub(xpub) {
return (xpub.indexOf('ypub') == 0) || (xpub.indexOf('upub') == 0) return (xpub.indexOf('ypub') === 0) || (xpub.indexOf('upub') === 0)
} }
/** /**
@ -99,7 +99,7 @@ class HDAccountsHelper {
* @returns {boolean} returns true if xpub encodes a zpub/vpub, false otherwise * @returns {boolean} returns true if xpub encodes a zpub/vpub, false otherwise
*/ */
isZpub(xpub) { isZpub(xpub) {
return (xpub.indexOf('zpub') == 0) || (xpub.indexOf('vpub') == 0) return (xpub.indexOf('zpub') === 0) || (xpub.indexOf('vpub') === 0)
} }
/** /**
@ -114,12 +114,12 @@ class HDAccountsHelper {
const ver = decoded.readInt32BE() const ver = decoded.readInt32BE()
if ( if (
ver != this.MAGIC_XPUB ver !== this.MAGIC_XPUB
&& ver != this.MAGIC_TPUB && ver !== this.MAGIC_TPUB
&& ver != this.MAGIC_YPUB && ver !== this.MAGIC_YPUB
&& ver != this.MAGIC_UPUB && ver !== this.MAGIC_UPUB
&& ver != this.MAGIC_ZPUB && ver !== this.MAGIC_ZPUB
&& ver != this.MAGIC_VPUB && ver !== this.MAGIC_VPUB
) { ) {
//Logger.error(null, 'HdAccountsHelper : xlatXPUB() : Incorrect format') //Logger.error(null, 'HdAccountsHelper : xlatXPUB() : Incorrect format')
return '' return ''
@ -165,7 +165,7 @@ class HDAccountsHelper {
/** /**
* Classify the hd account type retrieved from db * Classify the hd account type retrieved from db
* @param {integer} v - HD Account type (db encoding) * @param {number} v - HD Account type (db encoding)
* @returns {object} object storing the type and lock status of the hd account * @returns {object} object storing the type and lock status of the hd account
*/ */
classify(v) { classify(v) {
@ -194,9 +194,9 @@ class HDAccountsHelper {
/** /**
* Encode hd account type and lock status in db format * Encode hd account type and lock status in db format
* @param {integer} type - HD Account type (db encoding) * @param {number} type - HD Account type (db encoding)
* @param {boolean} locked - lock status of the hd account * @param {boolean} locked - lock status of the hd account
* @returns {integer} * @returns {number}
*/ */
makeType(type, locked) { makeType(type, locked) {
let p = let p =
@ -214,7 +214,7 @@ class HDAccountsHelper {
/** /**
* Return a string representation of the hd account type * Return a string representation of the hd account type
* @param {integer} v - HD Account type (db encoding) * @param {number} v - HD Account type (db encoding)
* @returns {string} * @returns {string}
*/ */
typeString(v) { typeString(v) {
@ -268,7 +268,7 @@ class HDAccountsHelper {
return true return true
} catch(e) { } catch(e) {
if (e == errors.xpub.PRIVKEY) throw e if (e === errors.xpub.PRIVKEY) throw e
return false return false
} }
} }
@ -287,12 +287,12 @@ class HDAccountsHelper {
/** /**
* Derives an address for an hd account * Derives an address for an hd account
* @param {int} chain - chain to be derived * @param {number} chain - chain to be derived
* must have a value on [0,1] for BIP44/BIP49/BIP84 derivation * must have a value on [0,1] for BIP44/BIP49/BIP84 derivation
* @param {bip32} chainNode - Parent bip32 used for derivation * @param {bip32} chainNode - Parent bip32 used for derivation
* @param {int} index - index to be derived * @param {number} index - index to be derived
* @param {int} type - type of derivation * @param {number} type - type of derivation
* @returns {Promise - object} returns an object {address: '...', chain: <int>, index: <int>} * @returns {Promise<object>} returns an object {address: '...', chain: <int>, index: <int>}
*/ */
async deriveAddress(chain, chainNode, index, type) { async deriveAddress(chain, chainNode, index, type) {
// Derive M/chain/index // Derive M/chain/index
@ -321,11 +321,11 @@ class HDAccountsHelper {
/** /**
* Derives addresses for an hd account * Derives addresses for an hd account
* @param {string} xpub - hd account to be derived * @param {string} xpub - hd account to be derived
* @param {int} chain - chain to be derived * @param {number} chain - chain to be derived
* must have a value on [0,1] for BIP44/BIP49/BIP84 derivation * must have a value on [0,1] for BIP44/BIP49/BIP84 derivation
* @param {int[]} indices - array of indices to be derived * @param {number[]} indices - array of indices to be derived
* @param {int} type - type of derivation * @param {number} type - type of derivation
* @returns {Promise - object[]} array of {address: '...', chain: <int>, index: <int>} * @returns {Promise<object[]>} array of {address: '...', chain: <int>, index: <int>}
*/ */
async deriveAddresses(xpub, chain, indices, type) { async deriveAddresses(xpub, chain, indices, type) {
const ret = [] const ret = []
@ -374,7 +374,7 @@ class HDAccountsHelper {
const msg = await this.derivationPool.exec('deriveAddresses', [data]) const msg = await this.derivationPool.exec('deriveAddresses', [data])
if (msg.status = 'ok') { if (msg.status === 'ok') {
resolve(msg.addresses) resolve(msg.addresses)
} else { } else {
Logger.error(null, 'HdAccountsHelper : A problem was met during parallel addresses derivation') Logger.error(null, 'HdAccountsHelper : A problem was met during parallel addresses derivation')

32
lib/bitcoin/hd-accounts-service.js

@ -29,7 +29,7 @@ class HDAccountsService {
/** /**
* Create a new hd account in db * Create a new hd account in db
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @param {int} scheme - derivation scheme * @param {number} scheme - derivation scheme
* @returns {Promise} returns true if success, false otherwise * @returns {Promise} returns true if success, false otherwise
*/ */
async createHdAccount(xpub, scheme) { async createHdAccount(xpub, scheme) {
@ -37,8 +37,8 @@ class HDAccountsService {
await this.newHdAccount(xpub, scheme) await this.newHdAccount(xpub, scheme)
return true return true
} catch(e) { } catch(e) {
const isInvalidXpub = (e == errors.xpub.INVALID || e == errors.xpub.PRIVKEY) const isInvalidXpub = (e === errors.xpub.INVALID || e === errors.xpub.PRIVKEY)
const isLockedXpub = (e == errors.xpub.LOCKED) const isLockedXpub = (e === errors.xpub.LOCKED)
const err = (isInvalidXpub || isLockedXpub) ? e : errors.xpub.CREATE const err = (isInvalidXpub || isLockedXpub) ? e : errors.xpub.CREATE
Logger.error(e, 'HdAccountsService : createHdAccount()' + err) Logger.error(e, 'HdAccountsService : createHdAccount()' + err)
return Promise.reject(err) return Promise.reject(err)
@ -49,7 +49,7 @@ class HDAccountsService {
/** /**
* Restore a hd account in db * Restore a hd account in db
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @param {int} scheme - derivation scheme * @param {number} scheme - derivation scheme
* @param {bool} forceOverride - force override of scheme even if hd account is locked * @param {bool} forceOverride - force override of scheme even if hd account is locked
* @returns {Promise} * @returns {Promise}
*/ */
@ -96,7 +96,7 @@ class HDAccountsService {
return hdaHelper.typeString(type) return hdaHelper.typeString(type)
} catch(e) { } catch(e) {
const err = (e == errors.db.ERROR_NO_HD_ACCOUNT) ? errors.get.UNKNXPUB : errors.generic.DB const err = (e === errors.db.ERROR_NO_HD_ACCOUNT) ? errors.get.UNKNXPUB : errors.generic.DB
return Promise.reject(err) return Promise.reject(err)
} }
} }
@ -110,7 +110,7 @@ class HDAccountsService {
try { try {
await db.deleteHDAccount(xpub) await db.deleteHDAccount(xpub)
} catch(e) { } catch(e) {
const err = (e == errors.db.ERROR_NO_HD_ACCOUNT) ? errors.get.UNKNXPUB : errors.generic.DB const err = (e === errors.db.ERROR_NO_HD_ACCOUNT) ? errors.get.UNKNXPUB : errors.generic.DB
return Promise.reject(err) return Promise.reject(err)
} }
} }
@ -134,11 +134,11 @@ class HDAccountsService {
let segwit = '' let segwit = ''
if (scheme == hdaHelper.BIP49) if (scheme === hdaHelper.BIP49)
segwit = ' SegWit (BIP49)' segwit = ' SegWit (BIP49)'
else if (scheme == hdaHelper.BIP84) else if (scheme === hdaHelper.BIP84)
segwit = ' SegWit (BIP84)' segwit = ' SegWit (BIP84)'
Logger.info(`HdAccountsService : Created HD Account: ${xpub}${segwit}`) Logger.info(`HdAccountsService : Created HD Account: ${xpub}${segwit}`)
const externalPrm = hdaHelper.deriveAddresses(xpub, 0, _.range(gap.external), scheme) const externalPrm = hdaHelper.deriveAddresses(xpub, 0, _.range(gap.external), scheme)
@ -152,8 +152,8 @@ class HDAccountsService {
/** /**
* Rescan the blockchain for a hd account * Rescan the blockchain for a hd account
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @param {integer} gapLimit - (optional) gap limit for derivation * @param {number} gapLimit - (optional) gap limit for derivation
* @param {integer} startIndex - (optional) rescan shall start from this index * @param {number} startIndex - (optional) rescan shall start from this index
* @returns {Promise} * @returns {Promise}
*/ */
async rescan(xpub, gapLimit, startIndex) { async rescan(xpub, gapLimit, startIndex) {
@ -165,7 +165,7 @@ class HDAccountsService {
await remote.importHDAccount(xpub, account.hdType, gapLimit, startIndex) await remote.importHDAccount(xpub, account.hdType, gapLimit, startIndex)
} catch(e) { } catch(e) {
return Promise.reject(e) return Promise.reject(e)
} }
} }
/** /**
@ -201,7 +201,7 @@ class HDAccountsService {
const info = hdaHelper.classify(account.hdType) const info = hdaHelper.classify(account.hdType)
// If this account is already known in the database, // If this account is already known in the database,
// check for a derivation scheme mismatch // check for a derivation scheme mismatch
if (info.type != scheme) { if (info.type !== scheme) {
if (info.locked && !forceOverride) { if (info.locked && !forceOverride) {
Logger.info(`HdAccountsService : Attempted override on locked account: ${xpub}`) Logger.info(`HdAccountsService : Attempted override on locked account: ${xpub}`)
return Promise.reject(errors.xpub.LOCKED) return Promise.reject(errors.xpub.LOCKED)
@ -224,7 +224,7 @@ class HDAccountsService {
* @param {string} address - address used to sign the message * @param {string} address - address used to sign the message
* @param {string} sig - signature of the message * @param {string} sig - signature of the message
* @param {string} msg - signed message * @param {string} msg - signed message
* @param {integer} scheme - derivation scheme to be used for the xpub * @param {number} scheme - derivation scheme to be used for the xpub
* @returns {Promise} returns the xpub if signature is valid, otherwise returns an error * @returns {Promise} returns the xpub if signature is valid, otherwise returns an error
*/ */
async verifyXpubSignature(xpub, address, sig, msg, scheme) { async verifyXpubSignature(xpub, address, sig, msg, scheme) {
@ -242,12 +242,12 @@ class HDAccountsService {
if (!addrHelper.verifySignature(msg, sigAddress, sig)) if (!addrHelper.verifySignature(msg, sigAddress, sig))
return Promise.reject(errors.sig.INVSIG) return Promise.reject(errors.sig.INVSIG)
// Check that adresses match // Check that adresses match
if (address != expectedAddress) if (address !== expectedAddress)
return Promise.reject(errors.sig.INVADDR) return Promise.reject(errors.sig.INVADDR)
// Return the corresponding xpub // Return the corresponding xpub
return xpub return xpub
} catch(err) { } catch(err) {
const ret = (err == errors.db.ERROR_NO_HD_ACCOUNT) ? errors.get.UNKNXPUB : errors.generic.DB const ret = (err === errors.db.ERROR_NO_HD_ACCOUNT) ? errors.get.UNKNXPUB : errors.generic.DB
return Promise.reject(ret) return Promise.reject(ret)
} }
} }

10
lib/bitcoin/parallel-address-derivation.js

@ -20,12 +20,12 @@ const BIP84 = 2
/** /**
* Derives an address for an hd account * Derives an address for an hd account
* @param {int} chain - chain to be derived * @param {number} chain - chain to be derived
* must have a value on [0,1] for BIP44/BIP49/BIP84 derivation * must have a value on [0,1] for BIP44/BIP49/BIP84 derivation
* @param {bip32} chainNode - Parent bip32 used for derivation * @param {bip32} chainNode - Parent bip32 used for derivation
* @param {int} index - index to be derived * @param {number} index - index to be derived
* @param {int} type - type of derivation * @param {number} type - type of derivation
* @returns {Promise - object} returns an object {address: '...', chain: <int>, index: <int>} * @returns {Promise<object>} returns an object {address: '...', chain: <int>, index: <int>}
*/ */
async function deriveAddress(chain, chainNode, index, type) { async function deriveAddress(chain, chainNode, index, type) {
// Derive M/chain/index // Derive M/chain/index
@ -54,7 +54,7 @@ async function deriveAddress(chain, chainNode, index, type) {
/** /**
* Derives a set of addresses for an hd account * Derives a set of addresses for an hd account
* @param {object} msg - parameters used for the derivation * @param {object} msg - parameters used for the derivation
* @returns {Promise - object[]} * @returns {Promise<object[]>}
*/ */
async function deriveAddresses(msg) { async function deriveAddresses(msg) {
try { try {

4
lib/bitcoind-rpc/fees.js

@ -34,7 +34,7 @@ class Fees {
/** /**
* Refresh and return the current fees * Refresh and return the current fees
* @returns {Promise} * @returns {Promise<object>}
*/ */
async getFees() { async getFees() {
try { try {
@ -50,7 +50,7 @@ class Fees {
/** /**
* Refresh the current fees * Refresh the current fees
* @returns {Promise} * @returns {Promise<void>}
*/ */
async refresh() { async refresh() {
await util.parallelCall(this.targets, async tgt => { await util.parallelCall(this.targets, async tgt => {

2
lib/bitcoind-rpc/rpc-client.js

@ -30,7 +30,7 @@ const createRpcClient = () => {
* @returns {boolean} returns true if message related to a connection error * @returns {boolean} returns true if message related to a connection error
*/ */
const isConnectionError = (err) => { const isConnectionError = (err) => {
if (typeof err != 'string') if (typeof err !== 'string')
return false return false
const isTimeoutError = (err.indexOf('connect ETIMEDOUT') !== -1) const isTimeoutError = (err.indexOf('connect ETIMEDOUT') !== -1)

12
lib/bitcoind-rpc/transactions.js

@ -41,7 +41,7 @@ class Transactions {
* Get the transactions for a given array of txids * Get the transactions for a given array of txids
* @param {string[]} txids - txids of the transaction to be retrieved * @param {string[]} txids - txids of the transaction to be retrieved
* @param {boolean} fees - true if fees must be computed, false otherwise * @param {boolean} fees - true if fees must be computed, false otherwise
* @returns {Promise} return an array of transactions (object[]) * @returns {Promise<object[]>} return an array of transactions (object[])
*/ */
async getTransactions(txids, fees) { async getTransactions(txids, fees) {
try { try {
@ -76,7 +76,7 @@ class Transactions {
* Get the transaction for a given txid * Get the transaction for a given txid
* @param {string} txid - txid of the transaction to be retrieved * @param {string} txid - txid of the transaction to be retrieved
* @param {boolean} fees - true if fees must be computed, false otherwise * @param {boolean} fees - true if fees must be computed, false otherwise
* @returns {Promise} * @returns {Promise<object[]>}
*/ */
async getTransaction(txid, fees) { async getTransaction(txid, fees) {
try { try {
@ -92,7 +92,7 @@ class Transactions {
* Formats a transaction object returned by the RPC API * Formats a transaction object returned by the RPC API
* @param {object} tx - transaction * @param {object} tx - transaction
* @param {boolean} fees - true if fees must be computed, false otherwise * @param {boolean} fees - true if fees must be computed, false otherwise
* @returns {Promise} return an array of inputs (object[]) * @returns {Promise<object[]>} return an array of inputs (object[])
*/ */
async _prepareTxResult(tx, fees) { async _prepareTxResult(tx, fees) {
const ret = { const ret = {
@ -148,7 +148,7 @@ class Transactions {
* Extract information about the inputs of a transaction * Extract information about the inputs of a transaction
* @param {object} tx - transaction * @param {object} tx - transaction
* @param {boolean} fees - true if fees must be computed, false otherwise * @param {boolean} fees - true if fees must be computed, false otherwise
* @returns {Promise} return an array of inputs (object[]) * @returns {Promise<object[]>} return an array of inputs (object[])
*/ */
async _getInputs(tx, fees) { async _getInputs(tx, fees) {
const inputs = [] const inputs = []
@ -202,7 +202,7 @@ class Transactions {
/** /**
* Extract information about the outputs of a transaction * Extract information about the outputs of a transaction
* @param {object} tx - transaction * @param {object} tx - transaction
* @returns {Promise} return an array of outputs (object[]) * @returns {Promise<object[]>} return an array of outputs (object[])
*/ */
async _getOutputs(tx) { async _getOutputs(tx) {
const outputs = [] const outputs = []
@ -220,7 +220,7 @@ class Transactions {
} }
if (pk.addresses) { if (pk.addresses) {
if (pk.addresses.length == 1) if (pk.addresses.length === 1)
o.address = pk.addresses[0] o.address = pk.addresses[0]
else else
o.addresses = pk.addresses o.addresses = pk.addresses

159
lib/db/mysql-db-wrapper.js

@ -11,8 +11,8 @@ const errors = require('../errors')
const hdaHelper = require('../bitcoin/hd-accounts-helper') const hdaHelper = require('../bitcoin/hd-accounts-helper')
const network = require('../bitcoin/network') const network = require('../bitcoin/network')
const keys = require('../../keys/')[network.key] const keys = require('../../keys/')[network.key]
const debug = !!(process.argv.indexOf('db-debug') > -1) const debug = process.argv.indexOf('db-debug') > -1
const queryDebug = !!(process.argv.indexOf('dbquery-debug') > -1) const queryDebug = process.argv.indexOf('dbquery-debug') > -1
/** /**
@ -387,9 +387,9 @@ class MySqlDbWrapper {
this.pool.query(query, null, async (err, result, fields) => { this.pool.query(query, null, async (err, result, fields) => {
if (err) { if (err) {
// Retry the request on lock errors // Retry the request on lock errors
if ((err.code == 'ER_LOCK_DEADLOCK' || if ((err.code === 'ER_LOCK_DEADLOCK' ||
err.code == 'ER_LOCK_TIMEOUT' || err.code === 'ER_LOCK_TIMEOUT' ||
err.code == 'ER_LOCK_WAIT_TIMEOUT') && (retries > 0) err.code === 'ER_LOCK_WAIT_TIMEOUT') && (retries > 0)
) { ) {
try { try {
this.queryError('Lock detected. Retry request in a few ms', query) this.queryError('Lock detected. Retry request in a few ms', query)
@ -426,7 +426,7 @@ class MySqlDbWrapper {
/** /**
* Get the ID of an address * Get the ID of an address
* @param {string} address - bitcoin address * @param {string} address - bitcoin address
* @returns {integer} returns the address id * @returns {number} returns the address id
*/ */
async getAddressId(address) { async getAddressId(address) {
const sqlQuery = 'SELECT `addrID` FROM `addresses` WHERE `addrAddress` = ?' const sqlQuery = 'SELECT `addrID` FROM `addresses` WHERE `addrAddress` = ?'
@ -443,7 +443,7 @@ class MySqlDbWrapper {
/** /**
* Get the ID of an Address. Ensures that the address exists. * Get the ID of an Address. Ensures that the address exists.
* @param {string} address - bitcoin address * @param {string} address - bitcoin address
* @returns {integer} returns the address id * @returns {number} returns the address id
*/ */
async ensureAddressId(address) { async ensureAddressId(address) {
const sqlQuery = 'SELECT `addrID` FROM `addresses` WHERE `addrAddress` = ?' const sqlQuery = 'SELECT `addrID` FROM `addresses` WHERE `addrAddress` = ?'
@ -469,7 +469,7 @@ class MySqlDbWrapper {
async getAddressesIds(addresses) { async getAddressesIds(addresses) {
const ret = {} const ret = {}
if (addresses.length == 0) if (addresses.length === 0)
return ret return ret
const sqlQuery = 'SELECT * FROM `addresses` WHERE `addrAddress` IN (?)' const sqlQuery = 'SELECT * FROM `addresses` WHERE `addrAddress` IN (?)'
@ -488,7 +488,7 @@ class MySqlDbWrapper {
* @param {string[]} addresses - array of bitcoin addresses * @param {string[]} addresses - array of bitcoin addresses
*/ */
async addAddresses(addresses) { async addAddresses(addresses) {
if (addresses.length == 0) if (addresses.length === 0)
return [] return []
const sqlQuery = 'INSERT IGNORE INTO `addresses` (addrAddress) VALUES ?' const sqlQuery = 'INSERT IGNORE INTO `addresses` (addrAddress) VALUES ?'
@ -502,7 +502,7 @@ class MySqlDbWrapper {
* @param {string[]} addresses - array of bitcoin addresses * @param {string[]} addresses - array of bitcoin addresses
*/ */
async getAddresses(addresses) { async getAddresses(addresses) {
if (addresses.length == 0) if (addresses.length === 0)
return [] return []
const sqlQuery = 'SELECT * FROM `addresses` WHERE `addrAddress` IN (?)' const sqlQuery = 'SELECT * FROM `addresses` WHERE `addrAddress` IN (?)'
@ -514,7 +514,7 @@ class MySqlDbWrapper {
/** /**
* Get address balance. * Get address balance.
* @param {string} address - bitcoin address * @param {string} address - bitcoin address
* @returns {integer} returns the balance of the address * @returns {number} returns the balance of the address
*/ */
async getAddressBalance(address) { async getAddressBalance(address) {
if (address == null) if (address == null)
@ -532,7 +532,7 @@ class MySqlDbWrapper {
const query = mysql.format(sqlQuery, params) const query = mysql.format(sqlQuery, params)
const results = await this._query(query) const results = await this._query(query)
if (results.length == 1) { if (results.length === 1) {
const balance = results[0].balance const balance = results[0].balance
return (balance == null) ? 0 : balance return (balance == null) ? 0 : balance
} }
@ -543,7 +543,7 @@ class MySqlDbWrapper {
/** /**
* Get the number of transactions for an address. * Get the number of transactions for an address.
* @param {string} address - bitcoin address * @param {string} address - bitcoin address
* @returns {integer} returns the number of transactions for the address * @returns {number} returns the number of transactions for the address
*/ */
async getAddressNbTransactions(address) { async getAddressNbTransactions(address) {
if(address == null) if(address == null)
@ -571,7 +571,7 @@ class MySqlDbWrapper {
const query = mysql.format(sqlQuery, params) const query = mysql.format(sqlQuery, params)
const results = await this._query(query) const results = await this._query(query)
if (results.length == 1) { if (results.length === 1) {
const nbTxs = results[0].nbTxs const nbTxs = results[0].nbTxs
return (nbTxs == null) ? 0 : nbTxs return (nbTxs == null) ? 0 : nbTxs
} }
@ -582,7 +582,7 @@ class MySqlDbWrapper {
/** /**
* Get an HD account. * Get an HD account.
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @returns {integer} returns {hdID, hdXpub, hdCreated, hdType} * @returns {number} returns {hdID, hdXpub, hdCreated, hdType}
* throws if no record of xpub * throws if no record of xpub
*/ */
async getHDAccount(xpub) { async getHDAccount(xpub) {
@ -600,7 +600,7 @@ class MySqlDbWrapper {
/** /**
* Get the ID of an HD account * Get the ID of an HD account
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @returns {integer} returns the id of the hd account * @returns {number} returns the id of the hd account
*/ */
async getHDAccountId(xpub) { async getHDAccountId(xpub) {
const sqlQuery = 'SELECT `hdID` FROM `hd` WHERE `hdXpub` = ?' const sqlQuery = 'SELECT `hdID` FROM `hd` WHERE `hdXpub` = ?'
@ -618,7 +618,7 @@ class MySqlDbWrapper {
* Get the ID of an HD account. Ensures that the account exists. * Get the ID of an HD account. Ensures that the account exists.
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @param {string} type - hd account type * @param {string} type - hd account type
* @returns {integer} returns the id of the hd account * @returns {number} returns the id of the hd account
*/ */
async ensureHDAccountId(xpub, type) { async ensureHDAccountId(xpub, type) {
const info = hdaHelper.classify(type) const info = hdaHelper.classify(type)
@ -650,15 +650,14 @@ class MySqlDbWrapper {
/** /**
* Lock the type of a hd account * Lock the type of a hd account
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @param {boolean} locked - true for locking, false for unlocking
* @returns {boolean} locked - true for locking, false for unlocking * @returns {boolean} locked - true for locking, false for unlocking
*/ */
async setLockHDAccountType(xpub, locked) { async setLockHDAccountType(xpub, locked) {
locked = !!locked
const account = await this.getHDAccount(xpub) const account = await this.getHDAccount(xpub)
const info = hdaHelper.classify(account.hdType) const info = hdaHelper.classify(account.hdType)
if (info.locked == locked) if (info.locked === locked)
return true return true
const hdType = hdaHelper.makeType(account.hdType, locked) const hdType = hdaHelper.makeType(account.hdType, locked)
@ -700,7 +699,7 @@ class MySqlDbWrapper {
* Add an address a hd account * Add an address a hd account
* @param {string} address - bitcoin address * @param {string} address - bitcoin address
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @param {integer} chain - derivation chain * @param {number} chain - derivation chain
* @param {index} index - derivation index for the address * @param {index} index - derivation index for the address
*/ */
async addAddressToHDAccount(address, xpub, chain, index) { async addAddressToHDAccount(address, xpub, chain, index) {
@ -733,7 +732,7 @@ class MySqlDbWrapper {
* which is the output of the HDAccountsHelper.deriveAddresses() * which is the output of the HDAccountsHelper.deriveAddresses()
*/ */
async addAddressesToHDAccount(xpub, addressData) { async addAddressesToHDAccount(xpub, addressData) {
if (addressData.length == 0) if (addressData.length === 0)
return return
const addresses = addressData.map(d => d.address) const addresses = addressData.map(d => d.address)
@ -769,7 +768,7 @@ class MySqlDbWrapper {
* @returns {object[]} * @returns {object[]}
*/ */
async getUngroupedHDAccountsByAddresses(addresses) { async getUngroupedHDAccountsByAddresses(addresses) {
if (addresses.length == 0) return {} if (addresses.length === 0) return {}
const sqlQuery = 'SELECT \ const sqlQuery = 'SELECT \
`hd`.`hdID`, \ `hd`.`hdID`, \
@ -814,7 +813,7 @@ class MySqlDbWrapper {
loose: [] loose: []
} }
if (addresses.length == 0) if (addresses.length === 0)
return ret return ret
const sqlQuery = 'SELECT \ const sqlQuery = 'SELECT \
@ -865,7 +864,7 @@ class MySqlDbWrapper {
/** /**
* Get an HD account balance * Get an HD account balance
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @returns {integer} returns the balance of the hd account * @returns {number} returns the balance of the hd account
*/ */
async getHDAccountBalance(xpub) { async getHDAccountBalance(xpub) {
const sqlQuery = 'SELECT \ const sqlQuery = 'SELECT \
@ -882,7 +881,7 @@ class MySqlDbWrapper {
const query = mysql.format(sqlQuery, params) const query = mysql.format(sqlQuery, params)
const results = await this._query(query) const results = await this._query(query)
if (results.length == 1) if (results.length === 1)
return (results[0].balance == null) ? 0 : results[0].balance return (results[0].balance == null) ? 0 : results[0].balance
return null return null
@ -891,7 +890,7 @@ class MySqlDbWrapper {
/** /**
* Get next unused address indices for each HD chain of an account * Get next unused address indices for each HD chain of an account
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @returns {integer[]} returns an array of unused indices * @returns {number[]} returns an array of unused indices
* [M/0/X, M/1/Y] -> [X,Y] * [M/0/X, M/1/Y] -> [X,Y]
*/ */
async getHDAccountNextUnusedIndices(xpub) { async getHDAccountNextUnusedIndices(xpub) {
@ -921,7 +920,7 @@ class MySqlDbWrapper {
/** /**
* Get the maximum derived address index for each HD chain of an account * Get the maximum derived address index for each HD chain of an account
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @returns {integer[]} returns an array of derived indices * @returns {number[]} returns an array of derived indices
* [M/0/X, M/1/Y] -> [X,Y] * [M/0/X, M/1/Y] -> [X,Y]
*/ */
async getHDAccountDerivedIndices(xpub) { async getHDAccountDerivedIndices(xpub) {
@ -950,10 +949,10 @@ class MySqlDbWrapper {
/** /**
* Get the number of indices derived in an interval for a HD chain * Get the number of indices derived in an interval for a HD chain
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @param {integer} chain - HD chain (0 or 1) * @param {number} chain - HD chain (0 or 1)
* @param {integer} minIdx - min index of derivation * @param {number} minIdx - min index of derivation
* @param {integer} maxIdx - max index of derivation * @param {number} maxIdx - max index of derivation
* @returns {integer[]} returns an array of number of derived indices * @returns {number[]} returns an array of number of derived indices
*/ */
async getHDAccountNbDerivedIndices(xpub, chain, minIdx, maxIdx) { async getHDAccountNbDerivedIndices(xpub, chain, minIdx, maxIdx) {
const sqlQuery = 'SELECT \ const sqlQuery = 'SELECT \
@ -969,7 +968,7 @@ class MySqlDbWrapper {
const query = mysql.format(sqlQuery, params) const query = mysql.format(sqlQuery, params)
const results = await this._query(query) const results = await this._query(query)
if (results.length == 1) { if (results.length === 1) {
const nbDerivedIndices = results[0].nbDerivedIndices const nbDerivedIndices = results[0].nbDerivedIndices
return (nbDerivedIndices == null) ? 0 : nbDerivedIndices return (nbDerivedIndices == null) ? 0 : nbDerivedIndices
} }
@ -980,7 +979,7 @@ class MySqlDbWrapper {
/** /**
* Get the number of transactions for an HD account * Get the number of transactions for an HD account
* @param {string} xpub - xpub * @param {string} xpub - xpub
* @returns {integer} returns the balance of the hd account * @returns {number} returns the balance of the hd account
*/ */
async getHDAccountNbTransactions(xpub) { async getHDAccountNbTransactions(xpub) {
const sqlQuery = 'SELECT COUNT(DISTINCT `r`.`txnTxid`) AS nbTxs \ const sqlQuery = 'SELECT COUNT(DISTINCT `r`.`txnTxid`) AS nbTxs \
@ -1007,7 +1006,7 @@ class MySqlDbWrapper {
const query = mysql.format(sqlQuery, params) const query = mysql.format(sqlQuery, params)
const results = await this._query(query) const results = await this._query(query)
if (results.length == 1) if (results.length === 1)
return (results[0].nbTxs == null) ? 0 : results[0].nbTxs return (results[0].nbTxs == null) ? 0 : results[0].nbTxs
return null return null
@ -1017,12 +1016,12 @@ class MySqlDbWrapper {
* Get the number of transactions for a list of addresses and HD accounts * Get the number of transactions for a list of addresses and HD accounts
* @param {string[]} addresses - array of bitcoin addresses * @param {string[]} addresses - array of bitcoin addresses
* @param {string[]} xpubs - array of xpubs * @param {string[]} xpubs - array of xpubs
* @returns {int} returns the number of transactions * @returns {number} returns the number of transactions
*/ */
async getAddrAndXpubsNbTransactions(addresses, xpubs) { async getAddrAndXpubsNbTransactions(addresses, xpubs) {
if ( if (
(!addresses || addresses.length == 0) (!addresses || addresses.length === 0)
&& (!xpubs || xpubs.length == 0) && (!xpubs || xpubs.length === 0)
) { ) {
return [] return []
} }
@ -1052,7 +1051,7 @@ class MySqlDbWrapper {
let query = mysql.format(sqlQuery) let query = mysql.format(sqlQuery)
const results = await this._query(query) const results = await this._query(query)
if (results.length == 1) if (results.length === 1)
return (results[0].nbTxs == null) ? 0 : results[0].nbTxs return (results[0].nbTxs == null) ? 0 : results[0].nbTxs
return null return null
@ -1062,12 +1061,14 @@ class MySqlDbWrapper {
* Get the transactions for a list of addresses and HD accounts * Get the transactions for a list of addresses and HD accounts
* @param {string[]} addresses - array of bitcoin addresses * @param {string[]} addresses - array of bitcoin addresses
* @param {string[]} xpubs - array of xpubs * @param {string[]} xpubs - array of xpubs
* @param {number=} page - page
* @param {number=} nbTxsPerPage - number of transactions per page
* @returns {object[]} returns an array of transactions * @returns {object[]} returns an array of transactions
*/ */
async getTxsByAddrAndXpubs(addresses, xpubs, page, nbTxsPerPage) { async getTxsByAddrAndXpubs(addresses, xpubs, page, nbTxsPerPage) {
if ( if (
(!addresses || addresses.length == 0) (!addresses || addresses.length === 0)
&& (!xpubs || xpubs.length == 0) && (!xpubs || xpubs.length === 0)
) { ) {
return [] return []
} }
@ -1117,7 +1118,7 @@ class MySqlDbWrapper {
const txsIds = txs.map(t => t.txnID) const txsIds = txs.map(t => t.txnID)
if (txsIds.length == 0) if (txsIds.length === 0)
return [] return []
// Prepares subqueries for // Prepares subqueries for
@ -1189,7 +1190,7 @@ class MySqlDbWrapper {
} }
} }
if (input.hdXpub && input.hdXpub !== null) { if (input.hdXpub) {
ret.prev_out.xpub = { ret.prev_out.xpub = {
m: input.hdXpub, m: input.hdXpub,
path: ['M', input.hdAddrChain, input.hdAddrIndex].join('/') path: ['M', input.hdAddrChain, input.hdAddrIndex].join('/')
@ -1211,7 +1212,7 @@ class MySqlDbWrapper {
addr: output.outAddress addr: output.outAddress
} }
if (output.hdXpub && output.hdXpub !== null) { if (output.hdXpub) {
ret.xpub = { ret.xpub = {
m: output.hdXpub, m: output.hdXpub,
path: ['M', output.hdAddrChain, output.hdAddrIndex].join('/') path: ['M', output.hdAddrChain, output.hdAddrIndex].join('/')
@ -1294,7 +1295,7 @@ class MySqlDbWrapper {
async getXpubByAddresses(addresses) { async getXpubByAddresses(addresses) {
const ret = {} const ret = {}
if (addresses.length == 0) if (addresses.length === 0)
return ret return ret
const sqlQuery = 'SELECT `hd`.`hdXpub`, `addresses`.`addrAddress` \ const sqlQuery = 'SELECT `hd`.`hdXpub`, `addresses`.`addrAddress` \
@ -1316,7 +1317,7 @@ class MySqlDbWrapper {
/** /**
* Get the mysql ID of a transaction. Ensures that the transaction exists. * Get the mysql ID of a transaction. Ensures that the transaction exists.
* @param {string} txid - txid of a transaction * @param {string} txid - txid of a transaction
* @returns {integer} returns the transaction id (mysql id) * @returns {number} returns the transaction id (mysql id)
*/ */
async ensureTransactionId(txid) { async ensureTransactionId(txid) {
const sqlQuery = 'INSERT IGNORE INTO `transactions` SET ?' const sqlQuery = 'INSERT IGNORE INTO `transactions` SET ?'
@ -1346,14 +1347,14 @@ class MySqlDbWrapper {
/** /**
* Get the mysql ID of a transaction * Get the mysql ID of a transaction
* @param {string} txid - txid of a transaction * @param {string} txid - txid of a transaction
* @returns {integer} returns the transaction id (mysql id) * @returns {number} returns the transaction id (mysql id)
*/ */
async getTransactionId(txid) { async getTransactionId(txid) {
const sqlQuery = 'SELECT `txnID` FROM `transactions` WHERE `txnTxid` = ?' const sqlQuery = 'SELECT `txnID` FROM `transactions` WHERE `txnTxid` = ?'
const params = txid const params = txid
const query = mysql.format(sqlQuery, params) const query = mysql.format(sqlQuery, params)
const result = await this._query(query) const result = await this._query(query)
return (result.length == 0) ? null : result[0].txnID return (result.length === 0) ? null : result[0].txnID
} }
/** /**
@ -1362,7 +1363,7 @@ class MySqlDbWrapper {
* @returns {object[]} returns an array of {txnTxid: txnId} * @returns {object[]} returns an array of {txnTxid: txnId}
*/ */
async getTransactionsIds(txids) { async getTransactionsIds(txids) {
if (txids.length == 0) if (txids.length === 0)
return [] return []
const sqlQuery = 'SELECT `txnID`, `txnTxid` FROM `transactions` WHERE `txnTxid` IN (?)' const sqlQuery = 'SELECT `txnID`, `txnTxid` FROM `transactions` WHERE `txnTxid` IN (?)'
@ -1378,11 +1379,11 @@ class MySqlDbWrapper {
/** /**
* Get the mysql IDs of a set of transactions * Get the mysql IDs of a set of transactions
* @param {string[]} txid - array of transactions txids * @param {string[]} txnIDs - array of transactions txids
* @returns {integer[]} returns an array of transaction ids (mysql ids) * @returns {number[]} returns an array of transaction ids (mysql ids)
*/ */
async getTransactionsById(txnIDs) { async getTransactionsById(txnIDs) {
if (txnIDs.length == 0) if (txnIDs.length === 0)
return [] return []
const sqlQuery = 'SELECT * FROM `transactions` WHERE `txnID` IN (?)' const sqlQuery = 'SELECT * FROM `transactions` WHERE `txnID` IN (?)'
@ -1419,7 +1420,7 @@ class MySqlDbWrapper {
* @param {object[]} txs - array of {txid, version, locktime} * @param {object[]} txs - array of {txid, version, locktime}
*/ */
async addTransactions(txs) { async addTransactions(txs) {
if (txs.length == 0) if (txs.length === 0)
return return
const sqlQuery = 'INSERT INTO `transactions` \ const sqlQuery = 'INSERT INTO `transactions` \
@ -1567,10 +1568,10 @@ class MySqlDbWrapper {
/** /**
* Batch confirm txids in a block * Batch confirm txids in a block
* @param {string[]} txnTxidArray - array of transaction txids * @param {string[]} txnTxidArray - array of transaction txids
* @param {integer} blockID - mysql id of the blck * @param {number} blockID - mysql id of the blck
*/ */
async confirmTransactions(txnTxidArray, blockID) { async confirmTransactions(txnTxidArray, blockID) {
if (txnTxidArray.length == 0) if (txnTxidArray.length === 0)
return return
const sqlQuery = 'UPDATE `transactions` SET `blockID` = ? WHERE `txnTxid` IN (?)' const sqlQuery = 'UPDATE `transactions` SET `blockID` = ? WHERE `txnTxid` IN (?)'
@ -1581,8 +1582,8 @@ class MySqlDbWrapper {
/** /**
* Get the transactions confirmed after a given height * Get the transactions confirmed after a given height
* @param {integer]} height - block height * @param {number} height - block height
* @param {object[]} returns an array of transactions * @returns {object[]} returns an array of transactions
*/ */
async getTransactionsConfirmedAfterHeight(height) { async getTransactionsConfirmedAfterHeight(height) {
const sqlQuery = 'SELECT `transactions`.* FROM `transactions` \ const sqlQuery = 'SELECT `transactions`.* FROM `transactions` \
@ -1595,7 +1596,7 @@ class MySqlDbWrapper {
/** /**
* Delete the transactions confirmed after a given height * Delete the transactions confirmed after a given height
* @param {integer]} height - block height * @param {number} height - block height
*/ */
async deleteTransactionsConfirmedAfterHeight(height) { async deleteTransactionsConfirmedAfterHeight(height) {
const sqlQuery = 'DELETE `transactions`.* FROM `transactions` \ const sqlQuery = 'DELETE `transactions`.* FROM `transactions` \
@ -1611,7 +1612,7 @@ class MySqlDbWrapper {
* @param {string[]} txnTxidArray - array of transaction txids * @param {string[]} txnTxidArray - array of transaction txids
*/ */
async unconfirmTransactions(txnTxidArray) { async unconfirmTransactions(txnTxidArray) {
if (txnTxidArray.length == 0) if (txnTxidArray.length === 0)
return return
const sqlQuery = 'UPDATE `transactions` SET `blockID` = NULL WHERE `txnTxid` IN (?)' const sqlQuery = 'UPDATE `transactions` SET `blockID` = NULL WHERE `txnTxid` IN (?)'
@ -1633,10 +1634,10 @@ class MySqlDbWrapper {
/** /**
* Delete a set of transactions identified by their mysql ids * Delete a set of transactions identified by their mysql ids
* @param {integer[]} txnIDs - mysql ids of the transactions * @param {number[]} txnIDs - mysql ids of the transactions
*/ */
async deleteTransactionsByID(txnIDs) { async deleteTransactionsByID(txnIDs) {
if (txnIDs.length == 0) if (txnIDs.length === 0)
return [] return []
const sqlQuery = 'DELETE `transactions`.* FROM `transactions` WHERE `transactions`.`txnID` in (?)' const sqlQuery = 'DELETE `transactions`.* FROM `transactions` WHERE `transactions`.`txnID` in (?)'
@ -1650,7 +1651,7 @@ class MySqlDbWrapper {
* @param {object[]} outputs - array of {txnID, addrID, outIndex, outAmount, outScript} * @param {object[]} outputs - array of {txnID, addrID, outIndex, outAmount, outScript}
*/ */
async addOutputs(outputs) { async addOutputs(outputs) {
if (outputs.length == 0) if (outputs.length === 0)
return return
const sqlQuery = 'INSERT IGNORE INTO `outputs` \ const sqlQuery = 'INSERT IGNORE INTO `outputs` \
@ -1671,7 +1672,7 @@ class MySqlDbWrapper {
* {addrAddress, outID, outAmount, txnTxid, outIndex, spendingTxnID/null, spendingInID/null} * {addrAddress, outID, outAmount, txnTxid, outIndex, spendingTxnID/null, spendingInID/null}
*/ */
async getOutputSpends(spends) { async getOutputSpends(spends) {
if (spends.length == 0) if (spends.length === 0)
return [] return []
const whereClauses = const whereClauses =
@ -1703,7 +1704,7 @@ class MySqlDbWrapper {
* {outID, txnTxid, outIndex} * {outID, txnTxid, outIndex}
*/ */
async getOutputIds(spends) { async getOutputIds(spends) {
if (spends.length == 0) if (spends.length === 0)
return [] return []
const whereClauses = const whereClauses =
@ -1730,7 +1731,7 @@ class MySqlDbWrapper {
* {txnTxid, outIndex, outAmount, outScript, addrAddress} * {txnTxid, outIndex, outAmount, outScript, addrAddress}
*/ */
async getUnspentOutputs(addresses) { async getUnspentOutputs(addresses) {
if (addresses.length == 0) if (addresses.length === 0)
return [] return []
const sqlQuery = 'SELECT \ const sqlQuery = 'SELECT \
@ -1761,7 +1762,7 @@ class MySqlDbWrapper {
* {txnID, outID, inIndex, inSequence} * {txnID, outID, inIndex, inSequence}
*/ */
async addInputs(inputs) { async addInputs(inputs) {
if (inputs.length == 0) if (inputs.length === 0)
return return
const sqlQuery = 'INSERT INTO `inputs` \ const sqlQuery = 'INSERT INTO `inputs` \
@ -1811,7 +1812,7 @@ class MySqlDbWrapper {
const params = hash const params = hash
const query = mysql.format(sqlQuery, params) const query = mysql.format(sqlQuery, params)
const result = await this._query(query) const result = await this._query(query)
return (result.length == 1) ? result[0] : null return (result.length === 1) ? result[0] : null
} }
/** /**
@ -1820,7 +1821,7 @@ class MySqlDbWrapper {
* @returns {object[]} returns the blocks * @returns {object[]} returns the blocks
*/ */
async getBlocksByHashes(hashes) { async getBlocksByHashes(hashes) {
if (hashes.length == 0) if (hashes.length === 0)
return [] return []
const sqlQuery = 'SELECT * FROM `blocks` WHERE `blockHash` IN (?)' const sqlQuery = 'SELECT * FROM `blocks` WHERE `blockHash` IN (?)'
@ -1831,7 +1832,7 @@ class MySqlDbWrapper {
/** /**
* Get details about all blocks at a given block height * Get details about all blocks at a given block height
* @param {integer} height - block height * @param {number} height - block height
* @returns {object[]} returns an array of blocks * @returns {object[]} returns an array of blocks
*/ */
async getBlocksByHeight(height) { async getBlocksByHeight(height) {
@ -1843,7 +1844,7 @@ class MySqlDbWrapper {
/** /**
* Delete the blocks after a given block height * Delete the blocks after a given block height
* @param {integer} height - block height * @param {number} height - block height
*/ */
async deleteBlocksAfterHeight(height) { async deleteBlocksAfterHeight(height) {
const sqlQuery = 'DELETE FROM `blocks` WHERE `blockHeight` > ?' const sqlQuery = 'DELETE FROM `blocks` WHERE `blockHeight` > ?'
@ -1854,12 +1855,12 @@ class MySqlDbWrapper {
/** /**
* Gets the last block * Gets the last block
* @returns {object} returns the last block * @returns {object | null} returns the last block
*/ */
async getHighestBlock() { async getHighestBlock() {
try { try {
const results = await this.getLastBlocks(1) const results = await this.getLastBlocks(1)
if (results == null || results.length == 0) if (results == null || results.length === 0)
return { return {
blockID: null, blockID: null,
blockHeight: 0 blockHeight: 0
@ -1873,7 +1874,7 @@ class MySqlDbWrapper {
/** /**
* Gets the N last blocks * Gets the N last blocks
* @param {integer} n - number of blocks to be retrieved * @param {number} n - number of blocks to be retrieved
* @returns {object[]} returns an array of the n last blocks * @returns {object[]} returns an array of the n last blocks
*/ */
async getLastBlocks(n) { async getLastBlocks(n) {
@ -1896,14 +1897,14 @@ class MySqlDbWrapper {
/** /**
* Get the mysql ID of a scheduled transaction * Get the mysql ID of a scheduled transaction
* @param {string} txid - txid of a scheduled transaction * @param {string} txid - txid of a scheduled transaction
* @returns {integer} returns the scheduled transaction id (mysql id) * @returns {number} returns the scheduled transaction id (mysql id)
*/ */
async getScheduledTransactionId(txid) { async getScheduledTransactionId(txid) {
const sqlQuery = 'SELECT `schID` FROM `scheduled_transactions` WHERE `schTxid` = ?' const sqlQuery = 'SELECT `schID` FROM `scheduled_transactions` WHERE `schTxid` = ?'
const params = txid const params = txid
const query = mysql.format(sqlQuery, params) const query = mysql.format(sqlQuery, params)
const result = await this._query(query) const result = await this._query(query)
return (result.length == 0) ? null : result[0].txnID return (result.length === 0) ? null : result[0].txnID
} }
/** /**
@ -1952,7 +1953,7 @@ class MySqlDbWrapper {
/** /**
* Get scheduled transactions * Get scheduled transactions
* with a trigger lower than a given block height * with a trigger lower than a given block height
* @param {integer} height - block height * @param {number} height - block height
*/ */
async getActivatedScheduledTransactions(height) { async getActivatedScheduledTransactions(height) {
const sqlQuery = 'SELECT * FROM `scheduled_transactions` \ const sqlQuery = 'SELECT * FROM `scheduled_transactions` \
@ -1964,7 +1965,7 @@ class MySqlDbWrapper {
/** /**
* Get the scheduled transaction having a given parentID * Get the scheduled transaction having a given parentID
* @param {integer} parentId - parent ID * @param {number} parentId - parent ID
* @returns {object[]} returns an array of scheduled transactions * @returns {object[]} returns an array of scheduled transactions
*/ */
async getNextScheduledTransactions(parentId) { async getNextScheduledTransactions(parentId) {
@ -1978,8 +1979,8 @@ class MySqlDbWrapper {
/** /**
* Update the trigger of a scheduled transaction * Update the trigger of a scheduled transaction
* identified by its ID * identified by its ID
* @param {integer} id - id of the scheduled transaction * @param {number} id - id of the scheduled transaction
* @param {integer} trigger - new trigger * @param {number} trigger - new trigger
*/ */
async updateTriggerScheduledTransaction(id, trigger) { async updateTriggerScheduledTransaction(id, trigger) {
const sqlQuery = 'UPDATE `scheduled_transactions` \ const sqlQuery = 'UPDATE `scheduled_transactions` \

3
lib/http-server/http-server.js

@ -19,7 +19,7 @@ class HttpServer {
/** /**
* Constructor * Constructor
* @param {int} port - port used by the http server * @param {number} port - port used by the http server
* @param {string} host - host exposing the http server * @param {string} host - host exposing the http server
*/ */
constructor(port, host) { constructor(port, host) {
@ -95,6 +95,7 @@ class HttpServer {
/** /**
* Return a http response without status * Return a http response without status
* @param {object} res - http response object * @param {object} res - http response object
* @param {object} data
*/ */
static sendOkDataOnly(res, data) { static sendOkDataOnly(res, data) {
res.status(200).json(data) res.status(200).json(data)

11
lib/indexer-rpc/rpc-client.js

@ -63,11 +63,11 @@ class RpcClient {
* @returns {boolean} returns true if message related to a connection error * @returns {boolean} returns true if message related to a connection error
*/ */
static isConnectionError(err) { static isConnectionError(err) {
if (typeof err != 'string') if (typeof err !== 'string')
return false return false
const isTimeoutError = (err.indexOf('connect ETIMEDOUT') != -1) const isTimeoutError = (err.indexOf('connect ETIMEDOUT') !== -1)
const isConnRejected = (err.indexOf('Connection Rejected') != -1) const isConnRejected = (err.indexOf('Connection Rejected') !== -1)
return (isTimeoutError || isConnRejected) return (isTimeoutError || isConnRejected)
} }
@ -122,6 +122,7 @@ class RpcClient {
/** /**
* Send requests (internal method) * Send requests (internal method)
* @param {Object[]} data - array of objects {method: ..., params: ...} * @param {Object[]} data - array of objects {method: ..., params: ...}
* @param {boolean=} batched - batch requests
* @returns {Promise} * @returns {Promise}
*/ */
async _call(data, batched) { async _call(data, batched) {
@ -174,7 +175,7 @@ class RpcClient {
for (let c of chunk) { for (let c of chunk) {
response += c response += c
// Detect the end of a response // Detect the end of a response
if (c == '\n') { if (c === '\n') {
try { try {
// Parse the response // Parse the response
let parsed = JSON.parse(response) let parsed = JSON.parse(response)
@ -190,7 +191,7 @@ class RpcClient {
response = '' response = ''
// If all responses have been received // If all responses have been received
// close the connection // close the connection
if (responses.length == data.length) if (responses.length === data.length)
conn.end() conn.end()
} catch (err) { } catch (err) {
reject( reject(

4
lib/remote-importer/esplora-wrapper.js

@ -20,6 +20,8 @@ class EsploraWrapper extends Wrapper {
/** /**
* Constructor * Constructor
* @constructor
* @param {string} url
*/ */
constructor(url) { constructor(url) {
super(url, keys.indexer.socks5Proxy) super(url, keys.indexer.socks5Proxy)
@ -87,7 +89,7 @@ class EsploraWrapper extends Wrapper {
while (true) { while (true) {
const txids = await this._getTxsForAddress(address, lastSeenTxid) const txids = await this._getTxsForAddress(address, lastSeenTxid)
if (txids.length == 0) if (txids.length === 0)
// we have all the transactions // we have all the transactions
return ret return ret

2
lib/remote-importer/local-indexer-wrapper.js

@ -104,7 +104,7 @@ class LocalIndexerWrapper extends Wrapper {
}) })
// Send the requests // Send the requests
const results = (keys.indexer.localIndexer.batchRequests == 'active') const results = (keys.indexer.localIndexer.batchRequests === 'active')
? await this.client.sendBatch(commands) ? await this.client.sendBatch(commands)
: await this.client.sendRequests(commands) : await this.client.sendRequests(commands)

2
lib/remote-importer/local-rest-indexer-wrapper.js

@ -22,6 +22,8 @@ class LocalRestIndexerWrapper extends Wrapper {
/** /**
* Constructor * Constructor
* @constructor
* @param {string} url
*/ */
constructor(url) { constructor(url) {
super(url, null) super(url, null)

4
lib/remote-importer/oxt-wrapper.js

@ -18,6 +18,8 @@ class OxtWrapper extends Wrapper {
/** /**
* Constructor * Constructor
* @constructor
* @param {string} url
*/ */
constructor(url) { constructor(url) {
super(url, keys.indexer.socks5Proxy) super(url, keys.indexer.socks5Proxy)
@ -123,7 +125,7 @@ class OxtWrapper extends Wrapper {
async getChainTipHeight() { async getChainTipHeight() {
let chainTipHeight = null let chainTipHeight = null
const result = await this._get(`/lastblock`) const result = await this._get(`/lastblock`)
if (result != null && result['data'].length == 1) if (result != null && result['data'].length === 1)
chainTipHeight = parseInt(result['data'][0]['height']) chainTipHeight = parseInt(result['data'][0]['height'])
return {'chainTipHeight': chainTipHeight} return {'chainTipHeight': chainTipHeight}
} }

14
lib/remote-importer/remote-importer.js

@ -17,7 +17,7 @@ const gap = keys.gap
let Sources let Sources
if (network.key == 'bitcoin') { if (network.key === 'bitcoin') {
Sources = require('./sources-mainnet') Sources = require('./sources-mainnet')
} else { } else {
Sources = require('./sources-testnet') Sources = require('./sources-testnet')
@ -64,8 +64,8 @@ class RemoteImporter {
* Import an HD account from remote sources * Import an HD account from remote sources
* @param {string} xpub - HD Account * @param {string} xpub - HD Account
* @param {string} type - type of HD Account * @param {string} type - type of HD Account
* @param {integer} gapLimit - (optional) gap limit for derivation * @param {number} gapLimit - (optional) gap limit for derivation
* @param {integer} startIndex - (optional) rescan shall start from this index * @param {number} startIndex - (optional) rescan shall start from this index
*/ */
async importHDAccount(xpub, type, gapLimit, startIndex) { async importHDAccount(xpub, type, gapLimit, startIndex) {
if (!hdaHelper.isValid(xpub)) if (!hdaHelper.isValid(xpub))
@ -202,7 +202,7 @@ class RemoteImporter {
} }
if (gotTransactions) { if (gotTransactions) {
const keyStatus = (c == 0) ? 'txs_ext' : 'txs_int' const keyStatus = (c === 0) ? 'txs_ext' : 'txs_int'
this.importing[xpub][keyStatus] = Object.keys(txids).length this.importing[xpub][keyStatus] = Object.keys(txids).length
// We must go deeper // We must go deeper
const result = await this.xpubScan(xpub, c, d, u, G, type, txids) const result = await this.xpubScan(xpub, c, d, u, G, type, txids)
@ -236,7 +236,7 @@ class RemoteImporter {
const addresses = candidates.filter(c => !this.importing[c]) const addresses = candidates.filter(c => !this.importing[c])
this.importing = addresses.reduce((m,a) => (m[a] = true, m), this.importing) this.importing = addresses.reduce((m,a) => (m[a] = true, m), this.importing)
if (addresses.length == 0) return true if (addresses.length === 0) return true
Logger.info(`Importer : Importing ${addresses.join(',')}`) Logger.info(`Importer : Importing ${addresses.join(',')}`)
@ -318,8 +318,8 @@ class RemoteImporter {
const blocks = await db.getBlocksByHashes(blocksHashes) const blocks = await db.getBlocksByHashes(blocksHashes)
return util.parallelCall(blocks, block => { return util.parallelCall(blocks, block => {
const filteredTxs = txs.filter(tx => (tx.block && tx.block.hash == block.blockHash)) const filteredTxs = txs.filter(tx => (tx.block && tx.block.hash === block.blockHash))
if (filteredTxs.length == 0) return if (filteredTxs.length === 0) return
const txids = filteredTxs.map(tx => tx.txid) const txids = filteredTxs.map(tx => tx.txid)
return db.confirmTransactions(txids, block.blockID) return db.confirmTransactions(txids, block.blockID)
}) })

6
lib/remote-importer/sources-mainnet.js

@ -31,17 +31,17 @@ class SourcesMainnet extends Sources {
* Initialize the external data source * Initialize the external data source
*/ */
_initSource() { _initSource() {
if (keys.indexer.active == 'local_bitcoind') { if (keys.indexer.active === 'local_bitcoind') {
// If local bitcoind option is activated // If local bitcoind option is activated
// we'll use the local node as our unique source // we'll use the local node as our unique source
this.source = new BitcoindWrapper() this.source = new BitcoindWrapper()
Logger.info('Importer : Activated Bitcoind as the data source for imports') Logger.info('Importer : Activated Bitcoind as the data source for imports')
} else if (keys.indexer.active == 'local_indexer') { } else if (keys.indexer.active === 'local_indexer') {
// If local indexer option is activated // If local indexer option is activated
// we'll use the local indexer as our unique source // we'll use the local indexer as our unique source
this.source = new LocalIndexerWrapper() this.source = new LocalIndexerWrapper()
Logger.info('Importer : Activated local indexer as the data source for imports') Logger.info('Importer : Activated local indexer as the data source for imports')
} else if (keys.indexer.active == 'local_rest_indexer') { } else if (keys.indexer.active === 'local_rest_indexer') {
// If local rest indexer option is activated // If local rest indexer option is activated
// we'll use the local indexer as our unique source // we'll use the local indexer as our unique source
const uri = `http://${keys.indexer.localIndexer.host}:${keys.indexer.localIndexer.port}` const uri = `http://${keys.indexer.localIndexer.host}:${keys.indexer.localIndexer.port}`

6
lib/remote-importer/sources-testnet.js

@ -32,17 +32,17 @@ class SourcesTestnet extends Sources {
* Initialize the external data source * Initialize the external data source
*/ */
_initSource() { _initSource() {
if (keys.indexer.active == 'local_bitcoind') { if (keys.indexer.active === 'local_bitcoind') {
// If local bitcoind option is activated // If local bitcoind option is activated
// we'll use the local node as our unique source // we'll use the local node as our unique source
this.source = new BitcoindWrapper() this.source = new BitcoindWrapper()
Logger.info('Importer : Activated Bitcoind as the data source for imports') Logger.info('Importer : Activated Bitcoind as the data source for imports')
} else if (keys.indexer.active == 'local_indexer') { } else if (keys.indexer.active === 'local_indexer') {
// If local indexer option is activated // If local indexer option is activated
// we'll use the local indexer as our unique source // we'll use the local indexer as our unique source
this.source = new LocalIndexerWrapper() this.source = new LocalIndexerWrapper()
Logger.info('Importer : Activated local indexer as the data source for imports') Logger.info('Importer : Activated local indexer as the data source for imports')
} else if (keys.indexer.active == 'local_rest_indexer') { } else if (keys.indexer.active === 'local_rest_indexer') {
// If local rest indexer option is activated // If local rest indexer option is activated
// we'll use the local indexer as our unique source // we'll use the local indexer as our unique source
const uri = `http://${keys.indexer.localIndexer.host}:${keys.indexer.localIndexer.port}` const uri = `http://${keys.indexer.localIndexer.host}:${keys.indexer.localIndexer.port}`

3
lib/remote-importer/wrapper.js

@ -16,6 +16,9 @@ class Wrapper {
/** /**
* Constructor * Constructor
* @constructor
* @param {string} url
* @param {string=} socks5Proxy
*/ */
constructor(url, socks5Proxy) { constructor(url, socks5Proxy) {
this.base = url this.base = url

118
lib/util.js

@ -5,18 +5,22 @@
'use strict' 'use strict'
/** /**
* Class providing utility functions as static methods * @class Util
* @description Class providing utility functions as static methods
*/ */
class Util { class Util {
/** /**
* Constructor * Constructor
* @constructor
*/ */
constructor() {} constructor() {}
/** /**
* Serialize a series of asynchronous calls to a function * @description Serialize a series of asynchronous calls to a function over a list of objects
* over a list of objects * @param {Array<any>} list
* @param {function} fn
* @returns {Promise<Array<any>>}
*/ */
static async seriesCall(list, fn) { static async seriesCall(list, fn) {
const results = [] const results = []
@ -29,8 +33,10 @@ class Util {
} }
/** /**
* Execute parallel asynchronous calls to a function * @description Execute parallel asynchronous calls to a function over a list of objects
* over a list of objects * @param {Array<any>} list
* @param {function} fn
* @returns {Promise<Array<any>>}
*/ */
static parallelCall(list, fn) { static parallelCall(list, fn) {
const operations = list.map(item => { return fn(item) }) const operations = list.map(item => { return fn(item) })
@ -38,16 +44,21 @@ class Util {
} }
/** /**
* Delay the call to a function * @description Delay the call to a function
* @param {number} ms
* @returns {Promise<void>}
*/ */
static delay(ms, v) { static delay(ms) {
return new Promise(resolve => { return new Promise(resolve => {
setTimeout(resolve.bind(null, v), ms) setTimeout(() => resolve(), ms)
}) })
} }
/** /**
* Splits a list into a list of lists each with maximum length LIMIT * @description Splits a list into a list of lists each with maximum length LIMIT
* @param {Array<any>} list
* @param {number} limit
* @returns {Array<Array<any>>}
*/ */
static splitList(list, limit) { static splitList(list, limit) {
const lists = [] const lists = []
@ -57,7 +68,9 @@ class Util {
} }
/** /**
* Check if a string is a valid hex value * @description Check if a string is a valid hex value
* @param {string} hash
* @returns {boolean}
*/ */
static isHashStr(hash) { static isHashStr(hash) {
const hexRegExp = new RegExp(/^[0-9a-f]*$/, 'i') const hexRegExp = new RegExp(/^[0-9a-f]*$/, 'i')
@ -65,49 +78,64 @@ class Util {
} }
/** /**
* Check if a string is a well formed 256 bits hash * @description Check if a string is a well formed 256 bits hash
* @param {string} hash
* @returns {boolean}
*/ */
static is256Hash(hash) { static is256Hash(hash) {
return Util.isHashStr(hash) && hash.length == 64 return Util.isHashStr(hash) && hash.length === 64
} }
/** /**
* Sum an array of values * @description Sum an array of values
* @param {Array<number>} arr
* @returns {number}
*/ */
static sum(arr) { static sum(arr) {
return arr.reduce((memo, val) => { return memo + val }, 0) return arr.reduce((memo, val) => { return memo + val }, 0)
} }
/** /**
* Mean of an array of values * @description Mean of an array of values
* @param {Array<number>} arr
* @returns {number}
*/ */
static mean(arr) { static mean(arr) {
if (arr.length == 0) if (arr.length === 0)
return NaN return NaN
return sum(arr) / arr.length return sum(arr) / arr.length
} }
/** /**
* Compare 2 values (asc order) * @description Compare 2 values (asc order)
* @param {number} a
* @param {number} b
* @returns {number}
*/ */
static cmpAsc(a, b) { static cmpAsc(a, b) {
return a - b return a - b
} }
/** /**
* Compare 2 values (desc order) * @description Compare 2 values (desc order)
* @param {number} a
* @param {number} b
* @returns {number}
*/ */
static cmpDesc(a,b) { static cmpDesc(a,b) {
return b - a return b - a
} }
/** /**
* Median of an array of values * @description Median of an array of values
* @param {Array<number>} arr
* @param {boolean=} sorted
* @returns {number}
*/ */
static median(arr, sorted) { static median(arr, sorted) {
if (arr.length == 0) return NaN if (arr.length === 0) return NaN
if (arr.length == 1) return arr[0] if (arr.length === 1) return arr[0]
if (!sorted) if (!sorted)
arr.sort(Util.cmpAsc) arr.sort(Util.cmpAsc)
@ -124,7 +152,10 @@ class Util {
} }
/** /**
* Median Absolute Deviation of an array of values * @description Median Absolute Deviation of an array of values
* @param {Array<number>} arr
* @param {boolean=} sorted
* @returns {number}
*/ */
static mad(arr, sorted) { static mad(arr, sorted) {
const med = Util.median(arr, sorted) const med = Util.median(arr, sorted)
@ -136,7 +167,10 @@ class Util {
} }
/** /**
* Quartiles of an array of values * @description Quartiles of an array of values
* @param {Array<number>} arr
* @param {boolean=} sorted
* @returns {Array<number>}
*/ */
static quartiles(arr, sorted) { static quartiles(arr, sorted) {
const q = [NaN,NaN,NaN] const q = [NaN,NaN,NaN]
@ -156,10 +190,10 @@ class Util {
const mod4 = arr.length % 4 const mod4 = arr.length % 4
const n = Math.floor(arr.length / 4) const n = Math.floor(arr.length / 4)
if (mod4 == 1) { if (mod4 === 1) {
q[0] = (arr[n-1] + 3 * arr[n]) / 4 q[0] = (arr[n-1] + 3 * arr[n]) / 4
q[2] = (3 * arr[3*n] + arr[3*n+1]) / 4 q[2] = (3 * arr[3*n] + arr[3*n+1]) / 4
} else if (mod4 == 3) { } else if (mod4 === 3) {
q[0] = (3 * arr[n] + arr[n+1]) / 4 q[0] = (3 * arr[n] + arr[n+1]) / 4
q[2] = (arr[3*n+1] + 3 * arr[3*n+2]) / 4 q[2] = (arr[3*n+1] + 3 * arr[3*n+2]) / 4
} }
@ -174,7 +208,11 @@ class Util {
} }
/** /**
* Obtain the value of the PCT-th percentile, where PCT on [0,100] * @description Obtain the value of the PCT-th percentile, where PCT on [0,100]
* @param {Array<number>} arr
* @param {number} pct
* @param {boolean=} sorted
* @returns {number}
*/ */
static percentile(arr, pct, sorted) { static percentile(arr, pct, sorted) {
if (arr.length < 2) return NaN if (arr.length < 2) return NaN
@ -210,28 +248,35 @@ class Util {
} }
/** /**
* Convert bytes to Mb * @description Convert bytes to MB
* @param {number} bytes
* @returns {number}
*/ */
static toMb(bytes) { static toMb(bytes) {
return +(bytes / Util.MB).toFixed(0) return +(bytes / Util.MB).toFixed(0)
} }
/** /**
* Convert a date to a unix timestamp * @description Convert a date to a unix timestamp
* @returns {number}
*/ */
static unix() { static unix() {
return (Date.now() / 1000) | 0 return (Date.now() / 1000) | 0
} }
/** /**
* Convert a value to a padded string (10 chars) * @description Convert a value to a padded string (10 chars)
* @param {number} v
* @returns {string}
*/ */
static pad10(v) { static pad10(v) {
return (v < 10) ? `0${v}` : `${v}` return (v < 10) ? `0${v}` : `${v}`
} }
/** /**
* Convert a value to a padded string (100 chars) * @description Convert a value to a padded string (100 chars)
* @param {number} v
* @returns {string}
*/ */
static pad100(v) { static pad100(v) {
if (v < 10) return `00${v}` if (v < 10) return `00${v}`
@ -240,7 +285,9 @@ class Util {
} }
/** /**
* Convert a value to a padded string (1000 chars) * @description Convert a value to a padded string (1000 chars)
* @param {number} v
* @returns {string}
*/ */
static pad1000(v) { static pad1000(v) {
if (v < 10) return `000${v}` if (v < 10) return `000${v}`
@ -250,7 +297,11 @@ class Util {
} }
/** /**
* Left pad * @description Left pad
* @param {number} number
* @param {number} places
* @param {string=} fill
* @returns {string}
*/ */
static leftPad(number, places, fill) { static leftPad(number, places, fill) {
number = Math.round(number) number = Math.round(number)
@ -271,7 +322,10 @@ class Util {
} }
/** /**
* Display a time period, in seconds, as DDD:HH:MM:SS[.MS] * @description Display a time period, in seconds, as DDD:HH:MM:SS[.MS]
* @param {number} period
* @param {number} milliseconds
* @returns {string}
*/ */
static timePeriod(period, milliseconds) { static timePeriod(period, milliseconds) {
milliseconds = !!milliseconds milliseconds = !!milliseconds

34
lib/wallet/address-info.js

@ -9,13 +9,15 @@ const hdaHelper = require('../bitcoin/hd-accounts-helper')
/** /**
* A class storing information about the actibity of an address * @class AddressInfo
* @description A class storing information about the actibity of an address
*/ */
class AddressInfo { class AddressInfo {
/** /**
* Constructor * Constructor
* @param {object} address - bitcoin address * @constructor
* @param {string} address - bitcoin address
*/ */
constructor(address) { constructor(address) {
// Initializes properties // Initializes properties
@ -25,7 +27,7 @@ class AddressInfo {
this.nTx = 0 this.nTx = 0
this.unspentOutputs = [] this.unspentOutputs = []
this.tracked = false, this.tracked = false
this.type = 'untracked' this.type = 'untracked'
this.xpub = null this.xpub = null
this.path = null this.path = null
@ -34,8 +36,8 @@ class AddressInfo {
} }
/** /**
* Load information about the address * @description Load information about the address
* @returns {Promise} * @returns {Promise<void[]>}
*/ */
async loadInfo() { async loadInfo() {
return Promise.all([ return Promise.all([
@ -57,9 +59,8 @@ class AddressInfo {
} }
/** /**
* Load information about the address * @description Load information about the address (extended form)
* (extended form) * @returns {Promise<void[]>}
* @returns {Promise}
*/ */
async loadInfoExtended() { async loadInfoExtended() {
const res = await db.getHDAccountsByAddresses([this.address]) const res = await db.getHDAccountsByAddresses([this.address])
@ -75,7 +76,7 @@ class AddressInfo {
} }
for (let a of res.loose) { for (let a of res.loose) {
if (a.addrAddress == this.address) { if (a.addrAddress === this.address) {
this.tracked = true this.tracked = true
this.type = 'loose' this.type = 'loose'
break break
@ -86,9 +87,9 @@ class AddressInfo {
} }
/** /**
* Loads a partial list of transactions for this address * @description Loads a partial list of transactions for this address
* @param {integer} page - page index * @param {number} page - page index
* @param {integer} count - number of transactions per page * @param {number} count - number of transactions per page
* @returns {Promise} * @returns {Promise}
*/ */
async loadTransactions(page, count) { async loadTransactions(page, count) {
@ -96,8 +97,8 @@ class AddressInfo {
} }
/** /**
* Load the utxos associated to the address * @description Load the utxos associated to the address
* @returns {Promise - object[]} * @returns {Promise<object[]>}
*/ */
async loadUtxos() { async loadUtxos() {
this.unspentOutputs = [] this.unspentOutputs = []
@ -118,7 +119,7 @@ class AddressInfo {
} }
/** /**
* Return a plain old js object with address properties * @description Return a plain old js object with address properties
* @returns {object} * @returns {object}
*/ */
toPojo() { toPojo() {
@ -135,8 +136,7 @@ class AddressInfo {
} }
/** /**
* Return a plain old js object with address properties * @description Return a plain old js object with address properties (extended version)
* (extended version)
* @returns {object} * @returns {object}
*/ */
toPojoExtended() { toPojoExtended() {

37
lib/wallet/hd-account-info.js

@ -12,13 +12,14 @@ const rpcLatestBlock = require('../bitcoind-rpc/latest-block')
/** /**
* A class storing information about the actibity of a hd account * @class HdAccountInfo
* @description A class storing information about the actibity of a hd account
*/ */
class HdAccountInfo { class HdAccountInfo {
/** /**
* Constructor * Constructor
* @param {object} xpub - xpub * @param {string} xpub - xpub
*/ */
constructor(xpub) { constructor(xpub) {
// Initializes properties // Initializes properties
@ -39,9 +40,8 @@ class HdAccountInfo {
} }
/** /**
* Ensure the hd account exists in database * @description Ensure the hd account exists in database. Otherwise, tries to import it with BIP44 derivation
* Otherwise, tries to import it with BIP44 derivation * @returns {Promise<number | null>} return the internal id of the hd account
* @returns {Promise - integer} return the internal id of the hd account
* or null if it doesn't exist * or null if it doesn't exist
*/ */
async ensureHdAccount() { async ensureHdAccount() {
@ -49,7 +49,7 @@ class HdAccountInfo {
const id = await db.getHDAccountId(this.xpub) const id = await db.getHDAccountId(this.xpub)
return id return id
} catch(e) { } catch(e) {
if (e == errors.db.ERROR_NO_HD_ACCOUNT) { if (e === errors.db.ERROR_NO_HD_ACCOUNT) {
try { try {
// Default to BIP44 import // Default to BIP44 import
return hdaService.restoreHdAccount(this.xpub, hdaHelper.BIP44) return hdaService.restoreHdAccount(this.xpub, hdaHelper.BIP44)
@ -62,8 +62,8 @@ class HdAccountInfo {
} }
/** /**
* Load information about the hd account * @description Load information about the hd account
* @returns {Promise} * @returns {Promise<boolean>}
*/ */
async loadInfo() { async loadInfo() {
try { try {
@ -93,29 +93,41 @@ class HdAccountInfo {
this.depth = node[2].depth this.depth = node[2].depth
} }
/**
* @returns {Promise<void>}
*/
async _loadBalance() { async _loadBalance() {
this.finalBalance = await db.getHDAccountBalance(this.xpub) this.finalBalance = await db.getHDAccountBalance(this.xpub)
} }
/**
* @returns {Promise<void>}
*/
async _loadUnusedIndices() { async _loadUnusedIndices() {
const unusedIdx = await db.getHDAccountNextUnusedIndices(this.xpub) const unusedIdx = await db.getHDAccountNextUnusedIndices(this.xpub)
this.accountIndex = unusedIdx[0] this.accountIndex = unusedIdx[0]
this.changeIndex = unusedIdx[1] this.changeIndex = unusedIdx[1]
} }
/**
* @returns {Promise<void>}
*/
async _loadDerivedIndices() { async _loadDerivedIndices() {
const derivedIdx = await db.getHDAccountDerivedIndices(this.xpub) const derivedIdx = await db.getHDAccountDerivedIndices(this.xpub)
this.accountDerivedIndex = derivedIdx[0] this.accountDerivedIndex = derivedIdx[0]
this.changeDerivedIndex = derivedIdx[1] this.changeDerivedIndex = derivedIdx[1]
} }
/**
* @returns {Promise<void>}
*/
async _loadNbTransactions() { async _loadNbTransactions() {
this.nTx = await db.getHDAccountNbTransactions(this.xpub) this.nTx = await db.getHDAccountNbTransactions(this.xpub)
} }
/** /**
* Load the utxos associated to the hd account * @description Load the utxos associated to the hd account
* @returns {Promise - object[]} * @returns {Promise<object[]>}
*/ */
async loadUtxos() { async loadUtxos() {
this.unspentOutputs = [] this.unspentOutputs = []
@ -153,7 +165,7 @@ class HdAccountInfo {
} }
/** /**
* Return a plain old js object with hd account properties * @description Return a plain old js object with hd account properties
* @returns {object} * @returns {object}
*/ */
toPojo() { toPojo() {
@ -169,8 +181,7 @@ class HdAccountInfo {
} }
/** /**
* Return a plain old js object with hd account properties * @description Return a plain old js object with hd account properties (extended version)
* (extended version)
* @returns {object} * @returns {object}
*/ */
toPojoExtended() { toPojoExtended() {

21
lib/wallet/wallet-entities.js

@ -6,13 +6,13 @@
/** /**
* A class storing entities (xpubs, addresses, pubkeys) * @class WalletEntities
* defining a (full|partial) wallet * @description A class storing entities (xpubs, addresses, pubkeys) defining a (full|partial) wallet
*/ */
class WalletEntities { class WalletEntities {
/** /**
* Constructor * @constructor
*/ */
constructor() { constructor() {
this.pubkeys = [] this.pubkeys = []
@ -23,8 +23,7 @@ class WalletEntities {
} }
/** /**
* Add a new hd account * @description Add a new hd account with its translation as an xpub
* with its translation as an xpub
* @param {string} xpub - xpub or tpub * @param {string} xpub - xpub or tpub
* @param {string} ypub - ypub or upub or false * @param {string} ypub - ypub or upub or false
* @param {string} zpub - zpub or vpub or false * @param {string} zpub - zpub or vpub or false
@ -36,7 +35,7 @@ class WalletEntities {
} }
/** /**
* Add a new address/pubkey * @description Add a new address/pubkey
* @param {string} address - bitcoin address * @param {string} address - bitcoin address
* @param {string} pubkey - pubkey associated to the address or false * @param {string} pubkey - pubkey associated to the address or false
*/ */
@ -46,7 +45,7 @@ class WalletEntities {
} }
/** /**
* Update the pubkey associated to a given address * @description Update the pubkey associated to a given address
* @param {string} address - bitcoin address * @param {string} address - bitcoin address
* @param {string} pubkey - public key * @param {string} pubkey - public key
*/ */
@ -57,7 +56,7 @@ class WalletEntities {
} }
/** /**
* Checks if a xpub is already listed * @description Checks if a xpub is already listed
* @param {string} xpub * @param {string} xpub
* @returns {boolean} returns true if the xpub is already listed, false otherwise * @returns {boolean} returns true if the xpub is already listed, false otherwise
*/ */
@ -66,7 +65,7 @@ class WalletEntities {
} }
/** /**
* Checks if an address is already listed * @description Checks if an address is already listed
* @param {string} address - bitcoin address * @param {string} address - bitcoin address
* @returns {boolean} returns true if the address is already listed, false otherwise * @returns {boolean} returns true if the address is already listed, false otherwise
*/ */
@ -75,7 +74,7 @@ class WalletEntities {
} }
/** /**
* Checks if a pubkey is already listed * @description Checks if a pubkey is already listed
* @param {string} pubkey - public key * @param {string} pubkey - public key
* @returns {boolean} returns true if the pubkey is already listed, false otherwise * @returns {boolean} returns true if the pubkey is already listed, false otherwise
*/ */
@ -85,4 +84,4 @@ class WalletEntities {
} }
module.exports = WalletEntities module.exports = WalletEntities

48
lib/wallet/wallet-info.js

@ -16,11 +16,13 @@ const AddressInfo = require('./address-info')
/** /**
* A class storing information about a (full|partial) wallet * A class storing information about a (full|partial) wallet
* Provides a set of methods allowing to retrieve specific information * Provides a set of methods allowing to retrieve specific information
* @class WalletInfo
*/ */
class WalletInfo { class WalletInfo {
/** /**
* Constructor * Constructor
* @constructor
* @param {object} entities - wallet entities (hdaccounts, addresses, pubkeys) * @param {object} entities - wallet entities (hdaccounts, addresses, pubkeys)
*/ */
constructor(entities) { constructor(entities) {
@ -49,7 +51,7 @@ class WalletInfo {
/** /**
* Ensure hd accounts exist in database * Ensure hd accounts exist in database
* @returns {Promise} * @returns {Promise<Array<any>>}
*/ */
async ensureHdAccounts() { async ensureHdAccounts() {
return util.parallelCall(this.entities.xpubs, async xpub => { return util.parallelCall(this.entities.xpubs, async xpub => {
@ -60,7 +62,7 @@ class WalletInfo {
/** /**
* Load information about the hd accounts * Load information about the hd accounts
* @returns {Promise} * @returns {Promise<Array<any>>}
*/ */
async loadHdAccountsInfo() { async loadHdAccountsInfo() {
return util.parallelCall(this.entities.xpubs, async xpub => { return util.parallelCall(this.entities.xpubs, async xpub => {
@ -91,7 +93,7 @@ class WalletInfo {
/** /**
* Filter addresses that belong to an active hd account * Filter addresses that belong to an active hd account
* @returns {Promise} * @returns {Promise<void>}
*/ */
async filterAddresses() { async filterAddresses() {
const res = await db.getXpubByAddresses(this.entities.addrs) const res = await db.getXpubByAddresses(this.entities.addrs)
@ -110,7 +112,7 @@ class WalletInfo {
/** /**
* Load information about the addresses * Load information about the addresses
* @returns {Promise} * @returns {Promise<Array<void>>}
*/ */
async loadAddressesInfo() { async loadAddressesInfo() {
return util.parallelCall(this.entities.addrs, async address => { return util.parallelCall(this.entities.addrs, async address => {
@ -123,11 +125,11 @@ class WalletInfo {
/** /**
* Loads a partial list of transactions for this wallet * Loads a partial list of transactions for this wallet
* @param {integer} page - page index * @param {number} page - page index
* @param {integer} count - number of transactions per page * @param {number} count - number of transactions per page
* @param {boolean} txBalance - True if past wallet balance * @param {boolean=} txBalance - True if past wallet balance
* should be computed for each transaction * should be computed for each transaction
* @returns {Promise} * @returns {Promise<void>}
*/ */
async loadTransactions(page, count, txBalance) { async loadTransactions(page, count, txBalance) {
this.txs = await db.getTxsByAddrAndXpubs( this.txs = await db.getTxsByAddrAndXpubs(
@ -149,7 +151,7 @@ class WalletInfo {
/** /**
* Loads the number of transactions for this wallet * Loads the number of transactions for this wallet
* @returns {Promise} * @returns {Promise<void>}
*/ */
async loadNbTransactions() { async loadNbTransactions() {
const nbTxs = await db.getAddrAndXpubsNbTransactions( const nbTxs = await db.getAddrAndXpubsNbTransactions(
@ -163,7 +165,7 @@ class WalletInfo {
/** /**
* Loads tinfo about the fee rates * Loads tinfo about the fee rates
* @returns {Promise} * @returns {Promise<void>}
*/ */
async loadFeesInfo() { async loadFeesInfo() {
this.info.fees = await rpcFees.getFees() this.info.fees = await rpcFees.getFees()
@ -171,7 +173,7 @@ class WalletInfo {
/** /**
* Loads the list of unspent outputs for this wallet * Loads the list of unspent outputs for this wallet
* @returns {Promise} * @returns {Promise<void>}
*/ */
async loadUtxos() { async loadUtxos() {
// Load the utxos for the hd accounts // Load the utxos for the hd accounts
@ -212,7 +214,7 @@ class WalletInfo {
/** /**
* Post process addresses and public keys * Post process addresses and public keys
*/ */
postProcessAddresses() { async postProcessAddresses() {
for (let b = 0; b < this.entities.pubkeys.length; b++) { for (let b = 0; b < this.entities.pubkeys.length; b++) {
const pk = this.entities.pubkeys[b] const pk = this.entities.pubkeys[b]
@ -221,7 +223,7 @@ class WalletInfo {
// Add pubkeys in this.addresses // Add pubkeys in this.addresses
for (let c = 0; c < this.addresses.length; c++) { for (let c = 0; c < this.addresses.length; c++) {
if (address == this.addresses[c].address) if (address === this.addresses[c].address)
this.addresses[c].pubkey = pk this.addresses[c].pubkey = pk
} }
@ -229,30 +231,32 @@ class WalletInfo {
for (let d = 0; d < this.txs.length; d++) { for (let d = 0; d < this.txs.length; d++) {
// inputs // inputs
for (let e = 0; e < this.txs[d].inputs.length; e++) { for (let e = 0; e < this.txs[d].inputs.length; e++) {
if (address == this.txs[d].inputs[e].prev_out.addr) if (address === this.txs[d].inputs[e].prev_out.addr)
this.txs[d].inputs[e].prev_out.pubkey = pk this.txs[d].inputs[e].prev_out.pubkey = pk
} }
// outputs // outputs
for (let e = 0; e < this.txs[d].out.length; e++) { for (let e = 0; e < this.txs[d].out.length; e++) {
if (address == this.txs[d].out[e].addr) if (address === this.txs[d].out[e].addr)
this.txs[d].out[e].pubkey = pk this.txs[d].out[e].pubkey = pk
} }
} }
// Add pubkeys in this.unspentOutputs // Add pubkeys in this.unspentOutputs
for (let f = 0; f < this.unspentOutputs.length; f++) { for (let f = 0; f < this.unspentOutputs.length; f++) {
if (address == this.unspentOutputs[f].addr) { if (address === this.unspentOutputs[f].addr) {
this.unspentOutputs[f].pubkey = pk this.unspentOutputs[f].pubkey = pk
} }
} }
} }
} }
return Promise.resolve()
} }
/** /**
* Post process hd accounts (xpubs translations) * Post process hd accounts (xpubs translations)
*/ */
postProcessHdAccounts() { async postProcessHdAccounts() {
for (let b = 0; b < this.entities.xpubs.length; b++) { for (let b = 0; b < this.entities.xpubs.length; b++) {
const entityXPub = this.entities.xpubs[b] const entityXPub = this.entities.xpubs[b]
const entityYPub = this.entities.ypubs[b] const entityYPub = this.entities.ypubs[b]
@ -263,7 +267,7 @@ class WalletInfo {
// Translate xpub => ypub/zpub in this.addresses // Translate xpub => ypub/zpub in this.addresses
for (let c = 0; c < this.addresses.length; c++) { for (let c = 0; c < this.addresses.length; c++) {
if (entityXPub == this.addresses[c].address) if (entityXPub === this.addresses[c].address)
this.addresses[c].address = tgtXPub this.addresses[c].address = tgtXPub
} }
@ -272,14 +276,14 @@ class WalletInfo {
// inputs // inputs
for (let e = 0; e < this.txs[d].inputs.length; e++) { for (let e = 0; e < this.txs[d].inputs.length; e++) {
const xpub = this.txs[d].inputs[e].prev_out.xpub const xpub = this.txs[d].inputs[e].prev_out.xpub
if (xpub && (xpub.m == entityXPub)) if (xpub && (xpub.m === entityXPub))
this.txs[d].inputs[e].prev_out.xpub.m = tgtXPub this.txs[d].inputs[e].prev_out.xpub.m = tgtXPub
} }
// outputs // outputs
for (let e = 0; e < this.txs[d].out.length; e++) { for (let e = 0; e < this.txs[d].out.length; e++) {
const xpub = this.txs[d].out[e].xpub const xpub = this.txs[d].out[e].xpub
if (xpub && (xpub.m == entityXPub)) if (xpub && (xpub.m === entityXPub))
this.txs[d].out[e].xpub.m = tgtXPub this.txs[d].out[e].xpub.m = tgtXPub
} }
} }
@ -287,12 +291,14 @@ class WalletInfo {
// Translate xpub => ypub/zpub in this.unspentOutputs // Translate xpub => ypub/zpub in this.unspentOutputs
for (let f = 0; f < this.unspentOutputs.length; f++) { for (let f = 0; f < this.unspentOutputs.length; f++) {
const xpub = this.unspentOutputs[f].xpub const xpub = this.unspentOutputs[f].xpub
if (xpub && (xpub.m == entityXPub)) { if (xpub && (xpub.m === entityXPub)) {
this.unspentOutputs[f].xpub.m = tgtXPub this.unspentOutputs[f].xpub.m = tgtXPub
} }
} }
} }
} }
return Promise.resolve()
} }
/** /**

28
lib/wallet/wallet-service.js

@ -72,7 +72,7 @@ class WalletService {
// Force import of addresses associated to paynyms // Force import of addresses associated to paynyms
// if dojo relies on a local index // if dojo relies on a local index
if (keys.indexer.active != 'third_party_explorer') if (keys.indexer.active !== 'third_party_explorer')
await this._forceEnsureAddressesForActivePubkeys(active) await this._forceEnsureAddressesForActivePubkeys(active)
// Filter the addresses // Filter the addresses
@ -150,7 +150,7 @@ class WalletService {
await walletInfo.ensureAddresses() await walletInfo.ensureAddresses()
// Force import of addresses associated to paynyms // Force import of addresses associated to paynyms
// if dojo relies on a local index // if dojo relies on a local index
if (keys.indexer.active != 'third_party_explorer') if (keys.indexer.active !== 'third_party_explorer')
await this._forceEnsureAddressesForActivePubkeys(active) await this._forceEnsureAddressesForActivePubkeys(active)
// Filter the address and load them // Filter the address and load them
await walletInfo.filterAddresses() await walletInfo.filterAddresses()
@ -252,7 +252,7 @@ class WalletService {
await walletInfo.ensureAddresses() await walletInfo.ensureAddresses()
// Force import of addresses associated to paynyms // Force import of addresses associated to paynyms
// if dojo relies on a local index // if dojo relies on a local index
if (keys.indexer.active != 'third_party_explorer') if (keys.indexer.active !== 'third_party_explorer')
await this._forceEnsureAddressesForActivePubkeys(active) await this._forceEnsureAddressesForActivePubkeys(active)
// Filter the addresses // Filter the addresses
await walletInfo.filterAddresses() await walletInfo.filterAddresses()
@ -274,8 +274,8 @@ class WalletService {
/** /**
* Get a subset of wallet transactions * Get a subset of wallet transactions
* @param {object} entities - mapping of active entities * @param {object} entities - mapping of active entities
* @param {integer} page - page of transactions to be returned * @param {number} page - page of transactions to be returned
* @param {integer} count - number of transactions returned per page * @param {number} count - number of transactions returned per page
* @returns {Promise} * @returns {Promise}
*/ */
async getWalletTransactions(entities, page, count) { async getWalletTransactions(entities, page, count) {
@ -287,7 +287,7 @@ class WalletService {
} }
// Check parameters // Check parameters
if (entities.xpubs.length == 0 && entities.addrs.length == 0) if (entities.xpubs.length === 0 && entities.addrs.length === 0)
return ret return ret
// Initialize a WalletInfo object // Initialize a WalletInfo object
@ -344,13 +344,13 @@ class WalletService {
* @returns {boolean} return true if conditions are met, false otherwise * @returns {boolean} return true if conditions are met, false otherwise
*/ */
_checkEntities(active, legacy, bip49, bip84, pubkeys) { _checkEntities(active, legacy, bip49, bip84, pubkeys) {
const allEmpty = active.xpubs.length == 0 const allEmpty = active.xpubs.length === 0
&& active.addrs.length == 0 && active.addrs.length === 0
&& legacy.xpubs.length == 0 && legacy.xpubs.length === 0
&& legacy.addrs.length == 0 && legacy.addrs.length === 0
&& pubkeys.addrs.length == 0 && pubkeys.addrs.length === 0
&& bip49.xpubs.length == 0 && bip49.xpubs.length === 0
&& bip84.xpubs.length == 0 && bip84.xpubs.length === 0
return !allEmpty return !allEmpty
} }
@ -375,7 +375,7 @@ class WalletService {
const pubkey = source.pubkeys[idxSource] const pubkey = source.pubkeys[idxSource]
const idxActive = active.addrs.indexOf(addr) const idxActive = active.addrs.indexOf(addr)
if (idxActive == -1) { if (idxActive === -1) {
active.addrs.push(addr) active.addrs.push(addr)
active.pubkeys.push(pubkey) active.pubkeys.push(pubkey)
} else if (pubkey) { } else if (pubkey) {

8
pushtx/orchestrator.js

@ -94,7 +94,7 @@ class Orchestrator {
break break
for (let tx of txs) { for (let tx of txs) {
let hasParentTx = (tx.schParentTxid != null) && (tx.schParentTxid != '') let hasParentTx = (tx.schParentTxid != null) && (tx.schParentTxid !== '')
let parentTx = null let parentTx = null
// Check if previous transaction has been confirmed // Check if previous transaction has been confirmed
@ -158,11 +158,11 @@ class Orchestrator {
/** /**
* Update triggers in chain of transactions * Update triggers in chain of transactions
* following a transaction identified by its txid * following a transaction identified by its txid
* @param {integer} parentId - parent id * @param {number} parentId - parent id
* @param {integer} shift - delta to be added to the triggers * @param {number} shift - delta to be added to the triggers
*/ */
async updateTriggers(parentId, shift) { async updateTriggers(parentId, shift) {
if (shift == 0) if (shift === 0)
return return
const txs = await db.getNextScheduledTransactions(parentId) const txs = await db.getNextScheduledTransactions(parentId)

4
pushtx/pushtx-processor.js

@ -17,7 +17,7 @@ const keys = require('../keys')[network.key]
const status = require('./status') const status = require('./status')
let Sources let Sources
if (network.key == 'bitcoin') { if (network.key === 'bitcoin') {
Sources = require('../lib/remote-importer/sources-mainnet') Sources = require('../lib/remote-importer/sources-mainnet')
} else { } else {
Sources = require('../lib/remote-importer/sources-testnet') Sources = require('../lib/remote-importer/sources-testnet')
@ -78,7 +78,7 @@ class PushTxProcessor {
} }
// Checks with indexer if addresses are known and have been used // Checks with indexer if addresses are known and have been used
if (Object.keys(addrMap).length > 0) { if (Object.keys(addrMap).length > 0) {
if (keys.indexer.active != 'local_bitcoind') { if (keys.indexer.active !== 'local_bitcoind') {
const results = await this.sources.getAddresses(Object.keys(addrMap)) const results = await this.sources.getAddresses(Object.keys(addrMap))
for (let r of results) for (let r of results)
if (r.ntx > 0) if (r.ntx > 0)

4
pushtx/pushtx-rest-api.js

@ -193,7 +193,7 @@ class PushTxRestApi {
HttpServer.sendOk(res) HttpServer.sendOk(res)
} catch(e) { } catch(e) {
// Returns code 200 if VIOLATION_STRICT_MODE_VOUTS // Returns code 200 if VIOLATION_STRICT_MODE_VOUTS
if (e.message && e.message.code && e.message.code == errors.pushtx.VIOLATION_STRICT_MODE_VOUTS) { if (e.message && e.message.code && e.message.code === errors.pushtx.VIOLATION_STRICT_MODE_VOUTS) {
e.message = JSON.stringify(e.message) e.message = JSON.stringify(e.message)
this._traceError(res, e, 200) this._traceError(res, e, 200)
} else { } else {
@ -206,7 +206,7 @@ class PushTxRestApi {
* Trace an error during push * Trace an error during push
* @param {object} res - http response object * @param {object} res - http response object
* @param {object} err - error object * @param {object} err - error object
* @param {int} errorCode - error code (optional) * @param {number} errorCode - error code (optional)
*/ */
_traceError(res, err, errorCode) { _traceError(res, err, errorCode) {
let ret = null let ret = null

8
pushtx/transactions-scheduler.js

@ -68,13 +68,13 @@ class TransactionsScheduler {
// Decode the transaction // Decode the transaction
const tx = bitcoin.Transaction.fromHex(entry.tx) const tx = bitcoin.Transaction.fromHex(entry.tx)
// Check that nlocktimes are matching // Check that nlocktimes are matching
if (!(tx.locktime && tx.locktime == entry.nlocktime)) { if (!(tx.locktime && tx.locktime === entry.nlocktime)) {
const msg = `TransactionsScheduler.schedule() : nLockTime mismatch : ${tx.locktime} - ${entry.nlocktime}` const msg = `TransactionsScheduler.schedule() : nLockTime mismatch : ${tx.locktime} - ${entry.nlocktime}`
Logger.error(null, `PushTx : ${msg}`) Logger.error(null, `PushTx : ${msg}`)
throw errors.pushtx.NLOCK_MISMATCH throw errors.pushtx.NLOCK_MISMATCH
} }
// Check that order of hop and nlocktime values are consistent // Check that order of hop and nlocktime values are consistent
if (entry.hop != lastHopProcessed) { if (entry.hop !== lastHopProcessed) {
if (entry.nlocktime < lastLockTimeProcessed) if (entry.nlocktime < lastLockTimeProcessed)
throw errors.pushtx.SCHEDULED_BAD_ORDER throw errors.pushtx.SCHEDULED_BAD_ORDER
} }
@ -105,7 +105,7 @@ class TransactionsScheduler {
lastHopProcessed = entry.hop lastHopProcessed = entry.hop
lastLockTimeProcessed = entry.nlocktime lastLockTimeProcessed = entry.nlocktime
// Update scheduled height if needed // Update scheduled height if needed
if (baseHeight != nltTx0) if (baseHeight !== nltTx0)
entry.nlocktime = baseHeight + entry.delta entry.nlocktime = baseHeight + entry.delta
} }
@ -123,7 +123,7 @@ class TransactionsScheduler {
let parentNlocktime = baseHeight let parentNlocktime = baseHeight
// Check if first transactions should be sent immediately // Check if first transactions should be sent immediately
while ((script.length > 0) && (script[0].nlocktime <= lastHeight) && (script[0].delta == 0)) { while ((script.length > 0) && (script[0].nlocktime <= lastHeight) && (script[0].delta === 0)) {
await pushTxProcessor.pushTx(script[0].tx) await pushTxProcessor.pushTx(script[0].tx)
const tx = bitcoin.Transaction.fromHex(script[0].tx) const tx = bitcoin.Transaction.fromHex(script[0].tx)
parentTxid = tx.getId() parentTxid = tx.getId()

14
scripts/patches/revert-hd-accounts.js

@ -21,9 +21,9 @@ function xlatXPUB(xpub) {
let xlatVer = 0 let xlatVer = 0
if (ver == hdaHelper.MAGIC_XPUB || ver == hdaHelper.MAGIC_YPUB || ver == hdaHelper.MAGIC_ZPUB) { if (ver === hdaHelper.MAGIC_XPUB || ver === hdaHelper.MAGIC_YPUB || ver === hdaHelper.MAGIC_ZPUB) {
xlatVer = hdaHelper.MAGIC_XPUB xlatVer = hdaHelper.MAGIC_XPUB
} else if (ver == hdaHelper.MAGIC_TPUB || ver == hdaHelper.MAGIC_UPUB || ver == hdaHelper.MAGIC_VPUB) { } else if (ver === hdaHelper.MAGIC_TPUB || ver === hdaHelper.MAGIC_UPUB || ver === hdaHelper.MAGIC_VPUB) {
xlatVer = hdaHelper.MAGIC_TPUB xlatVer = hdaHelper.MAGIC_TPUB
} }
@ -75,8 +75,8 @@ async function run() {
const xpub = account.hdXpub const xpub = account.hdXpub
const info = hdaHelper.classify(account.hdType) const info = hdaHelper.classify(account.hdType)
const scheme = info.type const scheme = info.type
if ((scheme == hdaHelper.BIP49) || (scheme == hdaHelper.BIP84)) { if ((scheme === hdaHelper.BIP49) || (scheme === hdaHelper.BIP84)) {
try { try {
const xlatedXpub = xlatXPUB(xpub) const xlatedXpub = xlatXPUB(xpub)
await updateHdAccount(hdId, xlatedXpub) await updateHdAccount(hdId, xlatedXpub)
@ -90,7 +90,7 @@ async function run() {
} catch(e) { } catch(e) {
console.log('A problem was met') console.log('A problem was met')
console.log(e) console.log(e)
} }
} }
/** /**
@ -102,4 +102,4 @@ const startupTimeout = setTimeout(async function() {
return run().then(() => { return run().then(() => {
console.log('Process completed') console.log('Process completed')
}) })
}, 1500) }, 1500)

20
scripts/patches/translate-hd-accounts.js

@ -21,18 +21,18 @@ function xlatXPUB(xpub, targetType) {
let xlatVer = 0 let xlatVer = 0
if (ver == hdaHelper.MAGIC_XPUB) { if (ver === hdaHelper.MAGIC_XPUB) {
if (targetType == hdaHelper.BIP49) if (targetType === hdaHelper.BIP49)
xlatVer = hdaHelper.MAGIC_YPUB xlatVer = hdaHelper.MAGIC_YPUB
else if (targetType == hdaHelper.BIP84) else if (targetType === hdaHelper.BIP84)
xlatVer = hdaHelper.MAGIC_ZPUB xlatVer = hdaHelper.MAGIC_ZPUB
} else if (ver == hdaHelper.MAGIC_TPUB) { } else if (ver === hdaHelper.MAGIC_TPUB) {
if (targetType == hdaHelper.BIP49) if (targetType === hdaHelper.BIP49)
xlatVer = hdaHelper.MAGIC_UPUB xlatVer = hdaHelper.MAGIC_UPUB
else if (targetType == hdaHelper.BIP84) else if (targetType === hdaHelper.BIP84)
xlatVer = hdaHelper.MAGIC_VPUB xlatVer = hdaHelper.MAGIC_VPUB
} }
@ -84,8 +84,8 @@ async function run() {
const xpub = account.hdXpub const xpub = account.hdXpub
const info = hdaHelper.classify(account.hdType) const info = hdaHelper.classify(account.hdType)
const scheme = info.type const scheme = info.type
if ((scheme == hdaHelper.BIP49) || (scheme == hdaHelper.BIP84)) { if ((scheme === hdaHelper.BIP49) || (scheme === hdaHelper.BIP84)) {
const xlatedXpub = xlatXPUB(xpub, scheme) const xlatedXpub = xlatXPUB(xpub, scheme)
await updateHdAccount(hdId, xlatedXpub) await updateHdAccount(hdId, xlatedXpub)
console.log(`Updated ${hdId} (${xpub} => ${xlatedXpub})`) console.log(`Updated ${hdId} (${xpub} => ${xlatedXpub})`)
@ -94,7 +94,7 @@ async function run() {
} catch(e) { } catch(e) {
console.log('A problem was met') console.log('A problem was met')
console.log(e) console.log(e)
} }
} }
/** /**
@ -106,4 +106,4 @@ const startupTimeout = setTimeout(async function() {
return run().then(() => { return run().then(() => {
console.log('Process completed') console.log('Process completed')
}) })
}, 1500) }, 1500)

2
static/admin/dmt/index.js

@ -84,7 +84,7 @@ function preparePage() {
const activeTab = sessionStorage.getItem('activeTab') const activeTab = sessionStorage.getItem('activeTab')
for (let idxTab in tabs) { for (let idxTab in tabs) {
const screen = screens[idxTab] const screen = screens[idxTab]
if (tabs[idxTab] == activeTab) { if (tabs[idxTab] === activeTab) {
$(screen).show() $(screen).show()
if (screenScripts.has(screen)) if (screenScripts.has(screen))
screenScripts.get(screen).preparePage() screenScripts.get(screen).preparePage()

10
static/admin/dmt/status/status.js

@ -95,7 +95,7 @@ const statusScript = {
this.chaintipBitcoind = data['bitcoind']['blocks'] this.chaintipBitcoind = data['bitcoind']['blocks']
$('#node-chaintip').text(data['bitcoind']['blocks']) $('#node-chaintip').text(data['bitcoind']['blocks'])
$('#node-version').text(data['bitcoind']['version']) $('#node-version').text(data['bitcoind']['version'])
const network = data['bitcoind']['testnet'] == true ? 'testnet' : 'mainnet' const network = data['bitcoind']['testnet'] === true ? 'testnet' : 'mainnet'
$('#node-network').text(network) $('#node-network').text(network)
$('#node-conn').text(data['bitcoind']['conn']) $('#node-conn').text(data['bitcoind']['conn'])
$('#node-relay-fee').text(data['bitcoind']['relayfee']) $('#node-relay-fee').text(data['bitcoind']['relayfee'])
@ -123,13 +123,13 @@ const statusScript = {
}, },
setStatusIndicator: function(id, status) { setStatusIndicator: function(id, status) {
if (status == 'ok') { if (status === 'ok') {
$(id).html('&#10003;') $(id).html('&#10003;')
$(id).css('color', '#76d776') $(id).css('color', '#76d776')
} else if (status == 'ko') { } else if (status === 'ko') {
$(id).html('X') $(id).html('X')
$(id).css('color', '#f77c7c') $(id).css('color', '#f77c7c')
} else if (status == 'desynchronized') { } else if (status === 'desynchronized') {
$(id).html('&#10003;') $(id).html('&#10003;')
$(id).css('color', '#f0c649') $(id).css('color', '#f0c649')
} else { } else {
@ -140,4 +140,4 @@ const statusScript = {
} }
screenScripts.set('#screen-status', statusScript) screenScripts.set('#screen-status', statusScript)

8
static/admin/dmt/xpubs-tools/xpubs-tools.js

@ -31,8 +31,8 @@ const screenXpubsToolsScript = {
preparePage: function() { preparePage: function() {
// Disable custom lookahead if data source is a third party explorer // Disable custom lookahead if data source is a third party explorer
const isTPE = sessionStorage.getItem('indexerType') == 'third_party_explorer' const isTPE = sessionStorage.getItem('indexerType') === 'third_party_explorer'
const isLRI = sessionStorage.getItem('indexerType') == 'local_rest_indexer' const isLRI = sessionStorage.getItem('indexerType') === 'local_rest_indexer'
const disableLookahead = isTPE || isLRI const disableLookahead = isTPE || isLRI
$('#rescan-lookahead').prop('disabled', disableLookahead) $('#rescan-lookahead').prop('disabled', disableLookahead)
@ -99,9 +99,9 @@ const screenXpubsToolsScript = {
} }
const derivType = $('#import-deriv-type').val() const derivType = $('#import-deriv-type').val()
if (derivType == 'bip49' || derivType == 'bip84') { if (derivType === 'bip49' || derivType === 'bip84') {
jsonData['segwit'] = derivType jsonData['segwit'] = derivType
} else if (derivType == 'auto') { } else if (derivType === 'auto') {
if (this.currentXpub.startsWith('ypub')) if (this.currentXpub.startsWith('ypub'))
jsonData['segwit'] = 'bip49' jsonData['segwit'] = 'bip49'
else if (this.currentXpub.startsWith('zpub')) else if (this.currentXpub.startsWith('zpub'))

4
static/admin/lib/auth-utils.js

@ -98,7 +98,7 @@ const lib_auth = {
isAuthenticated: function() { isAuthenticated: function() {
// Checks that an access token is stored in session storage // Checks that an access token is stored in session storage
let token = this.getAccessToken() let token = this.getAccessToken()
return (token && (token != 'null')) ? true : false return Boolean(token && (token !== 'null'))
}, },
/* /*
@ -128,7 +128,7 @@ const lib_auth = {
const payload = this.getPayloadAccessToken(token) const payload = this.getPayloadAccessToken(token)
if (!payload) if (!payload)
return false return false
return (('prf' in payload) && (payload['prf'] == this.TOKEN_PROFILE_ADMIN)) return (('prf' in payload) && (payload['prf'] === this.TOKEN_PROFILE_ADMIN))
}, },
/* /*

8
static/admin/lib/common-script.js

@ -27,9 +27,9 @@ const lib_cmn = {
getExplorerTxUrl: function(txid, explorerInfo) { getExplorerTxUrl: function(txid, explorerInfo) {
if (explorerInfo == null) if (explorerInfo == null)
return null return null
else if (explorerInfo['pairing']['type'] == 'explorer.oxt') else if (explorerInfo['pairing']['type'] === 'explorer.oxt')
return `${explorerInfo['pairing']['url']}/transaction/${txid}` return `${explorerInfo['pairing']['url']}/transaction/${txid}`
else if (explorerInfo['pairing']['type'] == 'explorer.btc_rpc_explorer') else if (explorerInfo['pairing']['type'] === 'explorer.btc_rpc_explorer')
return `http://${explorerInfo['pairing']['url']}/tx/${txid}` return `http://${explorerInfo['pairing']['url']}/tx/${txid}`
else else
return null return null
@ -46,7 +46,7 @@ const lib_cmn = {
if (file) { if (file) {
xhttp = new XMLHttpRequest() xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function() { xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) { if (this.readyState === 4 && this.status === 200) {
elmnt.innerHTML = this.responseText elmnt.innerHTML = this.responseText
elmnt.removeAttribute('include-html') elmnt.removeAttribute('include-html')
self.includeHTML(cb) self.includeHTML(cb)
@ -72,7 +72,7 @@ const lib_cmn = {
if (file) { if (file) {
xhttp = new XMLHttpRequest() xhttp = new XMLHttpRequest()
xhttp.onreadystatechange = function() { xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) { if (this.readyState === 4 && this.status === 200) {
const newElmnt = document.createElement('script') const newElmnt = document.createElement('script')
newElmnt.textContent = this.responseText newElmnt.textContent = this.responseText
if (elmnt.parentNode) { if (elmnt.parentNode) {

2
static/admin/lib/errors-utils.js

@ -14,7 +14,7 @@ const lib_errors = {
processError: function(e) { processError: function(e) {
const errorMsg = this.extractJqxhrErrorMsg(e) const errorMsg = this.extractJqxhrErrorMsg(e)
// Redirect to sign in page if authentication error // Redirect to sign in page if authentication error
if (errorMsg == 'Invalid JSON Web Token' || errorMsg == 'Missing JSON Web Token') { if (errorMsg === 'Invalid JSON Web Token' || errorMsg === 'Missing JSON Web Token') {
lib_auth.logout() lib_auth.logout()
} else { } else {
lib_msg.displayErrors(errorMsg) lib_msg.displayErrors(errorMsg)

2
static/admin/lib/format-utils.js

@ -52,7 +52,7 @@ const lib_fmt = {
* Format a unix timestamp into a readable date/hour * Format a unix timestamp into a readable date/hour
*/ */
formatUnixTs: function(ts) { formatUnixTs: function(ts) {
if (ts == null || ts == 0) if (ts == null || ts === 0)
return '-' return '-'
let tmpDate = new Date(ts*1000), let tmpDate = new Date(ts*1000),

10
tracker/block-worker.js

@ -61,22 +61,22 @@ async function processMessage(msg) {
try { try {
switch(msg.op) { switch(msg.op) {
case OP_INIT: case OP_INIT:
if (status != IDLE) if (status !== IDLE)
throw 'Operation not allowed' throw 'Operation not allowed'
res = await initBlock(msg.header) res = await initBlock(msg.header)
break break
case OP_PROCESS_OUTPUTS: case OP_PROCESS_OUTPUTS:
if (status != INITIALIZED) if (status !== INITIALIZED)
throw 'Operation not allowed' throw 'Operation not allowed'
res = await processOutputs() res = await processOutputs()
break break
case OP_PROCESS_INPUTS: case OP_PROCESS_INPUTS:
if (status != OUTPUTS_PROCESSED) if (status !== OUTPUTS_PROCESSED)
throw 'Operation not allowed' throw 'Operation not allowed'
res = await processInputs() res = await processInputs()
break break
case OP_CONFIRM: case OP_CONFIRM:
if (status != INPUTS_PROCESSED) if (status !== INPUTS_PROCESSED)
throw 'Operation not allowed' throw 'Operation not allowed'
res = await confirmTransactions(msg.blockId) res = await confirmTransactions(msg.blockId)
break break
@ -130,7 +130,7 @@ async function processInputs() {
/** /**
* Confirm the transactions * Confirm the transactions
* @param {integer} blockId - id of the block in db * @param {number} blockId - id of the block in db
*/ */
async function confirmTransactions(blockId) { async function confirmTransactions(blockId) {
status = TXS_CONFIRMED status = TXS_CONFIRMED

16
tracker/block.js

@ -44,7 +44,7 @@ class Block extends TransactionsBundle {
* @dev This method isn't used anymore. * @dev This method isn't used anymore.
* It has been replaced by a parallel processing of blocks. * It has been replaced by a parallel processing of blocks.
* (see blocks-processor and block-worker) * (see blocks-processor and block-worker)
* @returns {Promise - object[]} returns an array of transactions to be broadcast * @returns {Promise<object[]>} returns an array of transactions to be broadcast
*/ */
async processBlock() { async processBlock() {
Logger.info('Tracker : Beginning to process new block.') Logger.info('Tracker : Beginning to process new block.')
@ -77,7 +77,7 @@ class Block extends TransactionsBundle {
/** /**
* Process the transaction outputs * Process the transaction outputs
* @returns {Promise - object[]} returns an array of transactions to be broadcast * @returns {Promise<object[]>} returns an array of transactions to be broadcast
*/ */
async processOutputs() { async processOutputs() {
const txsForBroadcast = new Set() const txsForBroadcast = new Set()
@ -93,7 +93,7 @@ class Block extends TransactionsBundle {
/** /**
* Process the transaction inputs * Process the transaction inputs
* @returns {Promise - object[]} returns an array of transactions to be broadcast * @returns {Promise<object[]>} returns an array of transactions to be broadcast
*/ */
async processInputs() { async processInputs() {
const txsForBroadcast = new Set() const txsForBroadcast = new Set()
@ -109,7 +109,7 @@ class Block extends TransactionsBundle {
/** /**
* Store the block in db * Store the block in db
* @returns {Promise - int} returns the id of the block * @returns {Promise<number>} returns the id of the block
*/ */
async registerBlock() { async registerBlock() {
const prevBlock = await db.getBlockByHash(this.header.previousblockhash) const prevBlock = await db.getBlockByHash(this.header.previousblockhash)
@ -130,8 +130,8 @@ class Block extends TransactionsBundle {
/** /**
* Confirm the transactions in db * Confirm the transactions in db
* @param {Set} txs - set of transactions stored in db * @param {Set} txs - set of transactions stored in db
* @param {int} blockId - id of the block * @param {number} blockId - id of the block
* r@returns {Promise} * @returns {Promise}
*/ */
async confirmTransactions(txs, blockId) { async confirmTransactions(txs, blockId) {
const txids = txs.map(t => t.getId()) const txids = txs.map(t => t.getId())
@ -141,8 +141,8 @@ class Block extends TransactionsBundle {
/** /**
* Register the block header * Register the block header
* @param {int} prevBlockID - id of previous block * @param {number} prevBlockID - id of previous block
* @returns {Promise} * @returns {Promise<number>}
*/ */
async checkBlockHeader(prevBlockID) { async checkBlockHeader(prevBlockID) {
Logger.info('Tracker : Beginning to process new block header.') Logger.info('Tracker : Beginning to process new block header.')

26
tracker/blockchain-processor.js

@ -43,7 +43,7 @@ class BlockchainProcessor {
/** /**
* Start processing the blockchain * Start processing the blockchain
* @returns {Promise} * @returns {Promise<void>}
*/ */
async start() { async start() {
await this.catchup() await this.catchup()
@ -57,7 +57,7 @@ class BlockchainProcessor {
/** /**
* Tracker process startup * Tracker process startup
* @returns {Promise} * @returns {Promise<void>}
*/ */
async catchup() { async catchup() {
const [highest, info] = await Promise.all([db.getHighestBlock(), this.client.getblockchaininfo()]) const [highest, info] = await Promise.all([db.getHighestBlock(), this.client.getblockchaininfo()])
@ -78,7 +78,7 @@ class BlockchainProcessor {
* 2. Pull all block headers after database last known height * 2. Pull all block headers after database last known height
* 3. Process those block headers * 3. Process those block headers
* *
* @returns {Promise} * @returns {Promise<void>}
*/ */
async catchupIBDMode() { async catchupIBDMode() {
try { try {
@ -93,7 +93,7 @@ class BlockchainProcessor {
let prevBlockId = highest.blockID let prevBlockId = highest.blockID
// If no header or block loaded by bitcoind => try later // If no header or block loaded by bitcoind => try later
if (daemonNbHeaders == 0 || daemonNbBlocks == 0) { if (daemonNbHeaders === 0 || daemonNbBlocks === 0) {
Logger.info('Tracker : New attempt scheduled in 30s (waiting for block headers)') Logger.info('Tracker : New attempt scheduled in 30s (waiting for block headers)')
return util.delay(30000).then(() => { return util.delay(30000).then(() => {
return this.catchupIBDMode() return this.catchupIBDMode()
@ -148,7 +148,7 @@ class BlockchainProcessor {
* 2. Pull all block headers after database last known height * 2. Pull all block headers after database last known height
* 3. Process those block headers * 3. Process those block headers
* *
* @returns {Promise} * @returns {Promise<void>}
*/ */
async catchupNormalMode() { async catchupNormalMode() {
try { try {
@ -159,7 +159,7 @@ class BlockchainProcessor {
const daemonNbBlocks = info.blocks const daemonNbBlocks = info.blocks
if (highest == null) return null if (highest == null) return null
if (daemonNbBlocks == highest.blockHeight) return null if (daemonNbBlocks === highest.blockHeight) return null
const blockRange = _.range(highest.blockHeight, daemonNbBlocks + 1) const blockRange = _.range(highest.blockHeight, daemonNbBlocks + 1)
@ -225,7 +225,7 @@ class BlockchainProcessor {
* block confirmation. * block confirmation.
* *
* @param {Buffer} buf - block * @param {Buffer} buf - block
* @returns {Promise} * @returns {Promise<void>}
*/ */
async onBlockHash(buf) { async onBlockHash(buf) {
try { try {
@ -298,8 +298,8 @@ class BlockchainProcessor {
/** /**
* Cancel confirmation of transactions * Cancel confirmation of transactions
* and delete blocks after a given height * and delete blocks after a given height
* @param {integer} height - height of last block maintained * @param {number} height - height of last block maintained
* @returns {Promise} * @returns {Promise<void>}
*/ */
async rewind(height) { async rewind(height) {
// Retrieve transactions confirmed in reorg'd blocks // Retrieve transactions confirmed in reorg'd blocks
@ -317,8 +317,8 @@ class BlockchainProcessor {
/** /**
* Rescan a range of blocks * Rescan a range of blocks
* @param {integer} fromHeight - height of first block * @param {number} fromHeight - height of first block
* @param {integer} toHeight - height of last block * @param {number} toHeight - height of last block
* @returns {Promise} * @returns {Promise}
*/ */
async rescanBlocks(fromHeight, toHeight) { async rescanBlocks(fromHeight, toHeight) {
@ -356,7 +356,7 @@ class BlockchainProcessor {
/** /**
* Process a range of blocks * Process a range of blocks
* @param {int[]} heights - a range of block heights * @param {number[]} heights - a range of block heights
*/ */
async processBlockRange(heights) { async processBlockRange(heights) {
const chunks = util.splitList(heights, blocksProcessor.nbWorkers) const chunks = util.splitList(heights, blocksProcessor.nbWorkers)
@ -373,7 +373,7 @@ class BlockchainProcessor {
/** /**
* Process a block header * Process a block header
* @param {object} header - block header * @param {object} header - block header
* @param {int} prevBlockID - id of previous block * @param {number} prevBlockID - id of previous block
* @returns {Promise} * @returns {Promise}
*/ */
async processBlockHeader(header, prevBlockID) { async processBlockHeader(header, prevBlockID) {

8
tracker/blocks-processor.js

@ -90,11 +90,11 @@ async function processWorkerMessage(msg) {
if (!msg.status) { if (!msg.status) {
Logger.error(msg.res, 'Tracker : processWorkerMessage()') Logger.error(msg.res, 'Tracker : processWorkerMessage()')
} else if (msg.op == blockWorker.OP_CONFIRM) { } else if (msg.op === blockWorker.OP_CONFIRM) {
txsForBroadcast = txsForBroadcast.concat(msg.res) txsForBroadcast = txsForBroadcast.concat(msg.res)
} }
if (nbTasksCompleted == nbTasksEnqueued) { if (nbTasksCompleted === nbTasksEnqueued) {
switch (msg.op) { switch (msg.op) {
case blockWorker.OP_INIT: case blockWorker.OP_INIT:
// Process the transaction outputs // Process the transaction outputs
@ -139,7 +139,7 @@ async function processWorkerMessage(msg) {
/** /**
* Execute an operation processing a block * Execute an operation processing a block
* @param {integer} op - operation * @param {number} op - operation
* @param {*} args * @param {*} args
*/ */
function processTask(op, args) { function processTask(op, args) {
@ -204,7 +204,7 @@ function notifyBlock(header) {
/** /**
* Store a block in db * Store a block in db
* @param {object} header - block header * @param {object} header - block header
* @returns {Promise - int} returns the id of the block * @returns {Promise<number>} returns the id of the block
*/ */
async function registerBlock(header) { async function registerBlock(header) {
const prevBlock = await dbProcessor.getBlockByHash(header.previousblockhash) const prevBlock = await dbProcessor.getBlockByHash(header.previousblockhash)

15
tracker/mempool-processor.js

@ -47,7 +47,7 @@ class MempoolProcessor {
/** /**
* Start processing the mempool * Start processing the mempool
* @returns {Promise} * @returns {Promise<void>}
*/ */
async start() { async start() {
this.checkUnconfirmedId = setInterval( this.checkUnconfirmedId = setInterval(
@ -143,7 +143,7 @@ class MempoolProcessor {
/** /**
* Process transactions from the mempool buffer * Process transactions from the mempool buffer
* @returns {Promise} * @returns {Promise<void>}
*/ */
async processMempool() { async processMempool() {
// Refresh the isActive flag // Refresh the isActive flag
@ -181,7 +181,7 @@ class MempoolProcessor {
/** /**
* On reception of a new transaction from bitcoind mempool * On reception of a new transaction from bitcoind mempool
* @param {Buffer} buf - transaction * @param {Buffer} buf - transaction
* @returns {Promise} * @returns {Promise<void>}
*/ */
async onTx(buf) { async onTx(buf) {
if (this.isActive) { if (this.isActive) {
@ -201,7 +201,7 @@ class MempoolProcessor {
/** /**
* On reception of a new transaction from /pushtx * On reception of a new transaction from /pushtx
* @param {Buffer} buf - transaction * @param {Buffer} buf - transaction
* @returns {Promise} * @returns {Promise<void>}
*/ */
async onPushTx(buf) { async onPushTx(buf) {
try { try {
@ -249,7 +249,7 @@ class MempoolProcessor {
/** /**
* Check unconfirmed transactions * Check unconfirmed transactions
* @returns {Promise} * @returns {Promise<void>}
*/ */
async checkUnconfirmed() { async checkUnconfirmed() {
const t0 = Date.now() const t0 = Date.now()
@ -287,12 +287,13 @@ class MempoolProcessor {
// Logs // Logs
const ntx = unconfirmedTxs.length const ntx = unconfirmedTxs.length
const dt = ((Date.now() - t0) / 1000).toFixed(1) const dt = ((Date.now() - t0) / 1000).toFixed(1)
const per = (ntx == 0) ? 0 : ((Date.now() - t0) / ntx).toFixed(0) const per = (ntx === 0) ? 0 : ((Date.now() - t0) / ntx).toFixed(0)
Logger.info(`Tracker : Finished processing unconfirmed transactions ${dt}s, ${ntx} tx, ${per}ms/tx`) Logger.info(`Tracker : Finished processing unconfirmed transactions ${dt}s, ${ntx} tx, ${per}ms/tx`)
} }
/** /**
* Sets the isActive flag * Sets the isActive flag
* @private
*/ */
async _refreshActiveStatus() { async _refreshActiveStatus() {
// Get highest header in the blockchain // Get highest header in the blockchain
@ -300,7 +301,7 @@ class MempoolProcessor {
const [highestBlock, info] = await Promise.all([db.getHighestBlock(), this.client.getblockchaininfo()]) const [highestBlock, info] = await Promise.all([db.getHighestBlock(), this.client.getblockchaininfo()])
const highestHeader = info.headers const highestHeader = info.headers
if (highestBlock == null || highestBlock.blockHeight == 0) { if (highestBlock == null || highestBlock.blockHeight === 0) {
this.isActive = false this.isActive = false
return return
} }

2
tracker/tracker.js

@ -34,7 +34,7 @@ class Tracker {
/** /**
* Start the tracker * Start the tracker
* @returns {Promise} * @returns {Promise<void>}
*/ */
async start() { async start() {
if (!this.initialized) { if (!this.initialized) {

16
tracker/transaction.js

@ -96,7 +96,7 @@ class Transaction {
// Check if we find some inputs of interest // Check if we find some inputs of interest
const results = await db.getOutputSpends(spends) const results = await db.getOutputSpends(spends)
if (results.length == 0) if (results.length === 0)
return null return null
// Flag the transaction for broadcast // Flag the transaction for broadcast
@ -122,7 +122,7 @@ class Transaction {
}) })
// Detect potential double spends // Detect potential double spends
if (r.spendingTxnID !== null && r.spendingTxnID != this.storedTxnID) { if (r.spendingTxnID !== null && r.spendingTxnID !== this.storedTxnID) {
Logger.info(`Tracker : DOUBLE SPEND of ${r.txnTxid}-${r.outIndex} by ${this.txid}!`) Logger.info(`Tracker : DOUBLE SPEND of ${r.txnTxid}-${r.outIndex} by ${this.txid}!`)
// Delete the existing transaction that has been double-spent: // Delete the existing transaction that has been double-spent:
// since the deepest block keeps its transactions, this will // since the deepest block keeps its transactions, this will
@ -190,7 +190,7 @@ class Transaction {
const aHdAcctAddr = await this._processOutputsHdAccounts(result.hd, indexedOutputs) const aHdAcctAddr = await this._processOutputsHdAccounts(result.hd, indexedOutputs)
fundedAddresses = fundedAddresses.concat(aHdAcctAddr) fundedAddresses = fundedAddresses.concat(aHdAcctAddr)
if (fundedAddresses.length == 0) if (fundedAddresses.length === 0)
return null return null
// Flag the transaction for broadcast // Flag the transaction for broadcast
@ -219,7 +219,7 @@ class Transaction {
* Process outputs sending to tracked loose addresses * Process outputs sending to tracked loose addresses
* @param {object[]} addresses - array of address objects * @param {object[]} addresses - array of address objects
* @param {object} indexedOutputs - outputs indexed by address * @param {object} indexedOutputs - outputs indexed by address
* @returns {Promise - object[]} return an array of funded addresses * @returns {Promise<object[]>} return an array of funded addresses
* {addrID: ..., outIndex: ..., outAmount: ..., outScript: ...} * {addrID: ..., outIndex: ..., outAmount: ..., outScript: ...}
*/ */
async _processOutputsLooseAddresses(addresses, indexedOutputs) { async _processOutputsLooseAddresses(addresses, indexedOutputs) {
@ -247,7 +247,7 @@ class Transaction {
* Process outputs sending to tracked hd accounts * Process outputs sending to tracked hd accounts
* @param {object[]} hdAccounts - array of hd account objects * @param {object[]} hdAccounts - array of hd account objects
* @param {object} indexedOutputs - outputs indexed by address * @param {object} indexedOutputs - outputs indexed by address
* @returns {Promise - object[]} return an array of funded addresses * @returns {Promise<object[]>} return an array of funded addresses
* {addrID: ..., outIndex: ..., outAmount: ..., outScript: ...} * {addrID: ..., outIndex: ..., outAmount: ..., outScript: ...}
*/ */
async _processOutputsHdAccounts(hdAccounts, indexedOutputs) { async _processOutputsHdAccounts(hdAccounts, indexedOutputs) {
@ -297,7 +297,7 @@ class Transaction {
* @param {string} xpub * @param {string} xpub
* @param {object} hdAccount - hd account object * @param {object} hdAccount - hd account object
* @param {object} indexedOutputs - outputs indexed by address * @param {object} indexedOutputs - outputs indexed by address
* @returns {Promise - object[]} returns an array of the new addresses used * @returns {Promise<object[]>} returns an array of the new addresses used
*/ */
async _deriveNewAddresses(xpub, hdAccount, indexedOutputs) { async _deriveNewAddresses(xpub, hdAccount, indexedOutputs) {
const hdType = hdAccount.hdType const hdType = hdAccount.hdType
@ -317,10 +317,10 @@ class Transaction {
for (let chain of [0,1]) { for (let chain of [0,1]) {
// Get addresses for this account that are on this chain // Get addresses for this account that are on this chain
const chainAddresses = _.filter(hdAccount.addresses, v => { const chainAddresses = _.filter(hdAccount.addresses, v => {
return v.hdAddrChain == chain return v.hdAddrChain === chain
}) })
if (chainAddresses.length == 0) if (chainAddresses.length === 0)
continue continue
// Get the maximum used address on this chain // Get the maximum used address on this chain

17
tracker/transactions-bundle.js

@ -18,7 +18,8 @@ class TransactionsBundle {
/** /**
* Constructor * Constructor
* @param {object[]} txs - array of bitcoin transaction objects * @constructor
* @param {object[]=} txs - array of bitcoin transaction objects
*/ */
constructor(txs) { constructor(txs) {
// List of transactions // List of transactions
@ -52,7 +53,7 @@ class TransactionsBundle {
/** /**
* Get the size of the bundle * Get the size of the bundle
* @returns {integer} return the number of transactions stored in the bundle * @returns {number} return the number of transactions stored in the bundle
*/ */
size() { size() {
return this.transactions.length return this.transactions.length
@ -61,7 +62,7 @@ class TransactionsBundle {
/** /**
* Find the transactions of interest * Find the transactions of interest
* based on theirs inputs * based on theirs inputs
* @returns {object[]} returns an array of transactions objects * @returns {Promise<object[]>} returns an array of transactions objects
*/ */
async prefilterByInputs() { async prefilterByInputs() {
// Process transactions by slices of 5000 transactions // Process transactions by slices of 5000 transactions
@ -74,7 +75,7 @@ class TransactionsBundle {
/** /**
* Find the transactions of interest * Find the transactions of interest
* based on theirs outputs * based on theirs outputs
* @returns {object[]} returns an array of transactions objects * @returns {Promise<object[]>} returns an array of transactions objects
*/ */
async prefilterByOutputs() { async prefilterByOutputs() {
// Process transactions by slices of 5000 transactions // Process transactions by slices of 5000 transactions
@ -88,7 +89,7 @@ class TransactionsBundle {
* Find the transactions of interest * Find the transactions of interest
* based on theirs outputs (internal implementation) * based on theirs outputs (internal implementation)
* @params {object[]} txs - array of transactions objects * @params {object[]} txs - array of transactions objects
* @returns {object[]} returns an array of transactions objects * @returns {Promise<object[]>} returns an array of transactions objects
*/ */
async _prefilterByOutputs(txs) { async _prefilterByOutputs(txs) {
let addresses = [] let addresses = []
@ -122,7 +123,7 @@ class TransactionsBundle {
const idxTxs = indexedOutputs[key] const idxTxs = indexedOutputs[key]
if (idxTxs) { if (idxTxs) {
for (const idxTx of idxTxs) for (const idxTx of idxTxs)
if (filteredIdxTxs.indexOf(idxTx) == -1) if (filteredIdxTxs.indexOf(idxTx) === -1)
filteredIdxTxs.push(idxTx) filteredIdxTxs.push(idxTx)
} }
} }
@ -134,7 +135,7 @@ class TransactionsBundle {
* Find the transactions of interest * Find the transactions of interest
* based on theirs inputs (internal implementation) * based on theirs inputs (internal implementation)
* @params {object[]} txs - array of transactions objects * @params {object[]} txs - array of transactions objects
* @returns {object[]} returns an array of transactions objects * @returns {Promise<object[]>} returns an array of transactions objects
*/ */
async _prefilterByInputs(txs) { async _prefilterByInputs(txs) {
let inputs = [] let inputs = []
@ -169,7 +170,7 @@ class TransactionsBundle {
const idxTxs = indexedInputs[key] const idxTxs = indexedInputs[key]
if (idxTxs) { if (idxTxs) {
for (const idxTx of idxTxs) for (const idxTx of idxTxs)
if (filteredIdxTxs.indexOf(idxTx) == -1) if (filteredIdxTxs.indexOf(idxTx) === -1)
filteredIdxTxs.push(idxTx) filteredIdxTxs.push(idxTx)
} }
} }

Loading…
Cancel
Save