diff --git a/lib/services/address/index.js b/lib/services/address/index.js index 1e6aa797..37636422 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -11,7 +11,6 @@ var _ = bitcore.deps._; var Encoding = require('./encoding'); var Transform = require('stream').Transform; var assert = require('assert'); -var Stream = require('stream'); var utils = require('../../utils'); var AddressService = function(options) { @@ -373,17 +372,34 @@ AddressService.prototype._getAddressHistory = function(address, options, callbac async.waterfall([ + // query the mempool for relevant txs for this address function(next) { if (!options.queryMempool) { - return next(); + return next(null, []); } - self._mempool.getTxidsByAddress(address, next); + self._mempool.getTxsByAddress(address, next); }, + // add the meta data such as input values, etc. + function(mempoolTxs, next) { + + if (mempoolTxs.length <= 0) { + return next(); + } + async.mapSeries(mempoolTxs, function(tx, next) { + self._transaction.setTxMetaInfo(tx, options, next); + }, function(err, txs) { + if (err) { + return next(err); + } + options.results = txs; + next(); + }); + }, // stream the rest of the confirmed txids out of the address index - function(mempoolTxids, next) { + function(next) { var txStream = self._getTxStream(address, options); @@ -395,20 +411,6 @@ AddressService.prototype._getAddressHistory = function(address, options, callbac log.error('Address Service: txstream err: ' + err); txStream.unpipe(); }); - - if (mempoolTxids.length > 0) { - - var mempoolTxidStream = new Stream.Readable({ objectMode: true }); - - mempoolTxidStream.pipe(txStream); - - mempoolTxids.forEach(function(txid) { - mempoolTxidStream.push(txid); - }); - - mempoolTxidStream.push(null); - } - var txidStream = self._getTxidStream(address, options); txidStream.pipe(txStream); } diff --git a/lib/services/mempool/index.js b/lib/services/mempool/index.js index d2efdba6..3188405a 100644 --- a/lib/services/mempool/index.js +++ b/lib/services/mempool/index.js @@ -138,7 +138,7 @@ MempoolService.prototype.getMempoolTransaction = function(txid, callback) { }; // TODO optimize this using another index? -MempoolService.prototype.getTxidsByAddress = function(address, callback) { +MempoolService.prototype.getTxsByAddress = function(address, callback) { var self = this; var results = []; @@ -162,9 +162,9 @@ MempoolService.prototype.getTxidsByAddress = function(address, callback) { stream.on('data', function(data) { var tx = self._encoding.decodeMempoolTransactionValue(data.value); - var txid = self._involvesAddress(tx, address); - if (txid) { - results.push(txid); + tx = self._involvesAddress(tx, address); + if (tx) { + results.push(tx); } }); @@ -193,7 +193,7 @@ MempoolService.prototype._involvesAddress = function(tx, address) { for(var i = 0; i < collections.length; i++) { var hasAddress = contains(collections[i], this._network); if (hasAddress) { - return tx.txid(); + return tx; } } diff --git a/lib/services/transaction/index.js b/lib/services/transaction/index.js index bae7753f..97d9d1bf 100644 --- a/lib/services/transaction/index.js +++ b/lib/services/transaction/index.js @@ -42,7 +42,8 @@ TransactionService.prototype.getAPIMethods = function() { return [ ['getRawTransaction', this, this.getRawTransaction, 1], ['getTransaction', this, this.getTransaction, 1], - ['getDetailedTransaction', this, this.getDetailedTransaction, 1] + ['getDetailedTransaction', this, this.getDetailedTransaction, 1], + ['setTxMetaInfo', this, this.setTxMetaInfo, 2] ]; }; @@ -119,7 +120,7 @@ TransactionService.prototype.getTransaction = function(txid, options, callback) self._getTransaction.bind(self, txid, options), self._getSupplementaryTransactionInfo.bind(self), self._getMempoolTransaction.bind(self), - self._setMetaInfo.bind(self) + self.setTxMetaInfo.bind(self) ], callback); }; @@ -151,42 +152,75 @@ TransactionService.prototype._getSupplementaryTransactionInfo = function(txid, t }); }; -TransactionService.prototype._setMetaInfo = function(tx, options, callback) { +TransactionService.prototype.setTxMetaInfo = function(tx, options, callback) { + + var self = this; if (!tx) { return callback(); } - - // output values - var outputSatoshis = 0; - - tx.outputs.forEach(function(output) { - outputSatoshis += output.value; - }); - - tx.outputSatoshis = outputSatoshis; - - - //input values - if (!tx.inputs[0].isCoinbase()) { - - var inputSatoshis = 0; - - tx.__inputValues.forEach(function(val) { - - if (val >+ 0) { - inputSatoshis += val; + async.waterfall([ + function(next) { + if (tx.__inputValues) { + return next(null, tx); } - }); + // the tx's that contain these input values could, themselves be unconfirmed + // we are also assuming that this tx is from thet mempool + self._getInputValues(tx, options, function(err, inputValues) { - var feeSatoshis = inputSatoshis - outputSatoshis; - tx.inputSatoshis = inputSatoshis; - tx.feeSatoshis = feeSatoshis; + if (err) { + return callback(err); + } - } + tx.__inputValues = inputValues; + tx.confirmations = 0; + tx.blockHash = null; + tx.__blockHash = null; + next(null, tx); - callback(null, tx); + }); + }, + function(tx, next) { + + // output values + var outputSatoshis = 0; + + tx.outputs.forEach(function(output) { + outputSatoshis += output.value; + }); + + tx.outputSatoshis = outputSatoshis; + + //input values + if (!tx.inputs[0].isCoinbase()) { + + var inputSatoshis = 0; + + assert(tx.__inputValues.length === tx.inputs.length, + 'Transaction Service: input values length is not the same as the number of inputs.'); + + tx.__inputValues.forEach(function(val) { + + if (val >+ 0) { + inputSatoshis += val; + } + }); + + var feeSatoshis = inputSatoshis - outputSatoshis; + tx.inputSatoshis = inputSatoshis; + tx.feeSatoshis = feeSatoshis; + + } + + next(null, tx); + } + ], function(err, tx) { + if (err) { + return callback(err); + } + callback(null, tx); + }); }; @@ -209,21 +243,7 @@ TransactionService.prototype._getMempoolTransaction = function(txid, tx, options return callback(null, tx, options); } - // the tx's that contain these input values could, themselves be unconfirmed - self._getInputValues(tx, options, function(err, inputValues) { - - if (err) { - return callback(err); - } - - tx.__inputValues = inputValues; - tx.confirmations = 0; - tx.blockHash = null; - tx.__blockHash = null; - callback(null, tx, options); - - }); - + callback(null, tx, options); }); }; diff --git a/package-lock.json b/package-lock.json index 2d845114..540c0e31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bitcore-node", - "version": "5.0.0-beta.15", + "version": "5.0.0-beta.16", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4266,14 +4266,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "requires": { - "safe-buffer": "5.1.1" - } - }, "string-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", @@ -4293,6 +4285,14 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/package.json b/package.json index df926461..28521d43 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "node": ">=8.0.0" }, "author": "BitPay ", - "version": "5.0.0-beta.15", + "version": "5.0.0-beta.16", "main": "./index.js", "repository": "git://github.com/bitpay/bitcore-node.git", "homepage": "https://github.com/bitpay/bitcore-node", diff --git a/test/services/address/index.unit.js b/test/services/address/index.unit.js index d013f7ed..f98d49a7 100644 --- a/test/services/address/index.unit.js +++ b/test/services/address/index.unit.js @@ -81,8 +81,8 @@ describe('Address Service', function() { var getHeaderHash = sandbox.stub().callsArgWith(1, null, 'aa'); var getBlockHeader = sandbox.stub().callsArgWith(1, null, 'aa'); - var getTxidsByAddress = sandbox.stub().callsArgWith(1, null, []); - addressService._mempool = { getTxidsByAddress: getTxidsByAddress }; + var getTxsByAddress = sandbox.stub().callsArgWith(1, null, []); + addressService._mempool = { getTxsByAddress: getTxsByAddress }; addressService._header = { getHeaderHash: getHeaderHash, @@ -108,7 +108,7 @@ describe('Address Service', function() { if (err) { return done(err); } - expect(getTxidsByAddress.calledOnce).to.be.true; + expect(getTxsByAddress.calledOnce).to.be.true; expect(getTransaction.calledOnce).to.be.true; expect(res).to.deep.equal([ { diff --git a/test/services/transaction/index.unit.js b/test/services/transaction/index.unit.js index 98bd1d5e..850a7e96 100644 --- a/test/services/transaction/index.unit.js +++ b/test/services/transaction/index.unit.js @@ -111,4 +111,21 @@ describe('Transaction Service', function() { }); }); + + describe('#setMetaTxInfo', function() { + it('should set the appropriate meta data on a tx.', function(done) { + sandbox.stub(txService, '_getInputValues').callsArgWith(2, null, [2]); + var tx = { outputs: [ { value: 1 } ], inputs: [ { value: 2, isCoinbase: sinon.stub().returns(false) } ] }; + + txService.setTxMetaInfo(tx, {}, function(err, _tx) { + if (err) { + return done(err); + } + _tx.__inputValues.should.deep.equal([2]); + _tx.confirmations.should.equal(0); + _tx.inputSatoshis.should.equal(2); + done(); + }); + }); + }); });