From bf7cd6726954e9b51722c43a2da946eba0ef414f Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Thu, 10 Aug 2017 17:46:27 -0400 Subject: [PATCH] Fixed address/transaction indexing. --- lib/services/address/index.js | 43 +++++++++++++----------- lib/services/header/index.js | 7 ++-- lib/services/mempool/index.js | 4 +-- lib/services/transaction/index.js | 56 +++++++++++++++++++++++++++---- lib/utils.js | 3 +- 5 files changed, 79 insertions(+), 34 deletions(-) diff --git a/lib/services/address/index.js b/lib/services/address/index.js index 27b4e28c..869443f5 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -16,7 +16,8 @@ var AddressService = function(options) { BaseService.call(this, options); this._db = this.node.services.db; this._tx = this.node.services.transaction; - this._network = this.node.getNetworkName(); + this._network = this.node.network; + this._timestamp = this.node.services.timestamp; this._p2p = this.node.services.p2p; }; @@ -26,7 +27,8 @@ AddressService.dependencies = [ 'p2p', 'db', 'block', - 'transaction' + 'transaction', + 'timestamp' ]; // ---- public function prototypes @@ -406,7 +408,6 @@ AddressService.prototype._onReorg = function(commonAncestorHeader, oldBlockList) }; AddressService.prototype.onBlock = function(block, callback) { - var self = this; if (self.node.stopping) { @@ -415,28 +416,26 @@ AddressService.prototype.onBlock = function(block, callback) { var operations = []; - block.txs.forEach(function(tx) { - operations.concat(self._processTransaction(tx, { block: block })); - }); - - if (operations && operations.length > 0) { - - self._db.batch(operations); - + for(var i = 0; i < block.txs.length; i++) { + var tx = block.txs[i]; + var ops = self._processTransaction(tx, { block: block }); + operations.push(ops); } - setImmediate(function() { - callback(null, operations); - }); + + operations = _.flatten(operations); + callback(null, operations); }; AddressService.prototype._processInput = function(tx, input, opts) { - var address = input.address; + var address = input.getAddress(); if(!address) { return; } + address.network = this._network; + address = address.toString(); var txid = tx.txid(); // address index var addressKey = this._encoding.encodeAddressIndexKey(address, opts.block.height, txid); @@ -463,22 +462,23 @@ AddressService.prototype._processInput = function(tx, input, opts) { }; AddressService.prototype._processOutput = function(tx, output, index, opts) { - - var address = output.address; + var address = output.getAddress(); if(!address) { return; } + address.network = this._network; + var address = address.toString(); var txid = tx.txid(); var addressKey = this._encoding.encodeAddressIndexKey(address, opts.block.height, txid); var utxoKey = this._encoding.encodeUtxoIndexKey(address, txid, index); var utxoValue = this._encoding.encodeUtxoIndexValue( opts.block.height, Unit.fromBTC(output.value).toSatoshis(), + this._timestamp.getTimestampSync(opts.block.rhash()), output.script.toRaw() ); - var operations = [{ type: 'put', key: addressKey @@ -490,6 +490,8 @@ AddressService.prototype._processOutput = function(tx, output, index, opts) { value: utxoValue }); + return operations; + }; AddressService.prototype._processTransaction = function(tx, opts) { @@ -505,12 +507,13 @@ AddressService.prototype._processTransaction = function(tx, opts) { outputOperations = _.flatten(_.compact(outputOperations)); var inputOperations = tx.inputs.map(function(input) { - self._processInput(tx, input, _opts); + return self._processInput(tx, input, _opts); }); inputOperations = _.flatten(_.compact(inputOperations)); - return outputOperations.concat(inputOperations); + outputOperations.concat(inputOperations); + return outputOperations; }; diff --git a/lib/services/header/index.js b/lib/services/header/index.js index 90d006f6..deb24669 100644 --- a/lib/services/header/index.js +++ b/lib/services/header/index.js @@ -193,6 +193,9 @@ HeaderService.prototype._onBlock = function(block) { } for (var i = 0; i < this.subscriptions.block.length; i++) { + var prevHeader = this._headers.get(header.prevHash); + assert(prevHeader, 'We must have a previous header in order to calculate this block\'s data.'); + block.height = prevHeader.height + 1; this.subscriptions.block[i].emit('header/block', block, header); } }; @@ -218,7 +221,7 @@ HeaderService.prototype._onHeaders = function(headers) { headerListLength = headers.length; } - var prevHeader = this._headers.get(header.prevHash); + var prevHeader = self._headers.get(header.prevHash); assert(prevHeader, 'We must have a previous header in order to calculate this header\'s data.'); header.height = prevHeader.height + 1; @@ -429,8 +432,6 @@ HeaderService.prototype._getPersistedHeaders = function(callback) { var tipHeader = self._headers.getIndex(self._tip.height); self._tip.hash = tipHeader.hash; - self._lastChainwork = tipHeader.chainwork; - self._db.batch(removalOps, callback); }); diff --git a/lib/services/mempool/index.js b/lib/services/mempool/index.js index 6162fd2a..46d4c6ad 100644 --- a/lib/services/mempool/index.js +++ b/lib/services/mempool/index.js @@ -119,9 +119,7 @@ MempoolService.prototype.onBlock = function(block, callback) { key: self._encoding.encodeMempoolTransactionKey(tx.txid()) }; }); - setImmediate(function() { - callback(null, ops); - }); + callback(null, ops); }; MempoolService.prototype._onTransaction = function(tx) { diff --git a/lib/services/transaction/index.js b/lib/services/transaction/index.js index 7c96b8fe..5bbee3ca 100644 --- a/lib/services/transaction/index.js +++ b/lib/services/transaction/index.js @@ -45,14 +45,13 @@ TransactionService.prototype.getDetailedTransaction = function(txid, options, ca this.getTransaction(txid, options, callback); }; -TransactionService.prototype.getTransaction = function(txid, options, callback) { - +TransactionService.prototype._getTransaction = function(txid, options, callback) { var self = this; var _tx; var queryMempool = _.isUndefined(options.queryMempool) ? true : options.queryMempool; - var key = self.encoding.encodeTransactionKey(txid); + var key = self._encoding.encodeTransactionKey(txid); self._db.get(key, function(err, tx) { @@ -69,6 +68,7 @@ TransactionService.prototype.getTransaction = function(txid, options, callback) } if (memTx) { + memTx = self._encoding.decodeTransactionValue(memTx); memTx.confirmations = 0; _tx = memTx; } @@ -78,7 +78,9 @@ TransactionService.prototype.getTransaction = function(txid, options, callback) } else { if (tx) { + tx = self._encoding.decodeTransactionValue(tx); tx.confirmations = self._p2p.getBestHeight - tx.__height; + tx.blockHash = self._header.get(tx.__height).hash; _tx = tx; } @@ -88,8 +90,49 @@ TransactionService.prototype.getTransaction = function(txid, options, callback) return callback(); } - // TODO: this could cause crazy amounts of recursion if input values are missing from the entire chain of txs - self._addMissingInputValues(_tx, options, callback); + var outputSatoshis = 0; + _tx.outputs.forEach(function(output) { + outputSatoshis += output.value; + }); + _tx.outputs.forEach(function(output) { + outputSatoshis += output.value; + }); + _tx.outputSatoshis = outputSatoshis; + if (!_tx.inputs[0].isCoinbase()) { + var inputSatoshis = 0; + _tx.__inputValues.forEach(function(val) { + if (val >- 0) { + inputSatoshis += val; + } + }); + var feeSatoshis = inputSatoshis - outputSatoshis; + _tx.inputSatosbis = inputSatoshis; + _tx.feeSatosbis = feeSatoshis; + } + callback(null, _tx); + }); + +}; + +TransactionService.prototype.getTransaction = function(txid, options, callback) { + + var self = this; + + if (typeof callback !== 'function') { + callback = options; + } + + self._getTransaction(txid, options, function(err, tx) { + + if (err) { + return callback(err); + } + + if (!tx) { + return callback(); + } + + self._addMissingInputValues(tx, options, callback); }); @@ -109,7 +152,7 @@ TransactionService.prototype._addMissingInputValues = function(tx, options, call } var outputIndex = input.prevout.index; - self.getTransaction(input.prevout.txid(), options, function(err, _tx) { + self._getTransaction(input.prevout.txid(), options, function(err, _tx) { if (err || !_tx) { return next(err || new Error('tx not found for tx id: ' + input.prevout.txid())); @@ -122,7 +165,6 @@ TransactionService.prototype._addMissingInputValues = function(tx, options, call }); - }, function(err) { if (err) { diff --git a/lib/utils.js b/lib/utils.js index 6a3ea229..0e2d60d5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -81,11 +81,12 @@ utils.SimpleMap = function SimpleMap() { }; this.set = function (key, value, pos) { - object[key] = array.length; if (pos >= 0) { + object[key] = pos; array[pos] = value; } else { + object[key] = array.length; array.push(value); }