From fd8aa8eb328e8a63a764de008bd43fe502724c28 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Sat, 23 Jan 2021 11:37:59 +0530 Subject: [PATCH 01/18] updates formatting --- lib/services/bitcoind.js | 1270 ++++++++++++++++++++++---------------- 1 file changed, 732 insertions(+), 538 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index a6d57c89..25ade5a3 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -1,24 +1,24 @@ -'use strict'; - -var fs = require('fs'); -var path = require('path'); -var spawn = require('child_process').spawn; -var util = require('util'); -var mkdirp = require('mkdirp'); -var bitcore = require('bitcore-lib-komodo'); -var zmq = require('zmq'); -var async = require('async'); -var LRU = require('lru-cache'); -var BitcoinRPC = require('bitcoind-rpc'); +"use strict"; + +var fs = require("fs"); +var path = require("path"); +var spawn = require("child_process").spawn; +var util = require("util"); +var mkdirp = require("mkdirp"); +var bitcore = require("bitcore-lib-komodo"); +var zmq = require("zmq"); +var async = require("async"); +var LRU = require("lru-cache"); +var BitcoinRPC = require("bitcoind-rpc"); var $ = bitcore.util.preconditions; -var _ = bitcore.deps._; +var _ = bitcore.deps._; var Transaction = bitcore.Transaction; -var index = require('../'); +var index = require("../"); var errors = index.errors; var log = index.log; -var utils = require('../utils'); -var Service = require('../service'); +var utils = require("../utils"); +var Service = require("../service"); /** * Provides a friendly event driven API to bitcoind in Node.js. Manages starting and @@ -57,7 +57,7 @@ function Bitcoin(options) { // for testing purposes this._process = options.process || process; - this.on('error', function(err) { + this.on("error", function (err) { log.error(err.stack); }); } @@ -79,44 +79,52 @@ Bitcoin.DEFAULT_TIP_UPDATE_INTERVAL = 15000; Bitcoin.DEFAULT_TRANSACTION_CONCURRENCY = 5; Bitcoin.DEFAULT_CONFIG_SETTINGS = { server: 1, - whitelist: '127.0.0.1', + whitelist: "127.0.0.1", txindex: 1, addressindex: 1, timestampindex: 1, spentindex: 1, - zmqpubrawtx: 'tcp://127.0.0.1:28332', - zmqpubhashblock: 'tcp://127.0.0.1:28332', - rpcallowip: '127.0.0.1', - rpcuser: 'bitcoin', - rpcpassword: 'local321', - uacomment: 'bitcore' + zmqpubrawtx: "tcp://127.0.0.1:28332", + zmqpubhashblock: "tcp://127.0.0.1:28332", + rpcallowip: "127.0.0.1", + rpcuser: "bitcoin", + rpcpassword: "local321", + uacomment: "bitcore", }; -Bitcoin.prototype._initDefaults = function(options) { +Bitcoin.prototype._initDefaults = function (options) { /* jshint maxcomplexity: 15 */ // limits this.maxTxids = options.maxTxids || Bitcoin.DEFAULT_MAX_TXIDS; - this.maxTransactionHistory = options.maxTransactionHistory || Bitcoin.DEFAULT_MAX_HISTORY; - this.maxAddressesQuery = options.maxAddressesQuery || Bitcoin.DEFAULT_MAX_ADDRESSES_QUERY; - this.shutdownTimeout = options.shutdownTimeout || Bitcoin.DEFAULT_SHUTDOWN_TIMEOUT; + this.maxTransactionHistory = + options.maxTransactionHistory || Bitcoin.DEFAULT_MAX_HISTORY; + this.maxAddressesQuery = + options.maxAddressesQuery || Bitcoin.DEFAULT_MAX_ADDRESSES_QUERY; + this.shutdownTimeout = + options.shutdownTimeout || Bitcoin.DEFAULT_SHUTDOWN_TIMEOUT; // spawn restart setting - this.spawnRestartTime = options.spawnRestartTime || Bitcoin.DEFAULT_SPAWN_RESTART_TIME; + this.spawnRestartTime = + options.spawnRestartTime || Bitcoin.DEFAULT_SPAWN_RESTART_TIME; this.spawnStopTime = options.spawnStopTime || Bitcoin.DEFAULT_SPAWN_STOP_TIME; // try all interval - this.tryAllInterval = options.tryAllInterval || Bitcoin.DEFAULT_TRY_ALL_INTERVAL; - this.startRetryInterval = options.startRetryInterval || Bitcoin.DEFAULT_START_RETRY_INTERVAL; + this.tryAllInterval = + options.tryAllInterval || Bitcoin.DEFAULT_TRY_ALL_INTERVAL; + this.startRetryInterval = + options.startRetryInterval || Bitcoin.DEFAULT_START_RETRY_INTERVAL; // rpc limits - this.transactionConcurrency = options.transactionConcurrency || Bitcoin.DEFAULT_TRANSACTION_CONCURRENCY; + this.transactionConcurrency = + options.transactionConcurrency || Bitcoin.DEFAULT_TRANSACTION_CONCURRENCY; // sync progress level when zmq subscribes to events - this.zmqSubscribeProgress = options.zmqSubscribeProgress || Bitcoin.DEFAULT_ZMQ_SUBSCRIBE_PROGRESS; + this.zmqSubscribeProgress = + options.zmqSubscribeProgress || Bitcoin.DEFAULT_ZMQ_SUBSCRIBE_PROGRESS; }; -Bitcoin.prototype._initCaches = function() { +Bitcoin.prototype._initCaches = function () { // caches valid until there is a new block this.utxosCache = LRU(50000); this.txidsCache = LRU(50000); @@ -137,47 +145,47 @@ Bitcoin.prototype._initCaches = function() { this.lastTipTimeout = false; }; -Bitcoin.prototype._initClients = function() { +Bitcoin.prototype._initClients = function () { var self = this; this.nodes = []; this.nodesIndex = 0; - Object.defineProperty(this, 'client', { - get: function() { + Object.defineProperty(this, "client", { + get: function () { var client = self.nodes[self.nodesIndex].client; self.nodesIndex = (self.nodesIndex + 1) % self.nodes.length; return client; }, enumerable: true, - configurable: false + configurable: false, }); }; /** * Called by Node to determine the available API methods. */ -Bitcoin.prototype.getAPIMethods = function() { +Bitcoin.prototype.getAPIMethods = function () { var methods = [ - ['getBlock', this, this.getBlock, 1], - ['getRawBlock', this, this.getRawBlock, 1], - ['getBlockHeader', this, this.getBlockHeader, 1], - ['getBlockOverview', this, this.getBlockOverview, 1], - ['getBlockHashesByTimestamp', this, this.getBlockHashesByTimestamp, 2], - ['getBestBlockHash', this, this.getBestBlockHash, 0], - ['getSpentInfo', this, this.getSpentInfo, 1], - ['getInfo', this, this.getInfo, 0], - ['syncPercentage', this, this.syncPercentage, 0], - ['isSynced', this, this.isSynced, 0], - ['getRawTransaction', this, this.getRawTransaction, 1], - ['getTransaction', this, this.getTransaction, 1], - ['getDetailedTransaction', this, this.getDetailedTransaction, 1], - ['sendTransaction', this, this.sendTransaction, 1], - ['estimateFee', this, this.estimateFee, 1], - ['getAddressTxids', this, this.getAddressTxids, 2], - ['getAddressBalance', this, this.getAddressBalance, 2], - ['getAddressUnspentOutputs', this, this.getAddressUnspentOutputs, 2], - ['getAddressHistory', this, this.getAddressHistory, 2], - ['getAddressSummary', this, this.getAddressSummary, 1], - ['generateBlock', this, this.generateBlock, 1] + ["getBlock", this, this.getBlock, 1], + ["getRawBlock", this, this.getRawBlock, 1], + ["getBlockHeader", this, this.getBlockHeader, 1], + ["getBlockOverview", this, this.getBlockOverview, 1], + ["getBlockHashesByTimestamp", this, this.getBlockHashesByTimestamp, 2], + ["getBestBlockHash", this, this.getBestBlockHash, 0], + ["getSpentInfo", this, this.getSpentInfo, 1], + ["getInfo", this, this.getInfo, 0], + ["syncPercentage", this, this.syncPercentage, 0], + ["isSynced", this, this.isSynced, 0], + ["getRawTransaction", this, this.getRawTransaction, 1], + ["getTransaction", this, this.getTransaction, 1], + ["getDetailedTransaction", this, this.getDetailedTransaction, 1], + ["sendTransaction", this, this.sendTransaction, 1], + ["estimateFee", this, this.estimateFee, 1], + ["getAddressTxids", this, this.getAddressTxids, 2], + ["getAddressBalance", this, this.getAddressBalance, 2], + ["getAddressUnspentOutputs", this, this.getAddressUnspentOutputs, 2], + ["getAddressHistory", this, this.getAddressHistory, 2], + ["getAddressSummary", this, this.getAddressSummary, 1], + ["generateBlock", this, this.generateBlock, 1], ]; return methods; }; @@ -185,47 +193,59 @@ Bitcoin.prototype.getAPIMethods = function() { /** * Called by the Bus to determine the available events. */ -Bitcoin.prototype.getPublishEvents = function() { +Bitcoin.prototype.getPublishEvents = function () { return [ { - name: 'bitcoind/rawtransaction', + name: "bitcoind/rawtransaction", scope: this, - subscribe: this.subscribe.bind(this, 'rawtransaction'), - unsubscribe: this.unsubscribe.bind(this, 'rawtransaction') + subscribe: this.subscribe.bind(this, "rawtransaction"), + unsubscribe: this.unsubscribe.bind(this, "rawtransaction"), }, { - name: 'bitcoind/hashblock', + name: "bitcoind/hashblock", scope: this, - subscribe: this.subscribe.bind(this, 'hashblock'), - unsubscribe: this.unsubscribe.bind(this, 'hashblock') + subscribe: this.subscribe.bind(this, "hashblock"), + unsubscribe: this.unsubscribe.bind(this, "hashblock"), }, { - name: 'bitcoind/addresstxid', + name: "bitcoind/addresstxid", scope: this, subscribe: this.subscribeAddress.bind(this), - unsubscribe: this.unsubscribeAddress.bind(this) - } + unsubscribe: this.unsubscribeAddress.bind(this), + }, ]; }; -Bitcoin.prototype.subscribe = function(name, emitter) { +Bitcoin.prototype.subscribe = function (name, emitter) { this.subscriptions[name].push(emitter); - log.info(emitter.remoteAddress, 'subscribe:', 'bitcoind/' + name, 'total:', this.subscriptions[name].length); + log.info( + emitter.remoteAddress, + "subscribe:", + "bitcoind/" + name, + "total:", + this.subscriptions[name].length + ); }; -Bitcoin.prototype.unsubscribe = function(name, emitter) { +Bitcoin.prototype.unsubscribe = function (name, emitter) { var index = this.subscriptions[name].indexOf(emitter); if (index > -1) { this.subscriptions[name].splice(index, 1); } - log.info(emitter.remoteAddress, 'unsubscribe:', 'bitcoind/' + name, 'total:', this.subscriptions[name].length); + log.info( + emitter.remoteAddress, + "unsubscribe:", + "bitcoind/" + name, + "total:", + this.subscriptions[name].length + ); }; -Bitcoin.prototype.subscribeAddress = function(emitter, addresses) { +Bitcoin.prototype.subscribeAddress = function (emitter, addresses) { var self = this; function addAddress(addressStr) { - if(self.subscriptions.address[addressStr]) { + if (self.subscriptions.address[addressStr]) { var emitters = self.subscriptions.address[addressStr]; var index = emitters.indexOf(emitter); if (index === -1) { @@ -236,25 +256,31 @@ Bitcoin.prototype.subscribeAddress = function(emitter, addresses) { } } - for(var i = 0; i < addresses.length; i++) { + for (var i = 0; i < addresses.length; i++) { if (bitcore.Address.isValid(addresses[i], this.node.network)) { addAddress(addresses[i]); } } - log.info(emitter.remoteAddress, 'subscribe:', 'bitcoind/addresstxid', 'total:', _.size(this.subscriptions.address)); + log.info( + emitter.remoteAddress, + "subscribe:", + "bitcoind/addresstxid", + "total:", + _.size(this.subscriptions.address) + ); }; -Bitcoin.prototype.unsubscribeAddress = function(emitter, addresses) { +Bitcoin.prototype.unsubscribeAddress = function (emitter, addresses) { var self = this; - if(!addresses) { + if (!addresses) { return this.unsubscribeAddressAll(emitter); } function removeAddress(addressStr) { var emitters = self.subscriptions.address[addressStr]; var index = emitters.indexOf(emitter); - if(index > -1) { + if (index > -1) { emitters.splice(index, 1); if (emitters.length === 0) { delete self.subscriptions.address[addressStr]; @@ -262,13 +288,19 @@ Bitcoin.prototype.unsubscribeAddress = function(emitter, addresses) { } } - for(var i = 0; i < addresses.length; i++) { - if(this.subscriptions.address[addresses[i]]) { + for (var i = 0; i < addresses.length; i++) { + if (this.subscriptions.address[addresses[i]]) { removeAddress(addresses[i]); } } - log.info(emitter.remoteAddress, 'unsubscribe:', 'bitcoind/addresstxid', 'total:', _.size(this.subscriptions.address)); + log.info( + emitter.remoteAddress, + "unsubscribe:", + "bitcoind/addresstxid", + "total:", + _.size(this.subscriptions.address) + ); }; /** @@ -276,37 +308,43 @@ Bitcoin.prototype.unsubscribeAddress = function(emitter, addresses) { * @param {String} name - The name of the event * @param {EventEmitter} emitter - An instance of an event emitter */ -Bitcoin.prototype.unsubscribeAddressAll = function(emitter) { - for(var hashHex in this.subscriptions.address) { +Bitcoin.prototype.unsubscribeAddressAll = function (emitter) { + for (var hashHex in this.subscriptions.address) { var emitters = this.subscriptions.address[hashHex]; var index = emitters.indexOf(emitter); - if(index > -1) { + if (index > -1) { emitters.splice(index, 1); } if (emitters.length === 0) { delete this.subscriptions.address[hashHex]; } } - log.info(emitter.remoteAddress, 'unsubscribe:', 'bitcoind/addresstxid', 'total:', _.size(this.subscriptions.address)); + log.info( + emitter.remoteAddress, + "unsubscribe:", + "bitcoind/addresstxid", + "total:", + _.size(this.subscriptions.address) + ); }; -Bitcoin.prototype._getDefaultConfig = function() { - var config = ''; +Bitcoin.prototype._getDefaultConfig = function () { + var config = ""; var defaults = Bitcoin.DEFAULT_CONFIG_SETTINGS; - for(var key in defaults) { - config += key + '=' + defaults[key] + '\n'; + for (var key in defaults) { + config += key + "=" + defaults[key] + "\n"; } return config; }; -Bitcoin.prototype._parseBitcoinConf = function(configPath) { +Bitcoin.prototype._parseBitcoinConf = function (configPath) { var options = {}; var file = fs.readFileSync(configPath); - var unparsed = file.toString().split('\n'); - for(var i = 0; i < unparsed.length; i++) { + var unparsed = file.toString().split("\n"); + for (var i = 0; i < unparsed.length; i++) { var line = unparsed[i]; if (!line.match(/^\#/) && line.match(/\=/)) { - var option = line.split('='); + var option = line.split("="); var value; if (!Number.isNaN(Number(option[1]))) { value = Number(option[1]); @@ -319,28 +357,40 @@ Bitcoin.prototype._parseBitcoinConf = function(configPath) { return options; }; -Bitcoin.prototype._expandRelativeDatadir = function() { +Bitcoin.prototype._expandRelativeDatadir = function () { if (!utils.isAbsolutePath(this.options.spawn.datadir)) { $.checkState(this.node.configPath); $.checkState(utils.isAbsolutePath(this.node.configPath)); var baseConfigPath = path.dirname(this.node.configPath); - this.options.spawn.datadir = path.resolve(baseConfigPath, this.options.spawn.datadir); + this.options.spawn.datadir = path.resolve( + baseConfigPath, + this.options.spawn.datadir + ); } }; -Bitcoin.prototype._loadSpawnConfiguration = function(node) { +Bitcoin.prototype._loadSpawnConfiguration = function (node) { /* jshint maxstatements: 25 */ - $.checkArgument(this.options.spawn, 'Please specify "spawn" in komodod config options'); - $.checkArgument(this.options.spawn.datadir, 'Please specify "spawn.datadir" in komodod config options'); - $.checkArgument(this.options.spawn.exec, 'Please specify "spawn.exec" in komodod config options'); + $.checkArgument( + this.options.spawn, + 'Please specify "spawn" in komodod config options' + ); + $.checkArgument( + this.options.spawn.datadir, + 'Please specify "spawn.datadir" in komodod config options' + ); + $.checkArgument( + this.options.spawn.exec, + 'Please specify "spawn.exec" in komodod config options' + ); this._expandRelativeDatadir(); var spawnOptions = this.options.spawn; - var configPath = path.resolve(spawnOptions.datadir, './komodo.conf'); + var configPath = path.resolve(spawnOptions.datadir, "./komodo.conf"); - log.info('Using komodo config file:', configPath); + log.info("Using komodo config file:", configPath); this.spawn = {}; this.spawn.datadir = this.options.spawn.datadir; @@ -368,29 +418,28 @@ Bitcoin.prototype._loadSpawnConfiguration = function(node) { var spawnConfig = this.spawn.config; this._checkConfigIndexes(spawnConfig, node); - }; -Bitcoin.prototype._checkConfigIndexes = function(spawnConfig, node) { +Bitcoin.prototype._checkConfigIndexes = function (spawnConfig, node) { $.checkState( spawnConfig.txindex && spawnConfig.txindex === 1, '"txindex" option is required in order to use transaction query features of bitcore-node. ' + 'Please add "txindex=1" to your configuration and reindex an existing database if ' + - 'necessary with reindex=1' + "necessary with reindex=1" ); $.checkState( spawnConfig.addressindex && spawnConfig.addressindex === 1, '"addressindex" option is required in order to use address query features of bitcore-node. ' + 'Please add "addressindex=1" to your configuration and reindex an existing database if ' + - 'necessary with reindex=1' + "necessary with reindex=1" ); $.checkState( spawnConfig.spentindex && spawnConfig.spentindex === 1, '"spentindex" option is required in order to use spent info query features of bitcore-node. ' + 'Please add "spentindex=1" to your configuration and reindex an existing database if ' + - 'necessary with reindex=1' + "necessary with reindex=1" ); $.checkState( @@ -412,20 +461,22 @@ Bitcoin.prototype._checkConfigIndexes = function(spawnConfig, node) { ); $.checkState( - (spawnConfig.zmqpubhashblock === spawnConfig.zmqpubrawtx), + spawnConfig.zmqpubhashblock === spawnConfig.zmqpubrawtx, '"zmqpubrawtx" and "zmqpubhashblock" are expected to the same host and port in komodo.conf' ); if (spawnConfig.reindex && spawnConfig.reindex === 1) { - log.warn('Reindex option is currently enabled. This means that komodod is undergoing a reindex. ' + - 'The reindex flag will start the index from beginning every time the node is started, so it ' + - 'should be removed after the reindex has been initiated. Once the reindex is complete, the rest ' + - 'of bitcore-node services will start.'); + log.warn( + "Reindex option is currently enabled. This means that komodod is undergoing a reindex. " + + "The reindex flag will start the index from beginning every time the node is started, so it " + + "should be removed after the reindex has been initiated. Once the reindex is complete, the rest " + + "of bitcore-node services will start." + ); node._reindex = true; } }; -Bitcoin.prototype._resetCaches = function() { +Bitcoin.prototype._resetCaches = function () { this.transactionDetailedCache.reset(); this.utxosCache.reset(); this.txidsCache.reset(); @@ -434,61 +485,64 @@ Bitcoin.prototype._resetCaches = function() { this.blockOverviewCache.reset(); }; -Bitcoin.prototype._tryAllClients = function(func, callback) { +Bitcoin.prototype._tryAllClients = function (func, callback) { var self = this; var nodesIndex = this.nodesIndex; - var retry = function(done) { + var retry = function (done) { var client = self.nodes[nodesIndex].client; nodesIndex = (nodesIndex + 1) % self.nodes.length; func(client, done); }; - async.retry({times: this.nodes.length, interval: this.tryAllInterval || 1000}, retry, callback); + async.retry( + { times: this.nodes.length, interval: this.tryAllInterval || 1000 }, + retry, + callback + ); }; -Bitcoin.prototype._wrapRPCError = function(errObj) { +Bitcoin.prototype._wrapRPCError = function (errObj) { var err = new errors.RPCError(errObj.message); err.code = errObj.code; return err; }; -Bitcoin.prototype._initChain = function(callback) { +Bitcoin.prototype._initChain = function (callback) { var self = this; - self.client.getBestBlockHash(function(err, response) { + self.client.getBestBlockHash(function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } - self.client.getBlock(response.result, function(err, response) { + self.client.getBlock(response.result, function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } self.height = response.result.height; - self.client.getBlockHash(0, function(err, response) { + self.client.getBlockHash(0, function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } var blockhash = response.result; - self.getRawBlock(blockhash, function(err, blockBuffer) { + self.getRawBlock(blockhash, function (err, blockBuffer) { if (err) { return callback(err); } self.genesisBuffer = blockBuffer; - self.emit('ready'); - log.info('Komodo Daemon Ready'); + self.emit("ready"); + log.info("Komodo Daemon Ready"); callback(); }); }); - }); }); }; -Bitcoin.prototype._getDefaultConf = function() { +Bitcoin.prototype._getDefaultConf = function () { var networkOptions = { - rpcport: 8232 + rpcport: 8232, }; if (this.node.network === bitcore.Networks.testnet) { networkOptions.rpcport = 18232; @@ -496,48 +550,50 @@ Bitcoin.prototype._getDefaultConf = function() { return networkOptions; }; -Bitcoin.prototype._getNetworkConfigPath = function() { +Bitcoin.prototype._getNetworkConfigPath = function () { var networkPath; if (this.node.network === bitcore.Networks.testnet) { - networkPath = 'testnet3/komodo.conf'; + networkPath = "testnet3/komodo.conf"; if (this.node.network.regtestEnabled) { - networkPath = 'regtest/komodo.conf'; + networkPath = "regtest/komodo.conf"; } } return networkPath; }; -Bitcoin.prototype._getNetworkOption = function() { +Bitcoin.prototype._getNetworkOption = function () { var networkOption; if (this.node.network === bitcore.Networks.testnet) { - networkOption = '--testnet'; + networkOption = "--testnet"; if (this.node.network.regtestEnabled) { - networkOption = '--regtest'; + networkOption = "--regtest"; } } return networkOption; }; -Bitcoin.prototype._zmqBlockHandler = function(node, message) { +Bitcoin.prototype._zmqBlockHandler = function (node, message) { var self = this; // Update the current chain tip self._rapidProtectedUpdateTip(node, message); // Notify block subscribers - var id = message.toString('binary'); + var id = message.toString("binary"); if (!self.zmqKnownBlocks.get(id)) { self.zmqKnownBlocks.set(id, true); - self.emit('block', message); + self.emit("block", message); for (var i = 0; i < this.subscriptions.hashblock.length; i++) { - this.subscriptions.hashblock[i].emit('bitcoind/hashblock', message.toString('hex')); + this.subscriptions.hashblock[i].emit( + "bitcoind/hashblock", + message.toString("hex") + ); } } - }; -Bitcoin.prototype._rapidProtectedUpdateTip = function(node, message) { +Bitcoin.prototype._rapidProtectedUpdateTip = function (node, message) { var self = this; // Prevent a rapid succession of tip updates @@ -546,49 +602,54 @@ Bitcoin.prototype._rapidProtectedUpdateTip = function(node, message) { self._updateTip(node, message); } else { clearTimeout(self.lastTipTimeout); - self.lastTipTimeout = setTimeout(function() { + self.lastTipTimeout = setTimeout(function () { self._updateTip(node, message); }, 1000); } }; -Bitcoin.prototype._updateTip = function(node, message) { +Bitcoin.prototype._updateTip = function (node, message) { var self = this; - var hex = message.toString('hex'); + var hex = message.toString("hex"); if (hex !== self.tiphash) { - self.tiphash = message.toString('hex'); + self.tiphash = message.toString("hex"); // reset block valid caches self._resetCaches(); - node.client.getBlock(self.tiphash, function(err, response) { + node.client.getBlock(self.tiphash, function (err, response) { if (err) { var error = self._wrapRPCError(err); - self.emit('error', error); + self.emit("error", error); } else { self.height = response.result.height; $.checkState(self.height >= 0); - self.emit('tip', self.height); + self.emit("tip", self.height); } }); - if(!self.node.stopping) { - self.syncPercentage(function(err, percentage) { + if (!self.node.stopping) { + self.syncPercentage(function (err, percentage) { if (err) { - self.emit('error', err); + self.emit("error", err); } else { if (Math.round(percentage) >= 100) { - self.emit('synced', self.height); + self.emit("synced", self.height); } - log.info('Komodo Height:', self.height, 'Percentage:', percentage.toFixed(2)); + log.info( + "Komodo Height:", + self.height, + "Percentage:", + percentage.toFixed(2) + ); } }); } } }; -Bitcoin.prototype._getAddressesFromTransaction = function(transaction) { +Bitcoin.prototype._getAddressesFromTransaction = function (transaction) { var addresses = []; for (var i = 0; i < transaction.inputs.length; i++) { @@ -614,33 +675,36 @@ Bitcoin.prototype._getAddressesFromTransaction = function(transaction) { return _.uniq(addresses); }; -Bitcoin.prototype._notifyAddressTxidSubscribers = function(txid, transaction) { +Bitcoin.prototype._notifyAddressTxidSubscribers = function (txid, transaction) { var addresses = this._getAddressesFromTransaction(transaction); for (var i = 0; i < addresses.length; i++) { var address = addresses[i]; - if(this.subscriptions.address[address]) { + if (this.subscriptions.address[address]) { var emitters = this.subscriptions.address[address]; - for(var j = 0; j < emitters.length; j++) { - emitters[j].emit('bitcoind/addresstxid', { + for (var j = 0; j < emitters.length; j++) { + emitters[j].emit("bitcoind/addresstxid", { address: address, - txid: txid + txid: txid, }); } } } }; -Bitcoin.prototype._zmqTransactionHandler = function(node, message) { +Bitcoin.prototype._zmqTransactionHandler = function (node, message) { var self = this; var hash = bitcore.crypto.Hash.sha256sha256(message); - var id = hash.toString('binary'); + var id = hash.toString("binary"); if (!self.zmqKnownTransactions.get(id)) { self.zmqKnownTransactions.set(id, true); - self.emit('tx', message); + self.emit("tx", message); // Notify transaction subscribers for (var i = 0; i < this.subscriptions.rawtransaction.length; i++) { - this.subscriptions.rawtransaction[i].emit('bitcoind/rawtransaction', message.toString('hex')); + this.subscriptions.rawtransaction[i].emit( + "bitcoind/rawtransaction", + message.toString("hex") + ); } var tx = bitcore.Transaction(); @@ -648,30 +712,31 @@ Bitcoin.prototype._zmqTransactionHandler = function(node, message) { try { tx.fromString(message); } catch (error) { - tx.fromString("0400008085202f89000000000000000000000000000000000000000000"); + tx.fromString( + "0400008085202f89000000000000000000000000000000000000000000" + ); } - var txid = bitcore.util.buffer.reverse(hash).toString('hex'); + var txid = bitcore.util.buffer.reverse(hash).toString("hex"); self._notifyAddressTxidSubscribers(txid, tx); - } }; -Bitcoin.prototype._checkSyncedAndSubscribeZmqEvents = function(node) { +Bitcoin.prototype._checkSyncedAndSubscribeZmqEvents = function (node) { var self = this; var interval; function checkAndSubscribe(callback) { // update tip - node.client.getBestBlockHash(function(err, response) { + node.client.getBestBlockHash(function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } - var blockhash = new Buffer(response.result, 'hex'); - self.emit('block', blockhash); + var blockhash = new Buffer(response.result, "hex"); + self.emit("block", blockhash); self._updateTip(node, blockhash); // check if synced - node.client.getBlockchainInfo(function(err, response) { + node.client.getBlockchainInfo(function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } @@ -688,16 +753,16 @@ Bitcoin.prototype._checkSyncedAndSubscribeZmqEvents = function(node) { }); } - checkAndSubscribe(function(err, synced) { + checkAndSubscribe(function (err, synced) { if (err) { log.error(err); } if (!synced) { - interval = setInterval(function() { + interval = setInterval(function () { if (self.node.stopping) { return clearInterval(interval); } - checkAndSubscribe(function(err) { + checkAndSubscribe(function (err) { if (err) { log.error(err); } @@ -705,42 +770,44 @@ Bitcoin.prototype._checkSyncedAndSubscribeZmqEvents = function(node) { }, node._tipUpdateInterval || Bitcoin.DEFAULT_TIP_UPDATE_INTERVAL); } }); - }; -Bitcoin.prototype._subscribeZmqEvents = function(node) { +Bitcoin.prototype._subscribeZmqEvents = function (node) { var self = this; - node.zmqSubSocket.subscribe('hashblock'); - node.zmqSubSocket.subscribe('rawtx'); - node.zmqSubSocket.on('message', function(topic, message) { - var topicString = topic.toString('utf8'); - if (topicString === 'rawtx') { + node.zmqSubSocket.subscribe("hashblock"); + node.zmqSubSocket.subscribe("rawtx"); + node.zmqSubSocket.on("message", function (topic, message) { + var topicString = topic.toString("utf8"); + if (topicString === "rawtx") { self._zmqTransactionHandler(node, message); - } else if (topicString === 'hashblock') { + } else if (topicString === "hashblock") { self._zmqBlockHandler(node, message); } }); }; -Bitcoin.prototype._initZmqSubSocket = function(node, zmqUrl) { +Bitcoin.prototype._initZmqSubSocket = function (node, zmqUrl) { var self = this; - node.zmqSubSocket = zmq.socket('sub'); + node.zmqSubSocket = zmq.socket("sub"); - node.zmqSubSocket.on('connect', function(fd, endPoint) { - log.info('ZMQ connected to:', endPoint); + node.zmqSubSocket.on("connect", function (fd, endPoint) { + log.info("ZMQ connected to:", endPoint); }); - node.zmqSubSocket.on('connect_delay', function(fd, endPoint) { - log.warn('ZMQ connection delay:', endPoint); + node.zmqSubSocket.on("connect_delay", function (fd, endPoint) { + log.warn("ZMQ connection delay:", endPoint); }); - node.zmqSubSocket.on('disconnect', function(fd, endPoint) { - log.warn('ZMQ disconnect:', endPoint); + node.zmqSubSocket.on("disconnect", function (fd, endPoint) { + log.warn("ZMQ disconnect:", endPoint); }); - node.zmqSubSocket.on('monitor_error', function(err) { - log.error('Error in monitoring: %s, will restart monitoring in 5 seconds', err); - setTimeout(function() { + node.zmqSubSocket.on("monitor_error", function (err) { + log.error( + "Error in monitoring: %s, will restart monitoring in 5 seconds", + err + ); + setTimeout(function () { self.zmqSubSocket.monitor(500, 0); }, 5000); }); @@ -749,7 +816,7 @@ Bitcoin.prototype._initZmqSubSocket = function(node, zmqUrl) { node.zmqSubSocket.connect(zmqUrl); }; -Bitcoin.prototype._checkReindex = function(node, callback) { +Bitcoin.prototype._checkReindex = function (node, callback) { var self = this; var interval; function finish(err) { @@ -757,14 +824,16 @@ Bitcoin.prototype._checkReindex = function(node, callback) { callback(err); } if (node._reindex) { - interval = setInterval(function() { - node.client.getBlockchainInfo(function(err, response) { + interval = setInterval(function () { + node.client.getBlockchainInfo(function (err, response) { if (err) { return finish(self._wrapRPCError(err)); } var percentSynced = response.result.verificationprogress * 100; - log.info('Komodo Daemon Reindex Percentage: ' + percentSynced.toFixed(2)); + log.info( + "Komodo Daemon Reindex Percentage: " + percentSynced.toFixed(2) + ); if (Math.round(percentSynced) >= 100) { node._reindex = false; @@ -777,35 +846,35 @@ Bitcoin.prototype._checkReindex = function(node, callback) { } }; -Bitcoin.prototype._loadTipFromNode = function(node, callback) { +Bitcoin.prototype._loadTipFromNode = function (node, callback) { var self = this; - node.client.getBestBlockHash(function(err, response) { + node.client.getBestBlockHash(function (err, response) { if (err && err.code === -28) { log.warn(err.message); return callback(self._wrapRPCError(err)); } else if (err) { return callback(self._wrapRPCError(err)); } - node.client.getBlock(response.result, function(err, response) { + node.client.getBlock(response.result, function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } self.height = response.result.height; $.checkState(self.height >= 0); - self.emit('tip', self.height); + self.emit("tip", self.height); callback(); }); }); }; -Bitcoin.prototype._stopSpawnedBitcoin = function(callback) { +Bitcoin.prototype._stopSpawnedBitcoin = function (callback) { var self = this; var spawnOptions = this.options.spawn; - var pidPath = spawnOptions.datadir + '/komodod.pid'; + var pidPath = spawnOptions.datadir + "/komodod.pid"; function stopProcess() { - fs.readFile(pidPath, 'utf8', function(err, pid) { - if (err && err.code === 'ENOENT') { + fs.readFile(pidPath, "utf8", function (err, pid) { + if (err && err.code === "ENOENT") { // pid file doesn't exist we can continue return callback(null); } else if (err) { @@ -817,17 +886,20 @@ Bitcoin.prototype._stopSpawnedBitcoin = function(callback) { return callback(null); } try { - log.warn('Stopping existing spawned komodo process with pid: ' + pid); - self._process.kill(pid, 'SIGINT'); - } catch(err) { - if (err && err.code === 'ESRCH') { - log.warn('Unclean komodo process shutdown, process not found with pid: ' + pid); + log.warn("Stopping existing spawned komodo process with pid: " + pid); + self._process.kill(pid, "SIGINT"); + } catch (err) { + if (err && err.code === "ESRCH") { + log.warn( + "Unclean komodo process shutdown, process not found with pid: " + + pid + ); return callback(null); - } else if(err) { + } else if (err) { return callback(err); } } - setTimeout(function() { + setTimeout(function () { stopProcess(); }, self.spawnStopTime); }); @@ -836,7 +908,7 @@ Bitcoin.prototype._stopSpawnedBitcoin = function(callback) { stopProcess(); }; -Bitcoin.prototype._spawnChildProcess = function(callback) { +Bitcoin.prototype._spawnChildProcess = function (callback) { var self = this; var node = {}; @@ -845,41 +917,43 @@ Bitcoin.prototype._spawnChildProcess = function(callback) { try { self._loadSpawnConfiguration(node); - } catch(e) { + } catch (e) { return callback(e); } var options = [ - '--conf=' + this.spawn.configPath, - '--datadir=' + this.spawn.datadir, + "--conf=" + this.spawn.configPath, + "--datadir=" + this.spawn.datadir, ]; if (self._getNetworkOption()) { options.push(self._getNetworkOption()); } - self._stopSpawnedBitcoin(function(err) { + self._stopSpawnedBitcoin(function (err) { if (err) { return callback(err); } - log.info('Starting komodo process'); - self.spawn.process = spawn(self.spawn.exec, options, {stdio: 'inherit'}); + log.info("Starting komodo process"); + self.spawn.process = spawn(self.spawn.exec, options, { stdio: "inherit" }); - self.spawn.process.on('error', function(err) { - self.emit('error', err); + self.spawn.process.on("error", function (err) { + self.emit("error", err); }); - self.spawn.process.once('exit', function(code) { + self.spawn.process.once("exit", function (code) { if (!self.node.stopping) { - log.warn('Komodo process unexpectedly exited with code:', code); - log.warn('Restarting komodo child process in ' + self.spawnRestartTime + 'ms'); - setTimeout(function() { - self._spawnChildProcess(function(err) { + log.warn("Komodo process unexpectedly exited with code:", code); + log.warn( + "Restarting komodo child process in " + self.spawnRestartTime + "ms" + ); + setTimeout(function () { + self._spawnChildProcess(function (err) { if (err) { - return self.emit('error', err); + return self.emit("error", err); } - log.warn('Komodo process restarted'); + log.warn("Komodo process restarted"); }); }, self.spawnRestartTime); } @@ -887,137 +961,154 @@ Bitcoin.prototype._spawnChildProcess = function(callback) { var exitShutdown = false; - async.retry({times: 60, interval: self.startRetryInterval}, function(done) { - if (self.node.stopping) { - exitShutdown = true; - return done(); - } - - node.client = new BitcoinRPC({ - protocol: 'http', - host: '127.0.0.1', - port: self.spawn.config.rpcport, - user: self.spawn.config.rpcuser, - pass: self.spawn.config.rpcpassword - }); - - self._loadTipFromNode(node, done); - - }, function(err) { - if (err) { - return callback(err); - } - if (exitShutdown) { - return callback(new Error('Stopping while trying to spawn komodod.')); - } + async.retry( + { times: 60, interval: self.startRetryInterval }, + function (done) { + if (self.node.stopping) { + exitShutdown = true; + return done(); + } - self._initZmqSubSocket(node, self.spawn.config.zmqpubrawtx); + node.client = new BitcoinRPC({ + protocol: "http", + host: "127.0.0.1", + port: self.spawn.config.rpcport, + user: self.spawn.config.rpcuser, + pass: self.spawn.config.rpcpassword, + }); - self._checkReindex(node, function(err) { + self._loadTipFromNode(node, done); + }, + function (err) { if (err) { return callback(err); } - self._checkSyncedAndSubscribeZmqEvents(node); - callback(null, node); - }); + if (exitShutdown) { + return callback(new Error("Stopping while trying to spawn komodod.")); + } - }); + self._initZmqSubSocket(node, self.spawn.config.zmqpubrawtx); + self._checkReindex(node, function (err) { + if (err) { + return callback(err); + } + self._checkSyncedAndSubscribeZmqEvents(node); + callback(null, node); + }); + } + ); }); - }; -Bitcoin.prototype._connectProcess = function(config, callback) { +Bitcoin.prototype._connectProcess = function (config, callback) { var self = this; var node = {}; var exitShutdown = false; - async.retry({times: 60, interval: self.startRetryInterval}, function(done) { - if (self.node.stopping) { - exitShutdown = true; - return done(); - } - - node.client = new BitcoinRPC({ - protocol: config.rpcprotocol || 'http', - host: config.rpchost || '127.0.0.1', - port: config.rpcport, - user: config.rpcuser, - pass: config.rpcpassword, - rejectUnauthorized: _.isUndefined(config.rpcstrict) ? true : config.rpcstrict - }); + async.retry( + { times: 60, interval: self.startRetryInterval }, + function (done) { + if (self.node.stopping) { + exitShutdown = true; + return done(); + } - self._loadTipFromNode(node, done); + node.client = new BitcoinRPC({ + protocol: config.rpcprotocol || "http", + host: config.rpchost || "127.0.0.1", + port: config.rpcport, + user: config.rpcuser, + pass: config.rpcpassword, + rejectUnauthorized: _.isUndefined(config.rpcstrict) + ? true + : config.rpcstrict, + }); - }, function(err) { - if (err) { - return callback(err); - } - if (exitShutdown) { - return callback(new Error('Stopping while trying to connect to komodod.')); - } + self._loadTipFromNode(node, done); + }, + function (err) { + if (err) { + return callback(err); + } + if (exitShutdown) { + return callback( + new Error("Stopping while trying to connect to komodod.") + ); + } - self._initZmqSubSocket(node, config.zmqpubrawtx); - self._subscribeZmqEvents(node); + self._initZmqSubSocket(node, config.zmqpubrawtx); + self._subscribeZmqEvents(node); - callback(null, node); - }); + callback(null, node); + } + ); }; /** * Called by Node to start the service * @param {Function} callback */ -Bitcoin.prototype.start = function(callback) { +Bitcoin.prototype.start = function (callback) { var self = this; - async.series([ - function(next) { - if (self.options.spawn) { - self._spawnChildProcess(function(err, node) { - if (err) { - return next(err); - } - self.nodes.push(node); + async.series( + [ + function (next) { + if (self.options.spawn) { + self._spawnChildProcess(function (err, node) { + if (err) { + return next(err); + } + self.nodes.push(node); + next(); + }); + } else { next(); - }); - } else { - next(); - } - }, - function(next) { - if (self.options.connect) { - async.map(self.options.connect, self._connectProcess.bind(self), function(err, nodes) { - if (err) { - return callback(err); - } - for(var i = 0; i < nodes.length; i++) { - self.nodes.push(nodes[i]); - } + } + }, + function (next) { + if (self.options.connect) { + async.map( + self.options.connect, + self._connectProcess.bind(self), + function (err, nodes) { + if (err) { + return callback(err); + } + for (var i = 0; i < nodes.length; i++) { + self.nodes.push(nodes[i]); + } + next(); + } + ); + } else { next(); - }); - } else { - next(); + } + }, + ], + function (err) { + if (err) { + return callback(err); } + if (self.nodes.length === 0) { + return callback( + new Error( + 'Komodo configuration options "spawn" or "connect" are expected' + ) + ); + } + self._initChain(callback); } - ], function(err) { - if (err) { - return callback(err); - } - if (self.nodes.length === 0) { - return callback(new Error('Komodo configuration options "spawn" or "connect" are expected')); - } - self._initChain(callback); - }); - + ); }; /** * Helper to determine the state of the database. * @param {Function} callback */ -Bitcoin.prototype.isSynced = function(callback) { - this.syncPercentage(function(err, percentage) { +Bitcoin.prototype.isSynced = function (callback) { + this.syncPercentage(function (err, percentage) { if (err) { return callback(err); } @@ -1033,9 +1124,9 @@ Bitcoin.prototype.isSynced = function(callback) { * Helper to determine the progress of the database. * @param {Function} callback */ -Bitcoin.prototype.syncPercentage = function(callback) { +Bitcoin.prototype.syncPercentage = function (callback) { var self = this; - this.client.getBlockchainInfo(function(err, response) { + this.client.getBlockchainInfo(function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } @@ -1044,7 +1135,7 @@ Bitcoin.prototype.syncPercentage = function(callback) { }); }; -Bitcoin.prototype._normalizeAddressArg = function(addressArg) { +Bitcoin.prototype._normalizeAddressArg = function (addressArg) { var addresses = [addressArg]; if (Array.isArray(addressArg)) { addresses = addressArg; @@ -1058,23 +1149,26 @@ Bitcoin.prototype._normalizeAddressArg = function(addressArg) { * @param {Object} options * @param {Function} callback */ -Bitcoin.prototype.getAddressBalance = function(addressArg, options, callback) { +Bitcoin.prototype.getAddressBalance = function (addressArg, options, callback) { var self = this; var addresses = self._normalizeAddressArg(addressArg); - var cacheKey = addresses.join(''); + var cacheKey = addresses.join(""); var balance = self.balanceCache.get(cacheKey); if (balance) { - return setImmediate(function() { + return setImmediate(function () { callback(null, balance); }); } else { - this.client.getAddressBalance({addresses: addresses}, function(err, response) { - if (err) { - return callback(self._wrapRPCError(err)); + this.client.getAddressBalance( + { addresses: addresses }, + function (err, response) { + if (err) { + return callback(self._wrapRPCError(err)); + } + self.balanceCache.set(cacheKey, response.result); + callback(null, response.result); } - self.balanceCache.set(cacheKey, response.result); - callback(null, response.result); - }); + ); } }; @@ -1084,11 +1178,17 @@ Bitcoin.prototype.getAddressBalance = function(addressArg, options, callback) { * @param {Object} options * @param {Function} callback */ -Bitcoin.prototype.getAddressUnspentOutputs = function(addressArg, options, callback) { +Bitcoin.prototype.getAddressUnspentOutputs = function ( + addressArg, + options, + callback +) { var self = this; - var queryMempool = _.isUndefined(options.queryMempool) ? true : options.queryMempool; + var queryMempool = _.isUndefined(options.queryMempool) + ? true + : options.queryMempool; var addresses = self._normalizeAddressArg(addressArg); - var cacheKey = addresses.join(''); + var cacheKey = addresses.join(""); var utxos = self.utxosCache.get(cacheKey); function transformUnspentOutput(delta) { @@ -1099,7 +1199,7 @@ Bitcoin.prototype.getAddressUnspentOutputs = function(addressArg, options, callb outputIndex: delta.index, script: script.toHex(), satoshis: delta.satoshis, - timestamp: delta.timestamp + timestamp: delta.timestamp, }; } @@ -1129,11 +1229,11 @@ Bitcoin.prototype.getAddressUnspentOutputs = function(addressArg, options, callb var utxos = mempoolUnspentOutputs.reverse().concat(confirmedUtxos); if (isSpentOutputs) { - return utxos.filter(function(utxo) { + return utxos.filter(function (utxo) { if (!spentOutputs[utxo.txid]) { return true; } else { - return (spentOutputs[utxo.txid].indexOf(utxo.outputIndex) === -1); + return spentOutputs[utxo.txid].indexOf(utxo.outputIndex) === -1; } }); } @@ -1143,35 +1243,40 @@ Bitcoin.prototype.getAddressUnspentOutputs = function(addressArg, options, callb function finish(mempoolDeltas) { if (utxos) { - return setImmediate(function() { + return setImmediate(function () { callback(null, updateWithMempool(utxos, mempoolDeltas)); }); } else { - self.client.getAddressUtxos({addresses: addresses}, function(err, response) { - if (err) { - return callback(self._wrapRPCError(err)); + self.client.getAddressUtxos( + { addresses: addresses }, + function (err, response) { + if (err) { + return callback(self._wrapRPCError(err)); + } + var utxos = response.result.reverse(); + self.utxosCache.set(cacheKey, utxos); + callback(null, updateWithMempool(utxos, mempoolDeltas)); } - var utxos = response.result.reverse(); - self.utxosCache.set(cacheKey, utxos); - callback(null, updateWithMempool(utxos, mempoolDeltas)); - }); + ); } } if (queryMempool) { - self.client.getAddressMempool({addresses: addresses}, function(err, response) { - if (err) { - return callback(self._wrapRPCError(err)); + self.client.getAddressMempool( + { addresses: addresses }, + function (err, response) { + if (err) { + return callback(self._wrapRPCError(err)); + } + finish(response.result); } - finish(response.result); - }); + ); } else { finish(); } - }; -Bitcoin.prototype._getBalanceFromMempool = function(deltas) { +Bitcoin.prototype._getBalanceFromMempool = function (deltas) { var satoshis = 0; for (var i = 0; i < deltas.length; i++) { satoshis += deltas[i].satoshis; @@ -1179,7 +1284,7 @@ Bitcoin.prototype._getBalanceFromMempool = function(deltas) { return satoshis; }; -Bitcoin.prototype._getTxidsFromMempool = function(deltas) { +Bitcoin.prototype._getTxidsFromMempool = function (deltas) { var mempoolTxids = []; var mempoolTxidsKnown = {}; for (var i = 0; i < deltas.length; i++) { @@ -1192,10 +1297,12 @@ Bitcoin.prototype._getTxidsFromMempool = function(deltas) { return mempoolTxids; }; -Bitcoin.prototype._getHeightRangeQuery = function(options, clone) { +Bitcoin.prototype._getHeightRangeQuery = function (options, clone) { if (options.start >= 0 && options.end >= 0) { if (options.end > options.start) { - throw new TypeError('"end" is expected to be less than or equal to "start"'); + throw new TypeError( + '"end" is expected to be less than or equal to "start"' + ); } if (clone) { // reverse start and end as the order in bitcore is most recent to less recent @@ -1213,38 +1320,40 @@ Bitcoin.prototype._getHeightRangeQuery = function(options, clone) { * @param {Object} options * @param {Function} callback */ -Bitcoin.prototype.getAddressTxids = function(addressArg, options, callback) { +Bitcoin.prototype.getAddressTxids = function (addressArg, options, callback) { /* jshint maxstatements: 16 */ var self = this; - var queryMempool = _.isUndefined(options.queryMempool) ? true : options.queryMempool; + var queryMempool = _.isUndefined(options.queryMempool) + ? true + : options.queryMempool; var rangeQuery = false; try { rangeQuery = self._getHeightRangeQuery(options); - } catch(err) { + } catch (err) { return callback(err); } if (rangeQuery) { queryMempool = false; } var addresses = self._normalizeAddressArg(addressArg); - var cacheKey = addresses.join(''); + var cacheKey = addresses.join(""); var mempoolTxids = []; var txids = self.txidsCache.get(cacheKey); function finish() { if (txids && !rangeQuery) { var allTxids = mempoolTxids.reverse().concat(txids); - return setImmediate(function() { + return setImmediate(function () { callback(null, allTxids); }); } else { var txidOpts = { - addresses: addresses + addresses: addresses, }; if (rangeQuery) { self._getHeightRangeQuery(options, txidOpts); } - self.client.getAddressTxids(txidOpts, function(err, response) { + self.client.getAddressTxids(txidOpts, function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } @@ -1259,32 +1368,42 @@ Bitcoin.prototype.getAddressTxids = function(addressArg, options, callback) { } if (queryMempool) { - self.client.getAddressMempool({addresses: addresses}, function(err, response) { - if (err) { - return callback(self._wrapRPCError(err)); + self.client.getAddressMempool( + { addresses: addresses }, + function (err, response) { + if (err) { + return callback(self._wrapRPCError(err)); + } + mempoolTxids = self._getTxidsFromMempool(response.result); + finish(); } - mempoolTxids = self._getTxidsFromMempool(response.result); - finish(); - }); + ); } else { finish(); } - }; -Bitcoin.prototype._getConfirmationsDetail = function(transaction) { - $.checkState(this.height > 0, 'current height is unknown'); +Bitcoin.prototype._getConfirmationsDetail = function (transaction) { + $.checkState(this.height > 0, "current height is unknown"); var confirmations = 0; if (transaction.height >= 0) { confirmations = this.height - transaction.height + 1; } if (confirmations < 0) { - log.warn('Negative confirmations calculated for transaction:', transaction.hash); + log.warn( + "Negative confirmations calculated for transaction:", + transaction.hash + ); } return Math.max(0, confirmations); }; -Bitcoin.prototype._getAddressDetailsForInput = function(input, inputIndex, result, addressStrings) { +Bitcoin.prototype._getAddressDetailsForInput = function ( + input, + inputIndex, + result, + addressStrings +) { if (!input.address) { return; } @@ -1293,7 +1412,7 @@ Bitcoin.prototype._getAddressDetailsForInput = function(input, inputIndex, resul if (!result.addresses[address]) { result.addresses[address] = { inputIndexes: [inputIndex], - outputIndexes: [] + outputIndexes: [], }; } else { result.addresses[address].inputIndexes.push(inputIndex); @@ -1302,7 +1421,12 @@ Bitcoin.prototype._getAddressDetailsForInput = function(input, inputIndex, resul } }; -Bitcoin.prototype._getAddressDetailsForOutput = function(output, outputIndex, result, addressStrings) { +Bitcoin.prototype._getAddressDetailsForOutput = function ( + output, + outputIndex, + result, + addressStrings +) { if (!output.address) { return; } @@ -1311,7 +1435,7 @@ Bitcoin.prototype._getAddressDetailsForOutput = function(output, outputIndex, re if (!result.addresses[address]) { result.addresses[address] = { inputIndexes: [], - outputIndexes: [outputIndex] + outputIndexes: [outputIndex], }; } else { result.addresses[address].outputIndexes.push(outputIndex); @@ -1320,20 +1444,36 @@ Bitcoin.prototype._getAddressDetailsForOutput = function(output, outputIndex, re } }; -Bitcoin.prototype._getAddressDetailsForTransaction = function(transaction, addressStrings) { +Bitcoin.prototype._getAddressDetailsForTransaction = function ( + transaction, + addressStrings +) { var result = { addresses: {}, - satoshis: 0 + satoshis: 0, }; - for (var inputIndex = 0; inputIndex < transaction.inputs.length; inputIndex++) { + for ( + var inputIndex = 0; + inputIndex < transaction.inputs.length; + inputIndex++ + ) { var input = transaction.inputs[inputIndex]; this._getAddressDetailsForInput(input, inputIndex, result, addressStrings); } - for (var outputIndex = 0; outputIndex < transaction.outputs.length; outputIndex++) { + for ( + var outputIndex = 0; + outputIndex < transaction.outputs.length; + outputIndex++ + ) { var output = transaction.outputs[outputIndex]; - this._getAddressDetailsForOutput(output, outputIndex, result, addressStrings); + this._getAddressDetailsForOutput( + output, + outputIndex, + result, + addressStrings + ); } $.checkState(Number.isFinite(result.satoshis)); @@ -1346,30 +1486,34 @@ Bitcoin.prototype._getAddressDetailsForTransaction = function(transaction, addre * @param {Object} txid - A bitcoin transaction id * @param {Function} callback */ -Bitcoin.prototype._getAddressDetailedTransaction = function(txid, options, next) { +Bitcoin.prototype._getAddressDetailedTransaction = function ( + txid, + options, + next +) { var self = this; - self.getDetailedTransaction( - txid, - function(err, transaction) { - if (err) { - return next(err); - } + self.getDetailedTransaction(txid, function (err, transaction) { + if (err) { + return next(err); + } - var addressDetails = self._getAddressDetailsForTransaction(transaction, options.addressStrings); + var addressDetails = self._getAddressDetailsForTransaction( + transaction, + options.addressStrings + ); - var details = { - addresses: addressDetails.addresses, - satoshis: addressDetails.satoshis, - confirmations: self._getConfirmationsDetail(transaction), - tx: transaction - }; - next(null, details); - } - ); + var details = { + addresses: addressDetails.addresses, + satoshis: addressDetails.satoshis, + confirmations: self._getConfirmationsDetail(transaction), + tx: transaction, + }; + next(null, details); + }); }; -Bitcoin.prototype._getAddressStrings = function(addresses) { +Bitcoin.prototype._getAddressStrings = function (addresses) { var addressStrings = []; for (var i = 0; i < addresses.length; i++) { var address = addresses[i]; @@ -1378,17 +1522,20 @@ Bitcoin.prototype._getAddressStrings = function(addresses) { } else if (_.isString(address)) { addressStrings.push(address); } else { - throw new TypeError('Addresses are expected to be strings'); + throw new TypeError("Addresses are expected to be strings"); } } return addressStrings; }; -Bitcoin.prototype._paginateTxids = function(fullTxids, fromArg, toArg) { +Bitcoin.prototype._paginateTxids = function (fullTxids, fromArg, toArg) { var txids; var from = parseInt(fromArg); var to = parseInt(toArg); - $.checkState(from < to, '"from" (' + from + ') is expected to be less than "to" (' + to + ')'); + $.checkState( + from < to, + '"from" (' + from + ') is expected to be less than "to" (' + to + ")" + ); txids = fullTxids.slice(from, to); return txids; }; @@ -1399,27 +1546,39 @@ Bitcoin.prototype._paginateTxids = function(fullTxids, fromArg, toArg) { * @param {Object} options * @param {Function} callback */ -Bitcoin.prototype.getAddressHistory = function(addressArg, options, callback) { +Bitcoin.prototype.getAddressHistory = function (addressArg, options, callback) { var self = this; var addresses = self._normalizeAddressArg(addressArg); if (addresses.length > this.maxAddressesQuery) { - return callback(new TypeError('Maximum number of addresses (' + this.maxAddressesQuery + ') exceeded')); + return callback( + new TypeError( + "Maximum number of addresses (" + this.maxAddressesQuery + ") exceeded" + ) + ); } - var queryMempool = _.isUndefined(options.queryMempool) ? true : options.queryMempool; + var queryMempool = _.isUndefined(options.queryMempool) + ? true + : options.queryMempool; var addressStrings = this._getAddressStrings(addresses); var fromArg = parseInt(options.from || 0); var toArg = parseInt(options.to || self.maxTransactionHistory); - if ((toArg - fromArg) > self.maxTransactionHistory) { - return callback(new Error( - '"from" (' + options.from + ') and "to" (' + options.to + ') range should be less than or equal to ' + - self.maxTransactionHistory - )); + if (toArg - fromArg > self.maxTransactionHistory) { + return callback( + new Error( + '"from" (' + + options.from + + ') and "to" (' + + options.to + + ") range should be less than or equal to " + + self.maxTransactionHistory + ) + ); } - self.getAddressTxids(addresses, options, function(err, txids) { + self.getAddressTxids(addresses, options, function (err, txids) { if (err) { return callback(err); } @@ -1427,26 +1586,30 @@ Bitcoin.prototype.getAddressHistory = function(addressArg, options, callback) { var totalCount = txids.length; try { txids = self._paginateTxids(txids, fromArg, toArg); - } catch(e) { + } catch (e) { return callback(e); } async.mapLimit( txids, self.transactionConcurrency, - function(txid, next) { - self._getAddressDetailedTransaction(txid, { - queryMempool: queryMempool, - addressStrings: addressStrings - }, next); + function (txid, next) { + self._getAddressDetailedTransaction( + txid, + { + queryMempool: queryMempool, + addressStrings: addressStrings, + }, + next + ); }, - function(err, transactions) { + function (err, transactions) { if (err) { return callback(err); } callback(null, { totalCount: totalCount, - items: transactions + items: transactions, }); } ); @@ -1459,14 +1622,16 @@ Bitcoin.prototype.getAddressHistory = function(addressArg, options, callback) { * @param {Object} options * @param {Function} callback */ -Bitcoin.prototype.getAddressSummary = function(addressArg, options, callback) { +Bitcoin.prototype.getAddressSummary = function (addressArg, options, callback) { var self = this; var summary = {}; - var queryMempool = _.isUndefined(options.queryMempool) ? true : options.queryMempool; + var queryMempool = _.isUndefined(options.queryMempool) + ? true + : options.queryMempool; var summaryTxids = []; var mempoolTxids = []; var addresses = self._normalizeAddressArg(addressArg); - var cacheKey = addresses.join(''); + var cacheKey = addresses.join(""); function finishWithTxids() { if (!options.noTxList) { @@ -1474,16 +1639,22 @@ Bitcoin.prototype.getAddressSummary = function(addressArg, options, callback) { var fromArg = parseInt(options.from || 0); var toArg = parseInt(options.to || self.maxTxids); - if ((toArg - fromArg) > self.maxTxids) { - return callback(new Error( - '"from" (' + fromArg + ') and "to" (' + toArg + ') range should be less than or equal to ' + - self.maxTxids - )); + if (toArg - fromArg > self.maxTxids) { + return callback( + new Error( + '"from" (' + + fromArg + + ') and "to" (' + + toArg + + ") range should be less than or equal to " + + self.maxTxids + ) + ); } var paginatedTxids; try { paginatedTxids = self._paginateTxids(allTxids, fromArg, toArg); - } catch(e) { + } catch (e) { return callback(e); } @@ -1496,49 +1667,61 @@ Bitcoin.prototype.getAddressSummary = function(addressArg, options, callback) { } function querySummary() { - async.parallel([ - function getTxList(done) { - self.getAddressTxids(addresses, {queryMempool: false}, function(err, txids) { - if (err) { - return done(err); - } - summaryTxids = txids; - summary.appearances = txids.length; - done(); - }); - }, - function getBalance(done) { - self.getAddressBalance(addresses, options, function(err, data) { - if (err) { - return done(err); + async.parallel( + [ + function getTxList(done) { + self.getAddressTxids( + addresses, + { queryMempool: false }, + function (err, txids) { + if (err) { + return done(err); + } + summaryTxids = txids; + summary.appearances = txids.length; + done(); + } + ); + }, + function getBalance(done) { + self.getAddressBalance(addresses, options, function (err, data) { + if (err) { + return done(err); + } + summary.totalReceived = data.received; + summary.totalSpent = data.received - data.balance; + summary.balance = data.balance; + done(); + }); + }, + function getMempool(done) { + if (!queryMempool) { + return done(); } - summary.totalReceived = data.received; - summary.totalSpent = data.received - data.balance; - summary.balance = data.balance; - done(); - }); - }, - function getMempool(done) { - if (!queryMempool) { - return done(); + self.client.getAddressMempool( + { addresses: addresses }, + function (err, response) { + if (err) { + return done(self._wrapRPCError(err)); + } + mempoolTxids = self._getTxidsFromMempool(response.result); + summary.unconfirmedAppearances = mempoolTxids.length; + summary.unconfirmedBalance = self._getBalanceFromMempool( + response.result + ); + done(); + } + ); + }, + ], + function (err) { + if (err) { + return callback(err); } - self.client.getAddressMempool({'addresses': addresses}, function(err, response) { - if (err) { - return done(self._wrapRPCError(err)); - } - mempoolTxids = self._getTxidsFromMempool(response.result); - summary.unconfirmedAppearances = mempoolTxids.length; - summary.unconfirmedBalance = self._getBalanceFromMempool(response.result); - done(); - }); - }, - ], function(err) { - if (err) { - return callback(err); + self.summaryCache.set(cacheKey, summary); + finishWithTxids(); } - self.summaryCache.set(cacheKey, summary); - finishWithTxids(); - }); + ); } if (options.noTxList) { @@ -1551,14 +1734,16 @@ Bitcoin.prototype.getAddressSummary = function(addressArg, options, callback) { } else { querySummary(); } - }; -Bitcoin.prototype._maybeGetBlockHash = function(blockArg, callback) { +Bitcoin.prototype._maybeGetBlockHash = function (blockArg, callback) { var self = this; - if (_.isNumber(blockArg) || (blockArg.length < 40 && /^[0-9]+$/.test(blockArg))) { - self._tryAllClients(function(client, done) { - client.getBlockHash(blockArg, function(err, response) { + if ( + _.isNumber(blockArg) || + (blockArg.length < 40 && /^[0-9]+$/.test(blockArg)) + ) { + self._tryAllClients(function (client, done) { + client.getBlockHash(blockArg, function (err, response) { if (err) { return done(self._wrapRPCError(err)); } @@ -1575,7 +1760,7 @@ Bitcoin.prototype._maybeGetBlockHash = function(blockArg, callback) { * @param {String|Number} block - A block hash or block height number * @param {Function} callback */ -Bitcoin.prototype.getRawBlock = function(blockArg, callback) { +Bitcoin.prototype.getRawBlock = function (blockArg, callback) { // TODO apply performance patch to the RPC method for raw data var self = this; @@ -1583,12 +1768,12 @@ Bitcoin.prototype.getRawBlock = function(blockArg, callback) { if (err) { return callback(err); } - self._tryAllClients(function(client, done) { - self.client.getBlock(blockhash, false, function(err, response) { + self._tryAllClients(function (client, done) { + self.client.getBlock(blockhash, false, function (err, response) { if (err) { return done(self._wrapRPCError(err)); } - var buffer = new Buffer(response.result, 'hex'); + var buffer = new Buffer(response.result, "hex"); self.rawBlockCache.set(blockhash, buffer); done(null, buffer); }); @@ -1597,7 +1782,7 @@ Bitcoin.prototype.getRawBlock = function(blockArg, callback) { var cachedBlock = self.rawBlockCache.get(blockArg); if (cachedBlock) { - return setImmediate(function() { + return setImmediate(function () { callback(null, cachedBlock); }); } else { @@ -1610,7 +1795,7 @@ Bitcoin.prototype.getRawBlock = function(blockArg, callback) { * @param {String|Number} block - A block hash or block height number * @param {Function} callback */ -Bitcoin.prototype.getBlockOverview = function(blockArg, callback) { +Bitcoin.prototype.getBlockOverview = function (blockArg, callback) { var self = this; function queryBlock(err, blockhash) { @@ -1619,12 +1804,12 @@ Bitcoin.prototype.getBlockOverview = function(blockArg, callback) { } var cachedBlock = self.blockOverviewCache.get(blockhash); if (cachedBlock) { - return setImmediate(function() { + return setImmediate(function () { callback(null, cachedBlock); }); } else { - self._tryAllClients(function(client, done) { - client.getBlock(blockhash, true, function(err, response) { + self._tryAllClients(function (client, done) { + client.getBlock(blockhash, true, function (err, response) { if (err) { return done(self._wrapRPCError(err)); } @@ -1643,7 +1828,7 @@ Bitcoin.prototype.getBlockOverview = function(blockArg, callback) { nonce: result.nonce, bits: result.bits, difficulty: result.difficulty, - txids: result.tx + txids: result.tx, }; self.blockOverviewCache.set(blockhash, blockOverview); done(null, blockOverview); @@ -1660,7 +1845,7 @@ Bitcoin.prototype.getBlockOverview = function(blockArg, callback) { * @param {String|Number} block - A block hash or block height number * @param {Function} callback */ -Bitcoin.prototype.getBlock = function(blockArg, callback) { +Bitcoin.prototype.getBlock = function (blockArg, callback) { // TODO apply performance patch to the RPC method for raw data var self = this; @@ -1670,12 +1855,12 @@ Bitcoin.prototype.getBlock = function(blockArg, callback) { } var cachedBlock = self.blockCache.get(blockhash); if (cachedBlock) { - return setImmediate(function() { + return setImmediate(function () { callback(null, cachedBlock); }); } else { - self._tryAllClients(function(client, done) { - client.getBlock(blockhash, false, function(err, response) { + self._tryAllClients(function (client, done) { + client.getBlock(blockhash, false, function (err, response) { if (err) { return done(self._wrapRPCError(err)); } @@ -1696,9 +1881,9 @@ Bitcoin.prototype.getBlock = function(blockArg, callback) { * @param {Number} low - The older timestamp in seconds * @param {Function} callback */ -Bitcoin.prototype.getBlockHashesByTimestamp = function(high, low, callback) { +Bitcoin.prototype.getBlockHashesByTimestamp = function (high, low, callback) { var self = this; - self.client.getBlockHashes(high, low, function(err, response) { + self.client.getBlockHashes(high, low, function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } @@ -1726,15 +1911,15 @@ Bitcoin.prototype.getBlockHashesByTimestamp = function(high, low, callback) { * @param {String|Number} block - A block hash or block height * @param {Function} callback */ -Bitcoin.prototype.getBlockHeader = function(blockArg, callback) { +Bitcoin.prototype.getBlockHeader = function (blockArg, callback) { var self = this; function queryHeader(err, blockhash) { if (err) { return callback(err); } - self._tryAllClients(function(client, done) { - client.getBlockHeader(blockhash, function(err, response) { + self._tryAllClients(function (client, done) { + client.getBlockHeader(blockhash, function (err, response) { if (err) { return done(self._wrapRPCError(err)); } @@ -1752,7 +1937,7 @@ Bitcoin.prototype.getBlockHeader = function(blockArg, callback) { medianTime: result.mediantime, nonce: result.nonce, bits: result.bits, - difficulty: result.difficulty + difficulty: result.difficulty, }; done(null, header); }); @@ -1767,9 +1952,9 @@ Bitcoin.prototype.getBlockHeader = function(blockArg, callback) { * @param {Number} blocks - The number of blocks for the transaction to be confirmed. * @param {Function} callback */ -Bitcoin.prototype.estimateFee = function(blocks, callback) { +Bitcoin.prototype.estimateFee = function (blocks, callback) { var self = this; - this.client.estimateFee(blocks, function(err, response) { + this.client.estimateFee(blocks, function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } @@ -1784,7 +1969,7 @@ Bitcoin.prototype.estimateFee = function(blocks, callback) { * @param {Boolean=} options.allowAbsurdFees - Enable large fees * @param {Function} callback */ -Bitcoin.prototype.sendTransaction = function(tx, options, callback) { +Bitcoin.prototype.sendTransaction = function (tx, options, callback) { var self = this; var allowAbsurdFees = false; if (_.isFunction(options) && _.isUndefined(callback)) { @@ -1793,13 +1978,12 @@ Bitcoin.prototype.sendTransaction = function(tx, options, callback) { allowAbsurdFees = options.allowAbsurdFees; } - this.client.sendRawTransaction(tx, allowAbsurdFees, function(err, response) { + this.client.sendRawTransaction(tx, allowAbsurdFees, function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } callback(null, response.result); }); - }; /** @@ -1807,20 +1991,20 @@ Bitcoin.prototype.sendTransaction = function(tx, options, callback) { * @param {String} txid - The transaction hash * @param {Function} callback */ -Bitcoin.prototype.getRawTransaction = function(txid, callback) { +Bitcoin.prototype.getRawTransaction = function (txid, callback) { var self = this; var tx = self.rawTransactionCache.get(txid); if (tx) { - return setImmediate(function() { + return setImmediate(function () { callback(null, tx); }); } else { - self._tryAllClients(function(client, done) { - client.getRawTransaction(txid, function(err, response) { + self._tryAllClients(function (client, done) { + client.getRawTransaction(txid, function (err, response) { if (err) { return done(self._wrapRPCError(err)); } - var buffer = new Buffer(response.result, 'hex'); + var buffer = new Buffer(response.result, "hex"); self.rawTransactionCache.set(txid, buffer); done(null, buffer); }); @@ -1834,16 +2018,16 @@ Bitcoin.prototype.getRawTransaction = function(txid, callback) { * @param {Boolean} queryMempool - Include the mempool * @param {Function} callback */ -Bitcoin.prototype.getTransaction = function(txid, callback) { +Bitcoin.prototype.getTransaction = function (txid, callback) { var self = this; var tx = self.transactionCache.get(txid); if (tx) { - return setImmediate(function() { + return setImmediate(function () { callback(null, tx); }); } else { - self._tryAllClients(function(client, done) { - client.getRawTransaction(txid, function(err, response) { + self._tryAllClients(function (client, done) { + client.getRawTransaction(txid, function (err, response) { if (err) { return done(self._wrapRPCError(err)); } @@ -1898,14 +2082,14 @@ Bitcoin.prototype.getTransaction = function(txid, callback) { * @param {String} txid - The hex string of the transaction * @param {Function} callback */ -Bitcoin.prototype.getDetailedTransaction = function(txid, callback) { +Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var self = this; var tx = self.transactionDetailedCache.get(txid); function addInputsToTx(tx, result) { tx.inputs = []; tx.inputSatoshis = 0; - for(var inputIndex = 0; inputIndex < result.vin.length; inputIndex++) { + for (var inputIndex = 0; inputIndex < result.vin.length; inputIndex++) { var input = result.vin[inputIndex]; if (!tx.coinbase) { tx.inputSatoshis += input.valueSat; @@ -1925,7 +2109,7 @@ Bitcoin.prototype.getDetailedTransaction = function(txid, callback) { scriptAsm: scriptAsm || null, sequence: input.sequence, address: input.address || null, - satoshis: _.isUndefined(input.valueSat) ? null : input.valueSat + satoshis: _.isUndefined(input.valueSat) ? null : input.valueSat, }); } } @@ -1933,11 +2117,15 @@ Bitcoin.prototype.getDetailedTransaction = function(txid, callback) { function addOutputsToTx(tx, result) { tx.outputs = []; tx.outputSatoshis = 0; - for(var outputIndex = 0; outputIndex < result.vout.length; outputIndex++) { + for (var outputIndex = 0; outputIndex < result.vout.length; outputIndex++) { var out = result.vout[outputIndex]; tx.outputSatoshis += out.valueSat; var address = null; - if (out.scriptPubKey && out.scriptPubKey.addresses && out.scriptPubKey.addresses.length === 1) { + if ( + out.scriptPubKey && + out.scriptPubKey.addresses && + out.scriptPubKey.addresses.length === 1 + ) { address = out.scriptPubKey.addresses[0]; } tx.outputs.push({ @@ -1947,7 +2135,7 @@ Bitcoin.prototype.getDetailedTransaction = function(txid, callback) { spentTxId: out.spentTxId, spentIndex: out.spentIndex, spentHeight: out.spentHeight, - address: address + address: address, }); } } @@ -1967,12 +2155,12 @@ Bitcoin.prototype.getDetailedTransaction = function(txid, callback) { } if (tx) { - return setImmediate(function() { + return setImmediate(function () { callback(null, tx); }); } else { - self._tryAllClients(function(client, done) { - client.getRawTransaction(txid, 1, function(err, response) { + self._tryAllClients(function (client, done) { + client.getRawTransaction(txid, 1, function (err, response) { if (err) { return done(self._wrapRPCError(err)); } @@ -2001,7 +2189,8 @@ Bitcoin.prototype.getDetailedTransaction = function(txid, callback) { } if (!tx.coinbase) { - tx.feeSatoshis = tx.inputSatoshis - tx.outputSatoshis + netJoinSplitZatoshis; + tx.feeSatoshis = + tx.inputSatoshis - tx.outputSatoshis + netJoinSplitZatoshis; } else { tx.feeSatoshis = 0; } @@ -2020,7 +2209,11 @@ Bitcoin.prototype.getDetailedTransaction = function(txid, callback) { tx.bindingSig = result.bindingSig; } // Update tx.feeSatoshis with custom explorer JSON field 'valueBalanceZat' - tx.feeSatoshis = tx.feeSatoshis + (isNaN(result.valueBalanceZat) ? result.valueBalance * 1e8 : result.valueBalanceZat); + tx.feeSatoshis = + tx.feeSatoshis + + (isNaN(result.valueBalanceZat) + ? result.valueBalance * 1e8 + : result.valueBalanceZat); /* we should have custom 'valueBalanceZat' in src/rpc/rawtransaction.cpp TxToJSONExpanded function, here https://github.com/jl777/komodo/blob/dev/src/rpc/rawtransaction.cpp#L263 , like this: @@ -2028,7 +2221,6 @@ Bitcoin.prototype.getDetailedTransaction = function(txid, callback) { entry.push_back(Pair("valueBalance", ValueFromAmount(tx.valueBalance))); entry.push_back(Pair("valueBalanceZat", tx.valueBalance)); */ - } // Sapling END @@ -2043,9 +2235,9 @@ Bitcoin.prototype.getDetailedTransaction = function(txid, callback) { * Will get the best block hash for the chain. * @param {Function} callback */ -Bitcoin.prototype.getBestBlockHash = function(callback) { +Bitcoin.prototype.getBestBlockHash = function (callback) { var self = this; - this.client.getBestBlockHash(function(err, response) { + this.client.getBestBlockHash(function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } @@ -2057,9 +2249,9 @@ Bitcoin.prototype.getBestBlockHash = function(callback) { * Will give the txid and inputIndex that spent an output * @param {Function} callback */ -Bitcoin.prototype.getSpentInfo = function(options, callback) { +Bitcoin.prototype.getSpentInfo = function (options, callback) { var self = this; - this.client.getSpentInfo(options, function(err, response) { + this.client.getSpentInfo(options, function (err, response) { if (err && err.code === -5) { return callback(null, {}); } else if (err) { @@ -2085,9 +2277,9 @@ Bitcoin.prototype.getSpentInfo = function(options, callback) { * } * @param {Function} callback */ -Bitcoin.prototype.getInfo = function(callback) { +Bitcoin.prototype.getInfo = function (callback) { var self = this; - this.client.getInfo(function(err, response) { + this.client.getInfo(function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } @@ -2103,15 +2295,15 @@ Bitcoin.prototype.getInfo = function(callback) { testnet: result.testnet, relayFee: result.relayfee, errors: result.errors, - network: self.node.getNetworkName() + network: self.node.getNetworkName(), }; callback(null, info); }); }; -Bitcoin.prototype.generateBlock = function(num, callback) { +Bitcoin.prototype.generateBlock = function (num, callback) { var self = this; - this.client.generate(num, function(err, response) { + this.client.generate(num, function (err, response) { if (err) { return callback(self._wrapRPCError(err)); } @@ -2123,14 +2315,16 @@ Bitcoin.prototype.generateBlock = function(num, callback) { * Called by Node to stop the service. * @param {Function} callback */ -Bitcoin.prototype.stop = function(callback) { +Bitcoin.prototype.stop = function (callback) { if (this.spawn && this.spawn.process) { var exited = false; - this.spawn.process.once('exit', function(code) { + this.spawn.process.once("exit", function (code) { if (!exited) { exited = true; if (code !== 0) { - var error = new Error('komodod spawned process exited with status code: ' + code); + var error = new Error( + "komodod spawned process exited with status code: " + code + ); error.code = code; return callback(error); } else { @@ -2138,11 +2332,11 @@ Bitcoin.prototype.stop = function(callback) { } } }); - this.spawn.process.kill('SIGINT'); - setTimeout(function() { + this.spawn.process.kill("SIGINT"); + setTimeout(function () { if (!exited) { exited = true; - return callback(new Error('komodod process did not exit')); + return callback(new Error("komodod process did not exit")); } }, this.shutdownTimeout).unref(); } else { From 83913e57b6e69c47f5079a3ca92deef59c1fc705 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Sat, 23 Jan 2021 11:45:01 +0530 Subject: [PATCH 02/18] logic for reward calculation and addition to responses added --- lib/services/bitcoind.js | 199 ++++++++++++++++++++--------- lib/services/get-komodo-rewards.js | 58 +++++++++ 2 files changed, 200 insertions(+), 57 deletions(-) create mode 100644 lib/services/get-komodo-rewards.js diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 25ade5a3..dd5fcf90 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -13,6 +13,7 @@ var BitcoinRPC = require("bitcoind-rpc"); var $ = bitcore.util.preconditions; var _ = bitcore.deps._; var Transaction = bitcore.Transaction; +var getKomodoRewards = require("./get-komodo-rewards"); var index = require("../"); var errors = index.errors; @@ -520,7 +521,7 @@ Bitcoin.prototype._initChain = function (callback) { } self.height = response.result.height; - + self.tipTime = response.result.time; self.client.getBlockHash(0, function (err, response) { if (err) { return callback(self._wrapRPCError(err)); @@ -2102,6 +2103,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { } else if (input.coinbase) { script = input.coinbase; } + tx.inputs.push({ prevTxId: input.txid || null, outputIndex: _.isUndefined(input.vout) ? null : input.vout, @@ -2160,73 +2162,156 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { }); } else { self._tryAllClients(function (client, done) { - client.getRawTransaction(txid, 1, function (err, response) { - if (err) { - return done(self._wrapRPCError(err)); - } - var result = response.result; - var tx = { - hex: result.hex, - blockHash: result.blockhash, - height: result.height ? result.height : -1, - blockTimestamp: result.time, - version: result.version, - hash: txid, - locktime: result.locktime, - fOverwintered: result.overwintered, - }; - - if (result.vin[0] && result.vin[0].coinbase) { - tx.coinbase = true; - } - - addInputsToTx(tx, result); - addOutputsToTx(tx, result); + async.series( + [ + function (callback) { + client.getRawTransaction(txid, 1, function (err, response) { + if (err) { + return done(self._wrapRPCError(err)); + } + var result = response.result; + var tx = { + hex: result.hex, + blockHash: result.blockhash, + height: result.height ? result.height : -1, + blockTimestamp: result.time, + version: result.version, + hash: txid, + locktime: result.locktime, + fOverwintered: result.overwintered, + }; + + if (result.vin[0] && result.vin[0].coinbase) { + tx.coinbase = true; + } - var netJoinSplitZatoshis = 0; - if (tx.version >= 2) { - netJoinSplitZatoshis = addJoinSplitsToTx(tx, result); - } + addInputsToTx(tx, result); + addOutputsToTx(tx, result); - if (!tx.coinbase) { - tx.feeSatoshis = - tx.inputSatoshis - tx.outputSatoshis + netJoinSplitZatoshis; - } else { - tx.feeSatoshis = 0; - } + var netJoinSplitZatoshis = 0; + if (tx.version >= 2) { + netJoinSplitZatoshis = addJoinSplitsToTx(tx, result); + } + if (!tx.coinbase) { + tx.feeSatoshis = + tx.inputSatoshis - tx.outputSatoshis + netJoinSplitZatoshis; + } else { + tx.feeSatoshis = 0; + } - if (tx.fOverwintered) { - tx.nVersionGroupId = parseInt(result.versiongroupid, 16); - tx.nExpiryHeight = result.expiryheight; - } + if (tx.fOverwintered) { + tx.nVersionGroupId = parseInt(result.versiongroupid, 16); + tx.nExpiryHeight = result.expiryheight; + } - // Sapling START - if (tx.fOverwintered && tx.version >= 4) { - tx.valueBalance = result.valueBalance; - tx.spendDescs = result.vShieldedSpend; - tx.outputDescs = result.vShieldedOutput; - if (result.bindingSig) { - tx.bindingSig = result.bindingSig; - } - // Update tx.feeSatoshis with custom explorer JSON field 'valueBalanceZat' - tx.feeSatoshis = - tx.feeSatoshis + - (isNaN(result.valueBalanceZat) - ? result.valueBalance * 1e8 - : result.valueBalanceZat); - /* + // Sapling START + if (tx.fOverwintered && tx.version >= 4) { + tx.valueBalance = result.valueBalance; + tx.spendDescs = result.vShieldedSpend; + tx.outputDescs = result.vShieldedOutput; + if (result.bindingSig) { + tx.bindingSig = result.bindingSig; + } + // Update tx.feeSatoshis with custom explorer JSON field 'valueBalanceZat' + tx.feeSatoshis = + tx.feeSatoshis + + (isNaN(result.valueBalanceZat) + ? result.valueBalance * 1e8 + : result.valueBalanceZat); + /* we should have custom 'valueBalanceZat' in src/rpc/rawtransaction.cpp TxToJSONExpanded function, here https://github.com/jl777/komodo/blob/dev/src/rpc/rawtransaction.cpp#L263 , like this: entry.push_back(Pair("valueBalance", ValueFromAmount(tx.valueBalance))); entry.push_back(Pair("valueBalanceZat", tx.valueBalance)); */ - } - // Sapling END + } + // Sapling END - self.transactionDetailedCache.set(txid, tx); - done(null, tx); - }); + self.transactionDetailedCache.set(txid, tx); + callback(null, tx); + }); + }, + function (callback) { + var tx = self.transactionDetailedCache.get(txid); + var vins = tx.inputs; + var functionsArray = []; + for (let index = 0; index < vins.length; index++) { + functionsArray.push(function (callback) { + var prevTxId = vins[index].prevTxId || null; + var rewards = 0; + if (prevTxId) { + client.getRawTransaction( + prevTxId, + 1, + function (err, response) { + if (err) { + return done(self._wrapRPCError(err)); + } + var result = response.result; + var rewardData = { + tiptime: tx.blockTimestamp || self.tipTime, + locktime: result.locktime, + height: result.height, + satoshis: vins[index].satoshis, + }; + rewards = getKomodoRewards(rewardData); + callback(null, { + rewards: rewards, + prevTxnLocktime: result.locktime, + }); + } + ); + } else { + callback(null, { + rewards: rewards, + prevTxnLocktime: null, + }); + } + }); + } + + async.series(functionsArray, function (err, res) { + var totalReward = 0; + + //res.forEach((reward) => (totalReward = reward + totalReward)); + for (let index = 0; index < res.length; index++) { + tx.inputs[index].rewardClaimed = res[index].rewards + ? res[index].rewards * 1e-8 + : 0; + + var actualTimeRewardAccrued = res[index].prevTxnLocktime + ? (tx.blockTimestamp || self.tipTime) - + res[index].prevTxnLocktime + : null; + if (actualTimeRewardAccrued) { + tx.inputs[index].timeRewardAccrued = + actualTimeRewardAccrued < 31 * 24 * 60 * 60 + ? actualTimeRewardAccrued + : 31 * 24 * 60 * 60; + } else { + tx.inputs[index].timeRewardAccrued = null; + } + + totalReward = tx.inputs[index].rewardClaimed + totalReward; + } + tx.rewardClaimed = totalReward; + tx.feeSatoshis = + tx.inputSatoshis + tx.rewardClaimed * 1e8 - tx.outputSatoshis; + self.transactionDetailedCache.set(txid, tx); + callback(null, tx); + }); + + // self.transactionDetailedCache.set(txid, tx); + // callback(null, tx); + }, + ], + function (err, results) { + var tx = self.transactionDetailedCache.get(txid); + + done(null, tx); + } + ); }, callback); } }; diff --git a/lib/services/get-komodo-rewards.js b/lib/services/get-komodo-rewards.js new file mode 100644 index 00000000..b8bcab21 --- /dev/null +++ b/lib/services/get-komodo-rewards.js @@ -0,0 +1,58 @@ +var KOMODO_ENDOFERA = 7777777; +var LOCKTIME_THRESHOLD = 500000000; +var MIN_SATOSHIS = 1000000000; +var ONE_MONTH_CAP_HARDFORK = 1000000; +var ONE_HOUR = 60; +var ONE_MONTH = 31 * 24 * 60; +var ONE_YEAR = 365 * 24 * 60; +var DEVISOR = 10512000; + +var getKomodoRewards = (utxo) => { + // Validate types + ["tiptime", "locktime", "height", "satoshis"].forEach((property) => { + if (typeof utxo[property] !== "number") { + throw new TypeError(`\`${property}\` option must be a number.`); + } + }); + + // Destructure UTXO properties + //var { tiptime, locktime, height, satoshis } = utxo; + + var tiptime = utxo.tiptime; + var locktime = utxo.locktime; + var height = utxo.height; + var satoshis = utxo.satoshis; + + // Calculate coinage + var coinage = Math.floor((tiptime - locktime) / ONE_HOUR); + + // Return early if UTXO is not eligible for rewards + if ( + height >= KOMODO_ENDOFERA || + locktime < LOCKTIME_THRESHOLD || + satoshis < MIN_SATOSHIS || + coinage < ONE_HOUR || + !height + ) { + return 0; + } + + // Cap reward periods + var limit = height >= ONE_MONTH_CAP_HARDFORK ? ONE_MONTH : ONE_YEAR; + var rewardPeriod = Math.min(coinage, limit); + + // The first hour of coinage should not accrue rewards + rewardPeriod -= 59; + + // Calculate rewards + var rewards = Math.floor(satoshis / DEVISOR) * rewardPeriod; + + // Ensure reward value is never negative + if (rewards < 0) { + throw new Error("Reward should never be negative"); + } + + return rewards; +}; + +module.exports = getKomodoRewards; From 6ad601b06490f8fa0ef98d644d01ee34167e1d4d Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Sat, 23 Jan 2021 19:11:50 +0530 Subject: [PATCH 03/18] deals with reward calc for a txn with unconfirmed vins --- lib/services/bitcoind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index dd5fcf90..d50d2563 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2252,7 +2252,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var rewardData = { tiptime: tx.blockTimestamp || self.tipTime, locktime: result.locktime, - height: result.height, + height: result.height ? result.height : 1000001,//To satisfy getKomodoRewards constraints on unconfirmed transactions satoshis: vins[index].satoshis, }; rewards = getKomodoRewards(rewardData); From 545cfc3b4260174f8ab9ec75e78f24aca54c6eea Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Wed, 27 Jan 2021 15:42:28 +0530 Subject: [PATCH 04/18] changes base package dependency to gaeacodes/bitcore-node-komodo till testing is done --- lib/scaffold/create.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scaffold/create.js b/lib/scaffold/create.js index 40842c49..acac8901 100644 --- a/lib/scaffold/create.js +++ b/lib/scaffold/create.js @@ -20,7 +20,7 @@ var BASE_PACKAGE = { readme: 'README.md', dependencies: { 'bitcore-lib-komodo': 'git+https://git@github.com/DeckerSU/bitcore-lib-komodo', - 'bitcore-node-komodo': 'git+https://git@github.com/DeckerSU/bitcore-node-komodo' + 'bitcore-node-komodo': 'git+https://git@github.com/gaeacodes/bitcore-node-komodo' } }; From b1960f83116be8e188b926ef0caca4edc2fdc6dd Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Sat, 30 Jan 2021 14:11:45 +0530 Subject: [PATCH 05/18] testing --- lib/services/bitcoind.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index d50d2563..fc84a07b 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -1719,6 +1719,8 @@ Bitcoin.prototype.getAddressSummary = function (addressArg, options, callback) { if (err) { return callback(err); } + var abc = summary.txids; + console.log(abc); self.summaryCache.set(cacheKey, summary); finishWithTxids(); } @@ -2252,7 +2254,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var rewardData = { tiptime: tx.blockTimestamp || self.tipTime, locktime: result.locktime, - height: result.height ? result.height : 1000001,//To satisfy getKomodoRewards constraints on unconfirmed transactions + height: result.height ? result.height : 1000001, //To satisfy getKomodoRewards constraints on unconfirmed transactions satoshis: vins[index].satoshis, }; rewards = getKomodoRewards(rewardData); From a4e55ec6c7a37b3a7ce62d2947ca8981dbe31b24 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Tue, 2 Feb 2021 13:57:45 +0530 Subject: [PATCH 06/18] removed cache part --- lib/services/bitcoind.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index fc84a07b..e10b8590 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2164,6 +2164,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { }); } else { self._tryAllClients(function (client, done) { + let transactionData = {}; async.series( [ function (callback) { @@ -2230,12 +2231,17 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { } // Sapling END - self.transactionDetailedCache.set(txid, tx); + // self.transactionDetailedCache.set(txid, tx); + + transactionData.txid = txid; + transactionData.tx = tx; callback(null, tx); }); }, function (callback) { - var tx = self.transactionDetailedCache.get(txid); + // var tx = self.transactionDetailedCache.get(txid); + var tx = transactionData.tx; + var txid = transactionData.txid; var vins = tx.inputs; var functionsArray = []; for (let index = 0; index < vins.length; index++) { @@ -2279,7 +2285,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { //res.forEach((reward) => (totalReward = reward + totalReward)); for (let index = 0; index < res.length; index++) { tx.inputs[index].rewardClaimed = res[index].rewards - ? res[index].rewards * 1e-8 + ? (res[index].rewards * 1e-8).toFixed(8) : 0; var actualTimeRewardAccrued = res[index].prevTxnLocktime @@ -2300,16 +2306,17 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { tx.rewardClaimed = totalReward; tx.feeSatoshis = tx.inputSatoshis + tx.rewardClaimed * 1e8 - tx.outputSatoshis; - self.transactionDetailedCache.set(txid, tx); + // self.transactionDetailedCache.set(txid, tx); + transactionData.txid = txid; + transactionData.tx = tx; callback(null, tx); }); - - // self.transactionDetailedCache.set(txid, tx); - // callback(null, tx); }, ], function (err, results) { - var tx = self.transactionDetailedCache.get(txid); + // var tx = self.transactionDetailedCache.get(txid); + var tx = transactionData.tx; + var txid = transactionData.txid; done(null, tx); } From 1e90ed8bf23651ff3de661c5bd044c9e54dd42f3 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Tue, 2 Feb 2021 14:19:15 +0530 Subject: [PATCH 07/18] removed tofixed --- lib/services/bitcoind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index e10b8590..e74c2fc7 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2285,7 +2285,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { //res.forEach((reward) => (totalReward = reward + totalReward)); for (let index = 0; index < res.length; index++) { tx.inputs[index].rewardClaimed = res[index].rewards - ? (res[index].rewards * 1e-8).toFixed(8) + ? res[index].rewards * 1e-8 : 0; var actualTimeRewardAccrued = res[index].prevTxnLocktime From 4d419f7b168faa5ceffca8e7f961ec2a25e9a949 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Tue, 2 Feb 2021 16:55:40 +0530 Subject: [PATCH 08/18] Added self.tipTime --- lib/services/bitcoind.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index e74c2fc7..b6ddebb5 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -625,6 +625,7 @@ Bitcoin.prototype._updateTip = function (node, message) { self.emit("error", error); } else { self.height = response.result.height; + self.tipTime = response.result.time; $.checkState(self.height >= 0); self.emit("tip", self.height); } @@ -861,6 +862,7 @@ Bitcoin.prototype._loadTipFromNode = function (node, callback) { return callback(self._wrapRPCError(err)); } self.height = response.result.height; + self.tipTime = response.result.time; $.checkState(self.height >= 0); self.emit("tip", self.height); callback(); From c0d7204ef3c827559f56e2d14b875af03d95468f Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Tue, 2 Feb 2021 21:02:39 +0530 Subject: [PATCH 09/18] cleanup --- lib/services/bitcoind.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index b6ddebb5..65e18dea 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -1721,8 +1721,6 @@ Bitcoin.prototype.getAddressSummary = function (addressArg, options, callback) { if (err) { return callback(err); } - var abc = summary.txids; - console.log(abc); self.summaryCache.set(cacheKey, summary); finishWithTxids(); } @@ -2233,15 +2231,12 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { } // Sapling END - // self.transactionDetailedCache.set(txid, tx); - transactionData.txid = txid; transactionData.tx = tx; callback(null, tx); }); }, function (callback) { - // var tx = self.transactionDetailedCache.get(txid); var tx = transactionData.tx; var txid = transactionData.txid; var vins = tx.inputs; @@ -2308,7 +2303,6 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { tx.rewardClaimed = totalReward; tx.feeSatoshis = tx.inputSatoshis + tx.rewardClaimed * 1e8 - tx.outputSatoshis; - // self.transactionDetailedCache.set(txid, tx); transactionData.txid = txid; transactionData.tx = tx; callback(null, tx); @@ -2316,10 +2310,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { }, ], function (err, results) { - // var tx = self.transactionDetailedCache.get(txid); var tx = transactionData.tx; - var txid = transactionData.txid; - done(null, tx); } ); From 2a5814585b3070bf6d22366c5b9cd9ae92da0196 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Mon, 8 Feb 2021 16:08:09 +0530 Subject: [PATCH 10/18] let -> var --- lib/services/bitcoind.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 65e18dea..c720a100 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2164,7 +2164,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { }); } else { self._tryAllClients(function (client, done) { - let transactionData = {}; + var transactionData = {}; async.series( [ function (callback) { @@ -2241,7 +2241,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var txid = transactionData.txid; var vins = tx.inputs; var functionsArray = []; - for (let index = 0; index < vins.length; index++) { + for (var index = 0; index < vins.length; index++) { functionsArray.push(function (callback) { var prevTxId = vins[index].prevTxId || null; var rewards = 0; @@ -2280,7 +2280,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var totalReward = 0; //res.forEach((reward) => (totalReward = reward + totalReward)); - for (let index = 0; index < res.length; index++) { + for (var index = 0; index < res.length; index++) { tx.inputs[index].rewardClaimed = res[index].rewards ? res[index].rewards * 1e-8 : 0; From b4ae39d59edc21bd9637aed41da84cd7ce65314a Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Tue, 9 Feb 2021 12:19:39 +0530 Subject: [PATCH 11/18] returns txid for address summary --- lib/services/bitcoind.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index c720a100..9088cb4e 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -1721,6 +1721,10 @@ Bitcoin.prototype.getAddressSummary = function (addressArg, options, callback) { if (err) { return callback(err); } + var availableTxids = mempoolTxids.reverse().concat(summaryTxids); + summary.txidOverflow = + availableTxids.length > self.maxTxids ? true : false; + summary.availableTxids = !summary.txidOverflow ? availableTxids : []; self.summaryCache.set(cacheKey, summary); finishWithTxids(); } From 3a7dbc8e449851fb29379b08bcf2c121cfa8abc6 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Tue, 9 Feb 2021 12:52:23 +0530 Subject: [PATCH 12/18] cleanup --- lib/services/bitcoind.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 9088cb4e..0e53b79c 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2245,9 +2245,9 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var txid = transactionData.txid; var vins = tx.inputs; var functionsArray = []; - for (var index = 0; index < vins.length; index++) { + for (var i = 0; i < vins.length; i++) { functionsArray.push(function (callback) { - var prevTxId = vins[index].prevTxId || null; + var prevTxId = vins[i].prevTxId || null; var rewards = 0; if (prevTxId) { client.getRawTransaction( @@ -2262,7 +2262,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { tiptime: tx.blockTimestamp || self.tipTime, locktime: result.locktime, height: result.height ? result.height : 1000001, //To satisfy getKomodoRewards constraints on unconfirmed transactions - satoshis: vins[index].satoshis, + satoshis: vins[i].satoshis, }; rewards = getKomodoRewards(rewardData); callback(null, { @@ -2284,25 +2284,24 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var totalReward = 0; //res.forEach((reward) => (totalReward = reward + totalReward)); - for (var index = 0; index < res.length; index++) { - tx.inputs[index].rewardClaimed = res[index].rewards - ? res[index].rewards * 1e-8 + for (var i = 0; i < res.length; i++) { + tx.inputs[i].rewardClaimed = res[i].rewards + ? res[i].rewards * 1e-8 : 0; - var actualTimeRewardAccrued = res[index].prevTxnLocktime - ? (tx.blockTimestamp || self.tipTime) - - res[index].prevTxnLocktime + var actualTimeRewardAccrued = res[i].prevTxnLocktime + ? (tx.blockTimestamp || self.tipTime) - res[i].prevTxnLocktime : null; if (actualTimeRewardAccrued) { - tx.inputs[index].timeRewardAccrued = + tx.inputs[i].timeRewardAccrued = actualTimeRewardAccrued < 31 * 24 * 60 * 60 ? actualTimeRewardAccrued : 31 * 24 * 60 * 60; } else { - tx.inputs[index].timeRewardAccrued = null; + tx.inputs[i].timeRewardAccrued = null; } - totalReward = tx.inputs[index].rewardClaimed + totalReward; + totalReward = tx.inputs[i].rewardClaimed + totalReward; } tx.rewardClaimed = totalReward; tx.feeSatoshis = From b50e480653c2ce8d2c274351f5e1e66ed7c7d6ea Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Tue, 9 Feb 2021 14:54:43 +0530 Subject: [PATCH 13/18] var -> let --- lib/services/bitcoind.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 0e53b79c..eefb6fba 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2168,7 +2168,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { }); } else { self._tryAllClients(function (client, done) { - var transactionData = {}; + let transactionData = {}; async.series( [ function (callback) { @@ -2245,7 +2245,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var txid = transactionData.txid; var vins = tx.inputs; var functionsArray = []; - for (var i = 0; i < vins.length; i++) { + for (let i = 0; i < vins.length; i++) { functionsArray.push(function (callback) { var prevTxId = vins[i].prevTxId || null; var rewards = 0; @@ -2284,7 +2284,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var totalReward = 0; //res.forEach((reward) => (totalReward = reward + totalReward)); - for (var i = 0; i < res.length; i++) { + for (let i = 0; i < res.length; i++) { tx.inputs[i].rewardClaimed = res[i].rewards ? res[i].rewards * 1e-8 : 0; From 47933d14b278389431e38329cfd2b41f278acca9 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Wed, 10 Feb 2021 13:31:47 +0530 Subject: [PATCH 14/18] cleanup --- lib/services/bitcoind.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index eefb6fba..a48afd12 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2283,7 +2283,6 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { async.series(functionsArray, function (err, res) { var totalReward = 0; - //res.forEach((reward) => (totalReward = reward + totalReward)); for (let i = 0; i < res.length; i++) { tx.inputs[i].rewardClaimed = res[i].rewards ? res[i].rewards * 1e-8 From 70bc56923453e7eb011b02daac6c9b8a3c2d513b Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Wed, 10 Feb 2021 21:52:08 +0530 Subject: [PATCH 15/18] cleanup --- lib/services/bitcoind.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index a48afd12..2cd98d46 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2273,14 +2273,14 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { ); } else { callback(null, { - rewards: rewards, + rewards: 0, prevTxnLocktime: null, }); } }); } - async.series(functionsArray, function (err, res) { + async.parallel(functionsArray, function (err, res) { var totalReward = 0; for (let i = 0; i < res.length; i++) { From d278b6066f05729d277843e9a84b85e458a22c19 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Thu, 11 Feb 2021 11:59:27 +0530 Subject: [PATCH 16/18] cleanup --- lib/services/bitcoind.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 2cd98d46..0537e597 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2171,7 +2171,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { let transactionData = {}; async.series( [ - function (callback) { + function (callback1) { client.getRawTransaction(txid, 1, function (err, response) { if (err) { return done(self._wrapRPCError(err)); @@ -2237,16 +2237,16 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { transactionData.txid = txid; transactionData.tx = tx; - callback(null, tx); + callback1(null, tx); }); }, - function (callback) { + function (callback2) { var tx = transactionData.tx; var txid = transactionData.txid; var vins = tx.inputs; var functionsArray = []; for (let i = 0; i < vins.length; i++) { - functionsArray.push(function (callback) { + functionsArray.push(function (callback3) { var prevTxId = vins[i].prevTxId || null; var rewards = 0; if (prevTxId) { @@ -2265,14 +2265,14 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { satoshis: vins[i].satoshis, }; rewards = getKomodoRewards(rewardData); - callback(null, { + callback3(null, { rewards: rewards, prevTxnLocktime: result.locktime, }); } ); } else { - callback(null, { + callback3(null, { rewards: 0, prevTxnLocktime: null, }); @@ -2307,7 +2307,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { tx.inputSatoshis + tx.rewardClaimed * 1e8 - tx.outputSatoshis; transactionData.txid = txid; transactionData.tx = tx; - callback(null, tx); + callback2(null, tx); }); }, ], From 192053cdee8ddb943c6813b40f52b97240e43476 Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Fri, 12 Feb 2021 11:19:01 +0530 Subject: [PATCH 17/18] changes back to series to prevent rpc queue exceeded error --- lib/services/bitcoind.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 0537e597..d5f24adc 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2171,7 +2171,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { let transactionData = {}; async.series( [ - function (callback1) { + function (callback) { client.getRawTransaction(txid, 1, function (err, response) { if (err) { return done(self._wrapRPCError(err)); @@ -2237,10 +2237,10 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { transactionData.txid = txid; transactionData.tx = tx; - callback1(null, tx); + callback(null, tx); }); }, - function (callback2) { + function (callback) { var tx = transactionData.tx; var txid = transactionData.txid; var vins = tx.inputs; @@ -2265,14 +2265,14 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { satoshis: vins[i].satoshis, }; rewards = getKomodoRewards(rewardData); - callback3(null, { + callback(null, { rewards: rewards, prevTxnLocktime: result.locktime, }); } ); } else { - callback3(null, { + callback(null, { rewards: 0, prevTxnLocktime: null, }); @@ -2280,7 +2280,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { }); } - async.parallel(functionsArray, function (err, res) { + async.series(functionsArray, function (err, res) { var totalReward = 0; for (let i = 0; i < res.length; i++) { @@ -2307,12 +2307,14 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { tx.inputSatoshis + tx.rewardClaimed * 1e8 - tx.outputSatoshis; transactionData.txid = txid; transactionData.tx = tx; - callback2(null, tx); + callback(null, tx); }); }, ], function (err, results) { var tx = transactionData.tx; + var txid = transactionData.txid; + self.transactionDetailedCache.set(txid, tx); done(null, tx); } ); From d5cc7d06e6f0e548dff6e94b8e422b1935ec00ab Mon Sep 17 00:00:00 2001 From: gaeacodes Date: Fri, 12 Feb 2021 11:33:40 +0530 Subject: [PATCH 18/18] cleanup --- lib/services/bitcoind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index d5f24adc..2953ede0 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2246,7 +2246,7 @@ Bitcoin.prototype.getDetailedTransaction = function (txid, callback) { var vins = tx.inputs; var functionsArray = []; for (let i = 0; i < vins.length; i++) { - functionsArray.push(function (callback3) { + functionsArray.push(function (callback) { var prevTxId = vins[i].prevTxId || null; var rewards = 0; if (prevTxId) {