diff --git a/.gitignore b/.gitignore index 48655ce2..d72450d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules/ node_modules/* +coverage/* out/ out/* build/ diff --git a/integration/regtest-node.js b/integration/regtest-node.js index 1a661a1b..4fcbafa4 100644 --- a/integration/regtest-node.js +++ b/integration/regtest-node.js @@ -278,8 +278,9 @@ describe('Node Functionality', function() { if (err) { throw err; } - results.length.should.equal(1); - var info = results[0]; + var items = results.items; + items.length.should.equal(1); + var info = items[0]; should.exist(info.addresses[address]); info.addresses[address].outputIndexes.length.should.equal(1); info.addresses[address].outputIndexes[0].should.be.within(0, 1); @@ -419,10 +420,12 @@ describe('Node Functionality', function() { address6 ]; var options = {}; - node.services.address.getAddressHistory(addresses, options, function(err, history) { + node.services.address.getAddressHistory(addresses, options, function(err, results) { if (err) { throw err; } + results.totalCount.should.equal(4); + var history = results.items; history.length.should.equal(4); history[0].height.should.equal(157); history[0].confirmations.should.equal(1); @@ -450,10 +453,12 @@ describe('Node Functionality', function() { start: 157, end: 156 }; - node.services.address.getAddressHistory(addresses, options, function(err, history) { + node.services.address.getAddressHistory(addresses, options, function(err, results) { if (err) { throw err; } + results.totalCount.should.equal(2); + var history = results.items; history.length.should.equal(2); history[0].height.should.equal(157); history[0].confirmations.should.equal(1); @@ -475,10 +480,12 @@ describe('Node Functionality', function() { start: 155, end: 154 }; - node.services.address.getAddressHistory(addresses, options, function(err, history) { + node.services.address.getAddressHistory(addresses, options, function(err, results) { if (err) { throw err; } + results.totalCount.should.equal(2); + var history = results.items; history.length.should.equal(2); history[0].height.should.equal(155); history[1].height.should.equal(154); @@ -498,10 +505,12 @@ describe('Node Functionality', function() { from: 0, to: 3 }; - node.services.address.getAddressHistory(addresses, options, function(err, history) { + node.services.address.getAddressHistory(addresses, options, function(err, results) { if (err) { throw err; } + results.totalCount.should.equal(4); + var history = results.items; history.length.should.equal(3); history[0].height.should.equal(157); history[0].confirmations.should.equal(1); @@ -516,10 +525,12 @@ describe('Node Functionality', function() { address ]; var options = {}; - node.services.address.getAddressHistory(addresses, options, function(err, history) { + node.services.address.getAddressHistory(addresses, options, function(err, results) { if (err) { throw err; } + results.totalCount.should.equal(6); + var history = results.items; history.length.should.equal(6); history[0].height.should.equal(157); history[0].addresses[address].inputIndexes.should.deep.equal([0, 1]); @@ -543,11 +554,11 @@ describe('Node Functionality', function() { address ]; var options = {}; - node.services.address.getAddressHistoryCount(addresses, options, function(err, count) { + node.services.address.getAddressHistory(addresses, options, function(err, results) { if (err) { throw err; } - count.should.equal(6); + results.totalCount.should.equal(6); done(); }); }); @@ -558,10 +569,11 @@ describe('Node Functionality', function() { from: 0, to: 1 }; - node.services.address.getAddressHistory(address, options, function(err, history) { + node.services.address.getAddressHistory(address, options, function(err, results) { if (err) { throw err; } + var history = results.items; history.length.should.equal(1); history[0].height.should.equal(157); done(); @@ -572,10 +584,11 @@ describe('Node Functionality', function() { from: 1, to: 2 }; - node.services.address.getAddressHistory(address, options, function(err, history) { + node.services.address.getAddressHistory(address, options, function(err, results) { if (err) { throw err; } + var history = results.items; history.length.should.equal(1); history[0].height.should.equal(156); done(); @@ -586,10 +599,11 @@ describe('Node Functionality', function() { from: 2, to: 3 }; - node.services.address.getAddressHistory(address, options, function(err, history) { + node.services.address.getAddressHistory(address, options, function(err, results) { if (err) { throw err; } + var history = results.items; history.length.should.equal(1); history[0].height.should.equal(155); done(); @@ -600,10 +614,11 @@ describe('Node Functionality', function() { from: 3, to: 4 }; - node.services.address.getAddressHistory(address, options, function(err, history) { + node.services.address.getAddressHistory(address, options, function(err, results) { if (err) { throw err; } + var history = results.items; history.length.should.equal(1); history[0].height.should.equal(154); done(); @@ -614,10 +629,11 @@ describe('Node Functionality', function() { from: 4, to: 5 }; - node.services.address.getAddressHistory(address, options, function(err, history) { + node.services.address.getAddressHistory(address, options, function(err, results) { if (err) { throw err; } + var history = results.items; history.length.should.equal(1); history[0].height.should.equal(153); history[0].satoshis.should.equal(-10000); @@ -631,10 +647,11 @@ describe('Node Functionality', function() { from: 5, to: 6 }; - node.services.address.getAddressHistory(address, options, function(err, history) { + node.services.address.getAddressHistory(address, options, function(err, results) { if (err) { throw err; } + var history = results.items; history.length.should.equal(1); history[0].height.should.equal(150); history[0].satoshis.should.equal(10 * 1e8); diff --git a/lib/services/address/history.js b/lib/services/address/history.js index a74e69ce..8ab47338 100644 --- a/lib/services/address/history.js +++ b/lib/services/address/history.js @@ -27,27 +27,9 @@ function AddressHistory(args) { AddressHistory.MAX_ADDRESS_QUERIES = 20; -AddressHistory.prototype.getCount = function(callback) { - var self = this; - - async.eachLimit( - self.addresses, - AddressHistory.MAX_ADDRESS_QUERIES, - function(address, next) { - self.getTransactionInfo(address, next); - }, - function(err) { - if (err) { - return callback(err); - } - self.combineTransactionInfo(); - callback(null, self.combinedArray.length); - } - ); -}; - AddressHistory.prototype.get = function(callback) { var self = this; + var totalCount; // TODO check for mempool inputs and outputs by a group of addresses, currently // each address individually loops through the mempool and does not check input scripts. @@ -64,6 +46,7 @@ AddressHistory.prototype.get = function(callback) { } self.combineTransactionInfo(); + totalCount = Number(self.combinedArray.length); self.sortAndPaginateCombinedArray(); async.eachSeries( @@ -75,7 +58,10 @@ AddressHistory.prototype.get = function(callback) { if (err) { return callback(err); } - callback(null, self.detailedArray); + callback(null, { + totalCount: totalCount, + items: self.detailedArray + }); } ); } diff --git a/lib/services/address/index.js b/lib/services/address/index.js index dbf944ce..07fc750a 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -48,8 +48,7 @@ AddressService.prototype.getAPIMethods = function() { ['getOutputs', this, this.getOutputs, 2], ['getUnspentOutputs', this, this.getUnspentOutputs, 2], ['isSpent', this, this.isSpent, 2], - ['getAddressHistory', this, this.getAddressHistory, 2], - ['getAddressHistoryCount', this, this.getAddressHistoryCount, 2] + ['getAddressHistory', this, this.getAddressHistory, 2] ]; }; @@ -732,28 +731,30 @@ AddressService.prototype.isSpent = function(output, queryMempool, callback) { }); }; -/** - * This will give the total count of transactions for a single or several addresses - * limited by a range of block heights. - * @param {Array} addresses - An array of addresses - * @param {Object} options - The options to limit the query - * @param {Number} [options.start] - The beginning block height (e.g. 1500 the most recent block height). - * @param {Number} [options.end] - The ending block height (e.g. 0 the older block height, results are inclusive). - * @param {Boolean} [options.queryMempool] - Include the mempool in the query - * @param {Function} callback - */ -AddressService.prototype.getAddressHistoryCount = function(addresses, options, callback) { - var history = new AddressHistory({ - node: this.node, - options: options, - addresses: addresses - }); - history.getCount(callback); -}; - /** * This will give the history for many addresses limited by a range of block heights (to limit * the database lookup times) and/or paginated to limit the results length. + * + * The response format will be: + * { + * totalCount: 12 // the total number of items there are between the two heights + * items: [ + * { + * addresses: { + * '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX': { + * inputIndexes: [], + * outputIndexes: [0] + * } + * }, + * satoshis: 100, + * height: 300000, + * confirmations: 1, + * timestamp: 1442337090 // in seconds + * fees: 1000 // in satoshis + * tx: + * } + * ] + * } * @param {Array} addresses - An array of addresses * @param {Object} options - The options to limit the query * @param {Number} [options.from] - The pagination "from" index diff --git a/test/services/address/history.unit.js b/test/services/address/history.unit.js index 608081e9..8092a2f0 100644 --- a/test/services/address/history.unit.js +++ b/test/services/address/history.unit.js @@ -37,43 +37,6 @@ describe('Address Service History', function() { }); }); - describe('#getCount', function() { - it('will complete the async each limit series', function(done) { - var addresses = [address]; - var history = new AddressHistory({ - node: {}, - options: {}, - addresses: addresses - }); - history.getTransactionInfo = sinon.stub().callsArg(1); - history.combineTransactionInfo = sinon.stub(); - history.get(function(err, results) { - if (err) { - throw err; - } - history.getTransactionInfo.callCount.should.equal(1); - history.combineTransactionInfo.callCount.should.equal(1); - done(); - }); - }); - it('handle an error from getTransactionInfo', function(done) { - var addresses = [address]; - var history = new AddressHistory({ - node: {}, - options: {}, - addresses: addresses - }); - var expected = [{}]; - history.sortedArray = expected; - history.transactionInfo = [{}]; - history.getTransactionInfo = sinon.stub().callsArgWith(1, new Error('test')); - history.get(function(err) { - err.message.should.equal('test'); - done(); - }); - }); - }); - describe('#get', function() { it('will complete the async each limit series', function(done) { var addresses = [address]; @@ -98,7 +61,10 @@ describe('Address Service History', function() { history.getDetailedInfo.callCount.should.equal(1); history.combineTransactionInfo.callCount.should.equal(1); history.sortAndPaginateCombinedArray.callCount.should.equal(1); - results.should.equal(expected); + results.should.deep.equal({ + totalCount: 1, + items: expected + }); done(); }); }); diff --git a/test/services/address/index.unit.js b/test/services/address/index.unit.js index f8f8a65c..4aac31b5 100644 --- a/test/services/address/index.unit.js +++ b/test/services/address/index.unit.js @@ -29,7 +29,7 @@ describe('Address Service', function() { it('should return the correct methods', function() { var am = new AddressService({node: mocknode}); var methods = am.getAPIMethods(); - methods.length.should.equal(6); + methods.length.should.equal(5); }); }); @@ -857,25 +857,6 @@ describe('Address Service', function() { }); }); - describe('#getAddressHistoryCount', function() { - it('will call getCount on address history instance', function(done) { - function TestAddressHistory(args) { - args.node.should.equal(mocknode); - args.addresses.should.deep.equal([]); - args.options.should.deep.equal({}); - } - TestAddressHistory.prototype.getCount = sinon.stub().callsArg(0); - var TestAddressService = proxyquire('../../../lib/services/address', { - './history': TestAddressHistory - }); - var am = new TestAddressService({node: mocknode}); - am.getAddressHistoryCount([], {}, function(err, history) { - TestAddressHistory.prototype.getCount.callCount.should.equal(1); - done(); - }); - }); - }); - describe('#getAddressHistory', function() { it('will call get on address history instance', function(done) { function TestAddressHistory(args) {