From 2282d231bd6a18749a3bd62831842613cf9ae386 Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Wed, 25 Nov 2015 23:37:30 +0100 Subject: [PATCH 01/18] add block height to transaction response --- lib/transactions.js | 1 + test/addresses.js | 1 + test/transactions.js | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/lib/transactions.js b/lib/transactions.js index afffef222..4b5672220 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -92,6 +92,7 @@ TxController.prototype.transformTransaction = function(transaction, callback) { transformed.vout = vout; transformed.blockhash = transaction.__blockHash; + transformed.blockheight = transaction.__height; transformed.confirmations = confirmations; var time = transaction.__timestamp ? transaction.__timestamp : Math.round(Date.now() / 1000); transformed.time = time; diff --git a/test/addresses.js b/test/addresses.js index d86682d58..03e6c5953 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -455,6 +455,7 @@ describe('Addresses', function() { } ], "blockhash": "0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013", + "blockheight": 534181, "confirmations": 52, "time": 1441116143, "blocktime": 1441116143, diff --git a/test/transactions.js b/test/transactions.js index 07d82d5c2..93dd51a68 100644 --- a/test/transactions.js +++ b/test/transactions.js @@ -80,6 +80,7 @@ describe('Transactions', function() { } ], "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, "confirmations": 230, "time": 1440987503, "blocktime": 1440987503, @@ -213,6 +214,7 @@ describe('Transactions', function() { var blockHex = '07000020a491892cca9f143f7f00b8d65bbce0204bb32e17e914325fa5010000000000003e28f0519ecf01f7f01ea8da61084b2e4741a18ce1f3738117b84458353764b06fb9e35567f20c1a78eb626f0301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac000000000100000002ad5a14ae9d0f3221b790c4fc590fddceea1456e5692d8c4bf1ff7175f2b0c987000000008b4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff9621ac65bc22ea593ca9a61a8d63e461bf3d3f277989df5d3bd33ddfae0aa1d8000000008a4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307ffffffff02dc374401000000001976a9144b7b335f978f130269fe661423258ae9642df8a188ac72b3d000000000001976a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac000000000100000002060d3cb6dfb7ffe85e2908010fea63190c9707e96fc7448128eb895b5e222771030000006b483045022100f67cffc0ae23adb236ff3edb4a9736e277605db30cc7708dfab8cf1e1483bbce022052396aa5d664ec1cb65992c423fd9a17e94dc7af328d2d559e90746dd195ca5901210346134da14907581d8190d3980caaf46d95e4eb9c1ca8e70f1fc6007fefb1909dfeffffff7b2d8a8263cffbdb722e2a5c74166e6f2258634e277c0b08f51b578b667e2fba000000006a473044022077222a91cda23af69179377c62d84a176fb12caff6c5cbf6ae9e5957ff3b1afe0220768edead76819228dcba18cca3c9a5a5d4c32919720f21df21a297ba375bbe5c012103371ea5a4dfe356b3ea4042a537d7ab7ee0faabd43e21b6cc076fda2240629eeefeffffff02209a1d00000000001976a9148e451eec7ca0a1764b4ab119274efdd2727b3c8588ac40420f00000000001976a914d0fce8f064cd1059a6a11501dd66fe42368572b088accb250800'; var blockIndex = { "hash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, "chainWork": "0000000000000000000000000000000000000000000000054626b1839ade284a", "prevHash": "00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4", "height": 533974 @@ -295,6 +297,7 @@ describe('Transactions', function() { } ], "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, "confirmations": 236, "time": 1440987503, "blocktime": 1440987503, @@ -368,6 +371,7 @@ describe('Transactions', function() { } ], "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, "confirmations": 236, "time": 1440987503, "blocktime": 1440987503, @@ -445,6 +449,7 @@ describe('Transactions', function() { } ], "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, "confirmations": 236, "time": 1440987503, "blocktime": 1440987503, @@ -700,6 +705,7 @@ describe('Transactions', function() { } ], "blockhash": "00000000000001001aba15de213648f370607fb048288dd27b96f7e833a73520", + "blockheight": 534105, "confirmations": 119, "time": 1441068774, "blocktime": 1441068774, @@ -763,6 +769,7 @@ describe('Transactions', function() { } ], "blockhash": "0000000000000a3acc1f7fe72917eb48bb319ed96c125a6dfcc0ba6acab3c4d0", + "blockheight": 534110, "confirmations": 114, "time": 1441072817, "blocktime": 1441072817, From 4049bb69174f3e93f8a569668f6386bd50b4ed56 Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Thu, 10 Dec 2015 13:18:20 +0100 Subject: [PATCH 02/18] add batch util function --- lib/common.js | 27 ++++++++++++++++++++++++ test/common.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 test/common.js diff --git a/lib/common.js b/lib/common.js index d7fb9af67..3a4775d70 100644 --- a/lib/common.js +++ b/lib/common.js @@ -1,5 +1,7 @@ 'use strict'; +var async = require('async'); + exports.notReady = function (err, res, p) { res.status(503).send('Server not yet ready. Sync Percentage:' + p); }; @@ -17,3 +19,28 @@ exports.handleErrors = function (err, res) { res.status(404).send('Not found'); } }; + +/** + * batch + * + * @param handler + * @param outkey + * @returns {Function} + */ +exports.batch = function(handler, outkey) { + return function(req, res, next, inputdata) { + async.mapSeries(inputdata.split(','), async.ensureAsync(handler), function(err, results) { + if (err) { + return exports.handleErrors(err, res); + } + + if (results.length === 1) { + req[outkey] = results[0] + } else { + req[outkey] = results; + } + + return next(); + }); + }; +}; diff --git a/test/common.js b/test/common.js new file mode 100644 index 000000000..1d3dd0844 --- /dev/null +++ b/test/common.js @@ -0,0 +1,56 @@ +var common = require('../lib/common'); +var should = require('should'); +var sinon = require('sinon'); + +describe('common', function() { + function invokeHandle(index, value, handler, err, result) { + var callback; + + handler.args[index][0].should.equal(value); + callback = handler.args[index][1]; + callback(err, result); + } + + describe('batch', function() { + var handler; + var next; + var outkey; + var req; + var res; + + beforeEach(function() { + handler = sinon.stub(); + next = sinon.spy(); + outkey = 'qwerty'; + req = {}; + res = {}; + }); + + it('should single input data', function() { + common.batch(handler, outkey)(req, res, next, '123'); + + handler.callCount.should.equal(1); + invokeHandle(0, '123', handler, null, 'r123'); + handler.callCount.should.equal(1); + + should(req).have.property(outkey, 'r123'); + }); + + it('should multi input data', function() { + common.batch(handler, outkey)(req, res, next, '0,1,2'); + + handler.callCount.should.equal(1); + invokeHandle(0, '0', handler, null, 'r0'); + handler.callCount.should.equal(2); + invokeHandle(1, '1', handler, null, 'r1'); + handler.callCount.should.equal(3); + invokeHandle(2, '2', handler, null, 'r2'); + handler.callCount.should.equal(3); + + should(req).have.property(outkey).with.lengthOf(3); + req[outkey][0].should.equal('r0'); + req[outkey][1].should.equal('r1'); + req[outkey][2].should.equal('r2'); + }); + }); +}); From a45d227bfcfda991a810a3e35dbef36928261458 Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Thu, 10 Dec 2015 16:38:39 +0100 Subject: [PATCH 03/18] add TravisCI badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f300fc63..9ca57a1cd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Insight API +# Insight API [![Build Status](https://travis-ci.org/CoinSpace/insight-api.svg)](https://travis-ci.org/CoinSpace/insight-api) A Bitcoin blockchain REST and web socket API service for [Bitcore Node](https://github.com/bitpay/bitcore-node). From fbbe1f5386c47f8df2aaf7146ca8e1633c65b923 Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Thu, 10 Dec 2015 16:41:27 +0100 Subject: [PATCH 04/18] add me as contributor --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index b5c2b9a57..6b668ae0b 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,10 @@ { "name": "Braydon Fuller", "email": "braydon@bitpay.com" + }, + { + "name": "Eugene Krevenets", + "email": "ievgenii.krevenets@gmail.com" } ], "bugs": { From 9482929720718235a54f8ec298f9833dba1b0f93 Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Thu, 10 Dec 2015 22:21:15 +0100 Subject: [PATCH 05/18] batch /block/:id1,:id2,...,idn request --- lib/blocks.js | 13 ++++++------- lib/common.js | 6 +++++- test/blocks.js | 46 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 11806bda1..1f1ea75d7 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -1,10 +1,11 @@ 'use strict'; -var common = require('./common'); var async = require('async'); +var batch = require('./common').batch; var bitcore = require('bitcore-lib'); -var pools = require('../pools.json'); var BN = bitcore.crypto.BN; +var common = require('./common'); +var pools = require('../pools.json'); function BlockController(node) { var self = this; @@ -26,9 +27,8 @@ var BLOCK_LIMIT = 200; /** * Find block by hash ... */ -BlockController.prototype.block = function(req, res, next, hash) { +BlockController.prototype.block = batch(function(hash, callback) { var self = this; - this.node.getBlock(hash, function(err, block) { if(err && err.message === 'Block not found.') { // TODO libbitcoind should pass an instance of errors.Block.NotFound @@ -40,10 +40,9 @@ BlockController.prototype.block = function(req, res, next, hash) { var info = self.node.services.bitcoind.getBlockIndex(hash); info.isMainChain = self.node.services.bitcoind.isMainChain(hash); - req.block = self.transformBlock(block, info); - next(); + callback(null, self.transformBlock(block, info)); }); -}; +}, 'block'); BlockController.prototype.transformBlock = function(block, info) { var blockObj = block.toObject(); diff --git a/lib/common.js b/lib/common.js index 3a4775d70..a96f538a3 100644 --- a/lib/common.js +++ b/lib/common.js @@ -29,7 +29,11 @@ exports.handleErrors = function (err, res) { */ exports.batch = function(handler, outkey) { return function(req, res, next, inputdata) { - async.mapSeries(inputdata.split(','), async.ensureAsync(handler), function(err, results) { + var self = this; + + async.mapSeries(inputdata.split(','), async.ensureAsync(function() { + return handler.apply(self, arguments); + }), function(err, results) { if (err) { return exports.handleErrors(err, res); } diff --git a/test/blocks.js b/test/blocks.js index eea891c2d..fe5f2ecc5 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -69,6 +69,7 @@ describe('Blocks', function() { var bitcoreBlock = bitcore.Block.fromBuffer(new Buffer(blocks['0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'], 'hex')); var node = { + name: 'node1', getBlock: sinon.stub().callsArgWith(1, null, bitcoreBlock), services: { bitcoind: { @@ -103,6 +104,7 @@ describe('Blocks', function() { it('block pool info should be correct', function(done) { var block = bitcore.Block.fromString(blocks['000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4']); var node = { + name: 'node2', getBlock: sinon.stub().callsArgWith(1, null, block), services: { bitcoind: { @@ -122,7 +124,10 @@ describe('Blocks', function() { var res = {}; var next = function() { should.exist(req.block); - var block = req.block; + should.exist(req.block.poolInfo); + should.exist(req.block.poolInfo.poolName); + should.exist(req.block.poolInfo.url); + req.block.poolInfo.poolName.should.equal('Discus Fish'); req.block.poolInfo.url.should.equal('http://f2pool.com/'); done(); @@ -133,6 +138,45 @@ describe('Blocks', function() { controller.block(req, res, next, hash); }); + it('should return combined result on batch request', function(done) { + var stub = sinon.stub(); + stub.onFirstCall().callsArgWith(1, null, bitcore.Block.fromBuffer(blocks['000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7'], 'hex')); + stub.onSecondCall().callsArgWith(1, null, bitcore.Block.fromBuffer(blocks['00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441'], 'hex')) + var req = {}; + + var node = { + getBlock: stub, + services: { + bitcoind: { + getNextBlockHash: sinon.stub().returns('000000000001e866a8057cde0c650796cb8a59e0e6038dc31c69d7ca6649627d'), + getBlockIndex: sinon.stub().returns(blockIndexes['000000000000000004a118407a4e3556ae2d5e882017e7ce526659d8073f13a4']), + isMainChain: sinon.stub().returns(true) + }, + db: { + tip: { + __height: 534092 + } + } + } + }; + + var controller = new BlockController(node); + + controller.block(req, {}, function(data) { + console.log('data'); + console.log(data); + should.exist(req.block); + req.block.should.be.instanceof(Array).and.have.lengthOf(2); + should.exist(req.block[0].hash); + req.block[0].hash.should.be.equal('000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7'); + should.exist(req.block[1].hash); + req.block[1].hash.should.be.equal('00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441'); + done(); + }, [ + '000000000008fbb2e358e382a6f6948b2da24563bba183af447e6e2542e8efc7', + '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441' + ].join(',')); + }); }); describe('/blocks route', function() { From 2fe0057a183169fa8057a0a64d8ee89064881fbc Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Fri, 11 Dec 2015 15:42:50 +0100 Subject: [PATCH 06/18] batch /addrs/:id1,...,idn request --- lib/addresses.js | 21 ++++++++-- lib/index.js | 1 + test/addresses.js | 97 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 3 deletions(-) diff --git a/lib/addresses.js b/lib/addresses.js index 765faab84..95b4a401b 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -24,6 +24,23 @@ AddressController.prototype.show = function(req, res) { }); }; +AddressController.prototype.multishow = function(req, res) { + var options = { + noTxList: parseInt(req.query.noTxList) + }; + + var self = this; + + async.map(req.addrs.split(','), function(addr, callback) { + self.getAddressSummary(addr, options, callback); + }, function(err, datas) { + if(err) { + return common.handleErrors(err, res); + } + res.jsonp(datas); + }); +}; + AddressController.prototype.balance = function(req, res) { this.addressSummarySubQuery(req, res, 'balanceSat'); }; @@ -51,8 +68,6 @@ AddressController.prototype.addressSummarySubQuery = function(req, res, param) { }; AddressController.prototype.getAddressSummary = function(address, options, callback) { - var self = this; - this.node.getAddressSummary(address, options, function(err, summary) { if(err) { return callback(err); @@ -90,7 +105,7 @@ AddressController.prototype.checkAddrs = function(req, res, next) { } this.check(req, res, next, req.addrs); -} +}; AddressController.prototype.check = function(req, res, next, addresses) { if(!addresses.length || !addresses[0]) { diff --git a/lib/index.js b/lib/index.js index 66c88ddfd..2d24c310a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -118,6 +118,7 @@ InsightAPI.prototype.setupRoutes = function(app) { // Address routes var addresses = new AddressController(this.node); app.get('/addr/:addr', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.show.bind(addresses)); + app.get('/addrs/:addrs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multishow.bind(addresses)); app.get('/addr/:addr/utxo', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.utxo.bind(addresses)); app.get('/addrs/:addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses)); app.post('/addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses)); diff --git a/test/addresses.js b/test/addresses.js index 03e6c5953..2c4ba17ed 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -274,6 +274,103 @@ describe('Addresses', function() { }); }); + describe('/addrs/:addrs', function() { + var addresses; + var node; + var req; + var summaries; + + beforeEach(function() { + var stub = sinon.stub(); + + summaries = [{ + balance: 0, + totalReceived: 2782729129, + totalSpent: 2782729129, + unconfirmedBalance: 0, + appearances: 2, + unconfirmedAppearances: 0, + txids: [ + 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3' + ] + }, { + balance: 0, + totalReceived: 2782729129, + totalSpent: 2782729129, + unconfirmedBalance: 0, + appearances: 2, + unconfirmedAppearances: 0, + txids: [ + 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3' + ] + }]; + + stub + .onFirstCall() + .callsArgWith(2, null, summaries[0]); + stub + .onSecondCall() + .callsArgWith(2, null, summaries[1]); + + node = { + getAddressSummary: stub + }; + + addresses = new AddressController(node); + + req = { + addrs: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK,moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', + query: {} + }; + }); + + it('should have correct data', function(done) { + addresses.multishow(req, { + jsonp: function(data) { + should(data).eql([ + { + addrStr: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', + balance: 0, + balanceSat: 0, + totalReceived: 27.82729129, + totalReceivedSat: 2782729129, + totalSent: 27.82729129, + totalSentSat: 2782729129, + unconfirmedBalance: 0, + unconfirmedBalanceSat: 0, + unconfirmedTxApperances: 0, + txApperances: 2, + transactions: [ + 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3' + ] + }, + { + addrStr: 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', + balance: 0, + balanceSat: 0, + totalReceived: 27.82729129, + totalReceivedSat: 2782729129, + totalSent: 27.82729129, + totalSentSat: 2782729129, + unconfirmedBalance: 0, + unconfirmedBalanceSat: 0, + unconfirmedTxApperances: 0, + txApperances: 2, + transactions: [ + 'bb0ec3b96209fac9529570ea6f83a86af2cceedde4aaf2bfcc4796680d23f1c7', + '01f700df84c466f2a389440e5eeacdc47d04f380c39e5d19dce2ce91a11ecba3' + ] + } + ]); + done(); + } + }); + }); + }); + describe('/addr/:addr/utxo', function() { it('should have correct data', function(done) { var insight = [ From 000cf26915d3c88744ea41295bf309df5b9835aa Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Fri, 11 Dec 2015 18:48:18 +0100 Subject: [PATCH 07/18] batch /rawtxs/:txid1,...,txidn request --- lib/index.js | 2 ++ lib/transactions.js | 29 ++++++++++++++++++++++++++--- test/transactions.js | 31 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 2d24c310a..41643be87 100644 --- a/lib/index.js +++ b/lib/index.js @@ -114,6 +114,8 @@ InsightAPI.prototype.setupRoutes = function(app) { // Raw Routes app.get('/rawtx/:txid', this.cacheLong(), transactions.showRaw.bind(transactions)); app.param('txid', transactions.rawTransaction.bind(transactions)); + app.get('/rawtxs/:txids', this.cacheLong(), transactions.showRaw.bind(transactions)); + app.param('txids', transactions.multiRawTransaction.bind(transactions)); // Address routes var addresses = new AddressController(this.node); diff --git a/lib/transactions.js b/lib/transactions.js index e348d258a..c80876af0 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -1,10 +1,11 @@ 'use strict'; +var async = require('async'); var bitcore = require('bitcore-lib'); -var _ = bitcore.deps._; -var $ = bitcore.util.preconditions; var common = require('./common'); -var async = require('async'); + +var $ = bitcore.util.preconditions; +var _ = bitcore.deps._; function TxController(node) { this.node = node; @@ -244,6 +245,28 @@ TxController.prototype.rawTransaction = function(req, res, next, txid) { }); }; +TxController.prototype.multiRawTransaction = function(req, res, next, txids) { + var self = this; + + async.map(txids.split(','), function(txid, callback) { + self.node.getTransaction(txid, true, callback); + }, function(err, txs) { + if (err && err instanceof self.node.errors.Transaction.NotFound) { + return common.handleErrors(null, res); + } else if(err) { + return common.handleErrors(err, res); + } + + req.rawTransaction = { + 'rawtx': txs.map(function(tx) { + return tx.toBuffer().toString('hex'); + }) + }; + + next(); + }); +}; + TxController.prototype.showRaw = function(req, res) { if (req.rawTransaction) { res.jsonp(req.rawTransaction); diff --git a/test/transactions.js b/test/transactions.js index 771648675..30c4a4335 100644 --- a/test/transactions.js +++ b/test/transactions.js @@ -861,6 +861,37 @@ describe('Transactions', function() { }); }); + describe('/rawtxs/:txids', function() { + it('should give the correct data', function(done) { + var hexes = [ + '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac00000000', + '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac00000000' + ]; + + var stub = sinon.stub(); + + stub + .onFirstCall() + .callsArgWith(2, null, bitcore.Transaction().fromBuffer(new Buffer(hexes[0], 'hex'))); + stub + .onSecondCall() + .callsArgWith(2, null, bitcore.Transaction().fromBuffer(new Buffer(hexes[1], 'hex'))); + + var req = {}; + var transactions = new TxController({ + getTransaction: stub + }); + + transactions.multiRawTransaction(req, {}, function() { + should(req.rawTransaction.rawtx).eql(hexes); + done(); + }, [ + '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd', + 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0' + ].join(',')); + }); + }); + describe('#transformInvTransaction', function() { it('should give the correct data', function() { var insight = { From c16254427244cd0c42e07c8e6b33388836227df9 Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Fri, 11 Dec 2015 18:55:44 +0100 Subject: [PATCH 08/18] add doc about multiple block request --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 4f300fc63..42935bc1f 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,11 @@ Caching support has not yet been added in the v0.3 upgrade. /insight-api/block/00000000a967199a2fad0877433c93df785a8d8ce062e5f9b451cd1397bdbf62 ``` +#### Multiple blocks +``` + /insight-api/block/[:hash1],[:hash2],...,[:hash,] +``` + ### Block Index Get block hash by height ``` From f48de1f4ab8f2199fc3fa7724948e2a3f41150e6 Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Fri, 11 Dec 2015 19:07:31 +0100 Subject: [PATCH 09/18] add doc about multiple addresses request --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 42935bc1f..c353a7f98 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,12 @@ which is the hash of the Genesis block (0 height) /insight-api/addr/mmvP3mTe53qxHdPqXEvdu8WdC7GfQ2vmx5?noTxList=1 ``` +### Multiple Addresses +``` + /insight-api/addrs/[:addr1],[:addr2],...,[:addrn][?noTxList=1&noCache=1] + +``` + ### Address Properties ``` /insight-api/addr/[:addr]/balance From 941495db5b612f965b4a93681f5a35c0b5f8f62d Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Fri, 11 Dec 2015 19:08:27 +0100 Subject: [PATCH 10/18] add doc about multiple transactions request --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index c353a7f98..6c0e9242d 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,11 @@ which is the hash of the Genesis block (0 height) /insight-api/rawtx/525de308971eabd941b139f46c7198b5af9479325c2395db7f2fb5ae8562556c ``` +### Multiple Transactions +``` + /insight-api/rawtxs/[:rawid1],[:rawid2],...,[:rawidn] +``` + ### Address ``` /insight-api/addr/[:addr][?noTxList=1&noCache=1] From aaf41adf8428a5b61cf519290db9f8d90e7bb2a4 Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Fri, 11 Dec 2015 23:15:18 +0100 Subject: [PATCH 11/18] batch /txs/:txid1,...,txidn request --- README.md | 1 + lib/index.js | 2 + lib/transactions.js | 36 +++++++ test/transactions.js | 235 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+) diff --git a/README.md b/README.md index 6c0e9242d..8e848fe58 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ which is the hash of the Genesis block (0 height) ### Multiple Transactions ``` + /insight-api/txs/[:rawid1],[:rawid2],...,[:rawidn] /insight-api/rawtxs/[:rawid1],[:rawid2],...,[:rawidn] ``` diff --git a/lib/index.js b/lib/index.js index 41643be87..ec8393e34 100644 --- a/lib/index.js +++ b/lib/index.js @@ -108,6 +108,8 @@ InsightAPI.prototype.setupRoutes = function(app) { var transactions = new TxController(this.node); app.get('/tx/:txid', this.cacheLong(), transactions.show.bind(transactions)); app.param('txid', transactions.transaction.bind(transactions)); + app.get('/txs/:txids', this.cacheShort(), transactions.show.bind(transactions)); + app.param('txids', transactions.multitransactions.bind(transactions)); app.get('/txs', this.cacheShort(), transactions.list.bind(transactions)); app.post('/tx/send', transactions.send.bind(transactions)); diff --git a/lib/transactions.js b/lib/transactions.js index c80876af0..097f108eb 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -49,6 +49,42 @@ TxController.prototype.transaction = function(req, res, next, txid) { }); }; +TxController.prototype.multitransactions = function(req, res, next, txids) { + var self = this; + + async.map(txids.split(','), function(txid, callback) { + self.node.getTransactionWithBlockInfo(txid, true, function(err, transaction) { + if (err) { + return callback(err); + } + + transaction.populateInputs(self.node.services.db, [], function(err) { + if (err) { + return callback(err); + } + + self.transformTransaction(transaction, function(err, transformedTransaction) { + if (err) { + return callback(err); + } + + callback(null, transformedTransaction); + }); + }); + }); + }, function(err, txs) { + if (err && err instanceof self.node.errors.Transaction.NotFound) { + return common.handleErrors(null, res); + } else if(err) { + return common.handleErrors(err, res); + } + + req.transaction = txs; + next(); + }); +}; + + TxController.prototype.transformTransaction = function(transaction, callback) { $.checkArgument(_.isFunction(callback)); var self = this; diff --git a/test/transactions.js b/test/transactions.js index 30c4a4335..c1ea31899 100644 --- a/test/transactions.js +++ b/test/transactions.js @@ -532,6 +532,241 @@ describe('Transactions', function() { transactions.list(req, res); }); + + it('should give the correct data', function(done) { + var insight = [ + { + "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, + "blocktime": 1440987503, + "confirmations": 230, + "fees": 0.0003, + "locktime": 0, + "size": 437, + "time": 1440987503, + "txid": "b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0", + "valueIn": 0.3495539, + "valueOut": 0.3492539, + "version": 1, + "vin": [ + { + "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", + "doubleSpentTxID": null, + "n": 0, + "scriptSig": { + "asm": "30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "hex": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + }, + "sequence": 4294967295, + "txid": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", + "value": 0.18535505, + "valueSat": 18535505, + "vout": 0 + }, + { + "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", + "doubleSpentTxID": null, + "n": 1, + "scriptSig": { + "asm": "30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "hex": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + }, + "sequence": 4294967295, + "txid": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", + "value": 0.16419885, + "valueSat": 16419885, + "vout": 0 + } + ], + "vout": [ + { + "n": 0, + "scriptPubKey": { + "addresses": [ + "mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X" + ], + "asm": "OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac", + "type": "pubkeyhash" + }, + "value": "0.21247964" + }, + { + "n": 1, + "scriptPubKey": { + "addresses": [ + "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f" + ], + "asm": "OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac", + "type": "pubkeyhash" + }, + "spentIndex": 1, + "spentTxId": "614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec", + "value": "0.13677426" + } + ] + }, + { + "blockhash": "0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7", + "blockheight": 533974, + "blocktime": 1440987503, + "confirmations": 230, + "fees": 0.0003, + "locktime": 0, + "size": 437, + "time": 1440987503, + "txid": "b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0", + "valueIn": 0.3495539, + "valueOut": 0.3492539, + "version": 1, + "vin": [ + { + "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", + "doubleSpentTxID": null, + "n": 0, + "scriptSig": { + "asm": "30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "hex": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + }, + "sequence": 4294967295, + "txid": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", + "value": 0.18535505, + "valueSat": 18535505, + "vout": 0 + }, + { + "addr": "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f", + "doubleSpentTxID": null, + "n": 1, + "scriptSig": { + "asm": "30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "hex": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307" + }, + "sequence": 4294967295, + "txid": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", + "value": 0.16419885, + "valueSat": 16419885, + "vout": 0 + } + ], + "vout": [ + { + "n": 0, + "scriptPubKey": { + "addresses": [ + "mnQ4ZaGessNgdxmWPxbTHcfx4b8R6eUr1X" + ], + "asm": "OP_DUP OP_HASH160 4b7b335f978f130269fe661423258ae9642df8a1 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac", + "type": "pubkeyhash" + }, + "value": "0.21247964" + }, + { + "n": 1, + "scriptPubKey": { + "addresses": [ + "mqdofsXHpePPGBFXuwwypAqCcXi48Xhb2f" + ], + "asm": "OP_DUP OP_HASH160 6efcf883b4b6f9997be9a0600f6c095fe2bd2d92 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac", + "type": "pubkeyhash" + }, + "spentIndex": 1, + "spentTxId": "614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec", + "value": "0.13677426" + } + ] + } + ]; + + var bitcoreTxObj = { + "hash": "b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0", + "version": 1, + "inputs": [ + { + "prevTxId": "87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad", + "outputIndex": 0, + "sequenceNumber": 4294967295, + "script": "4830450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "scriptString": "72 0x30450221008e5df62719cd92d7b137d00bbd27f153f2909bcad3a300960bc1020ec6d5e961022039df51600ff4fb5da5a794d1648c6b47c1f7d277fd5877fb5e52a730a3595f8c01 65 0x04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "output": { + "satoshis": 18535505, + "script": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac" + } + }, + { + "prevTxId": "d8a10aaedf3dd33b5ddf8979273f3dbf61e4638d1aa6a93c59ea22bc65ac2196", + "outputIndex": 0, + "sequenceNumber": 4294967295, + "script": "4730440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb31014104eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "scriptString": "71 0x30440220761464d7bab9515d92260762a97af82a9b25d202d8f7197b1aaec81b6fed541f022059f99606de6b06e17b2cd102dceb3807ebdd9e777a5b77c9a0b3672f5eabcb3101 65 0x04eb1e0ccd9afcac42229348dd776e991c69551ae3474340fada12e787e51758397e1d3afdba360d6374261125ea3b6ea079a5f202c150dfd729e1062d9176a307", + "output": { + "satoshis": 16419885, + "script": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac" + } + } + ], + "outputs": [ + { + "satoshis": 21247964, + "script": "76a9144b7b335f978f130269fe661423258ae9642df8a188ac" + }, + { + "satoshis": 13677426, + "script": "76a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288ac" + } + ], + "nLockTime": 0 + }; + + var spentTxId = '614fe1708825f9c21732394e4784cc6808ac1d8b939736bfdead970567561eec'; + var spentIndex = 1; + + var bitcoreTx = bitcore.Transaction(bitcoreTxObj); + bitcoreTx.__blockHash = '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7'; + bitcoreTx.__height = 533974; + bitcoreTx.__timestamp = 1440987503; + bitcoreTx.populateInputs = sinon.stub().callsArg(2); + bitcoreTx.toObject = sinon.stub().returns(bitcoreTxObj); + + var transactions = new TxController({ + getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, bitcoreTx), + services: { + db: { + tip: { + __height: 534203 + } + }, + address: { + getInputForOutput: function(txid, outputIndex, options, callback) { + var data = false; + if (txid === 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0' && + outputIndex === 1) { + data = { + inputTxId: spentTxId, + inputIndex: spentIndex + } + } + setImmediate(function() { + callback(null, data); + }); + } + } + }, + network: 'testnet' + }); + + var req = {}; + + transactions.multitransactions(req, {}, function() { + should.exist(insight); + req.transaction.should.eql(insight); + done(); + }, 'b85334bf2df35c6dd5b294efe92ffc793a78edff75a2ca666fc296ffb04bbba0,87c9b0f27571fff14b8c2d69e55614eacedd0f59fcc490b721320f9dae145aad'); + }); + it('by address', function(done) { var txinfos = [ From a380ee1f8ed99e0f459b257641e9c44cb54e45db Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Mon, 14 Dec 2015 15:32:54 +0100 Subject: [PATCH 12/18] handle error on block request --- lib/blocks.js | 4 ++-- package.json | 1 + test/blocks.js | 35 ++++++++++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 1f1ea75d7..114e72fc8 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -32,9 +32,9 @@ BlockController.prototype.block = batch(function(hash, callback) { this.node.getBlock(hash, function(err, block) { if(err && err.message === 'Block not found.') { // TODO libbitcoind should pass an instance of errors.Block.NotFound - return common.handleErrors(null, res); + return common.handleErrors(null, block); } else if(err) { - return common.handleErrors(err, res); + return common.handleErrors(err, block); } var info = self.node.services.bitcoind.getBlockIndex(hash); diff --git a/package.json b/package.json index b5c2b9a57..240e2bf1e 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "chai": "*", "mocha": "~1.16.2", "proxyquire": "^1.7.2", + "rewire": "^2.5.1", "should": "^2.1.1", "sinon": "^1.10.3" } diff --git a/test/blocks.js b/test/blocks.js index fe5f2ecc5..bf79159e5 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -1,10 +1,13 @@ 'use strict'; -var should = require('should'); -var sinon = require('sinon'); +var _ = require('lodash'); var BlockController = require('../lib/blocks'); var bitcore = require('bitcore-lib'); -var _ = require('lodash'); +var sinon = require('sinon'); +var should = require('should'); +var rewire = require('rewire'); + +var RewiredBlockController = rewire('../lib/blocks'); var blocks = require('./data/blocks.json'); @@ -177,6 +180,32 @@ describe('Blocks', function() { '00000000000006bd8fe9e53780323c0e85719eca771022e1eb6d10c62195c441' ].join(',')); }); + + it('should graceful fail on error', function() { + var error = { + message: 'some error' + }; + + var controller = new RewiredBlockController({ + getBlock: sinon.stub().callsArgWith(1, error, 'block data') + }); + + var handleErrors = sinon.spy(); + + RewiredBlockController.__set__('common', { + handleErrors: handleErrors + }); + + controller.block({}, {}, function(data) { + assert(false, 'should not call next middleware on fail'); + }, ''); + + + handleErrors.callCount.should.equal(1); + handleErrors.callCount.should.equal(1); + handleErrors.args[0][0].should.equal(error); + handleErrors.args[0][1].should.equal('block data'); + }); }); describe('/blocks route', function() { From ff2dade6484183f7fc253fc9fd8adf31ef021a47 Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Mon, 14 Dec 2015 16:21:10 +0100 Subject: [PATCH 13/18] handle error on block request more --- lib/blocks.js | 7 ++----- test/blocks.js | 34 ++++++++++++++++------------------ 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 114e72fc8..6501e1332 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -30,11 +30,8 @@ var BLOCK_LIMIT = 200; BlockController.prototype.block = batch(function(hash, callback) { var self = this; this.node.getBlock(hash, function(err, block) { - if(err && err.message === 'Block not found.') { - // TODO libbitcoind should pass an instance of errors.Block.NotFound - return common.handleErrors(null, block); - } else if(err) { - return common.handleErrors(err, block); + if (err) { + return callback(err); } var info = self.node.services.bitcoind.getBlockIndex(hash); diff --git a/test/blocks.js b/test/blocks.js index bf79159e5..84cd37b78 100644 --- a/test/blocks.js +++ b/test/blocks.js @@ -5,9 +5,6 @@ var BlockController = require('../lib/blocks'); var bitcore = require('bitcore-lib'); var sinon = require('sinon'); var should = require('should'); -var rewire = require('rewire'); - -var RewiredBlockController = rewire('../lib/blocks'); var blocks = require('./data/blocks.json'); @@ -181,30 +178,31 @@ describe('Blocks', function() { ].join(',')); }); - it('should graceful fail on error', function() { + it('should graceful fail on error', function(done) { var error = { - message: 'some error' + code: 123, + message: 'some error' }; - var controller = new RewiredBlockController({ - getBlock: sinon.stub().callsArgWith(1, error, 'block data') + var controller = new BlockController({ + getBlock: sinon.stub().callsArgWith(1, error) }); - var handleErrors = sinon.spy(); - - RewiredBlockController.__set__('common', { - handleErrors: handleErrors - }); + var res = { + status: sinon.stub().returns({ + send: sinon.spy() + }) + }; - controller.block({}, {}, function(data) { + controller.block({}, res, function() { assert(false, 'should not call next middleware on fail'); }, ''); - - handleErrors.callCount.should.equal(1); - handleErrors.callCount.should.equal(1); - handleErrors.args[0][0].should.equal(error); - handleErrors.args[0][1].should.equal('block data'); + setTimeout(function() { + res.status.callCount.should.equal(1); + res.status.args[0][0].should.equal(400); + done(); + }); }); }); From e5fd19f99c2cbac8445fd9892a500a91194fba8a Mon Sep 17 00:00:00 2001 From: Samuel Reed Date: Thu, 17 Dec 2015 16:13:52 -0600 Subject: [PATCH 14/18] Don't split req.addrs, it's already split in checkAddrs --- lib/addresses.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/addresses.js b/lib/addresses.js index 95b4a401b..24783ff1e 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -31,7 +31,7 @@ AddressController.prototype.multishow = function(req, res) { var self = this; - async.map(req.addrs.split(','), function(addr, callback) { + async.map(req.addrs, function(addr, callback) { self.getAddressSummary(addr, options, callback); }, function(err, datas) { if(err) { From 6af2a32d59cd6e5a0aefb0e6b0a8c8be0a31eb74 Mon Sep 17 00:00:00 2001 From: Samuel Reed Date: Thu, 17 Dec 2015 16:43:51 -0600 Subject: [PATCH 15/18] Fix 'res' incorrectly referenced in batch callback --- lib/blocks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/blocks.js b/lib/blocks.js index 1f1ea75d7..3831f6b36 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -32,9 +32,9 @@ BlockController.prototype.block = batch(function(hash, callback) { this.node.getBlock(hash, function(err, block) { if(err && err.message === 'Block not found.') { // TODO libbitcoind should pass an instance of errors.Block.NotFound - return common.handleErrors(null, res); + return callback(null); } else if(err) { - return common.handleErrors(err, res); + return callback(err); } var info = self.node.services.bitcoind.getBlockIndex(hash); From 691a2f007fc12068ad4be3670e7f4491fb8db00f Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Fri, 18 Dec 2015 15:43:47 +0100 Subject: [PATCH 16/18] add log to transaction send --- lib/transactions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/transactions.js b/lib/transactions.js index 097f108eb..d7b1ad3fe 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -396,6 +396,8 @@ TxController.prototype.list = function(req, res) { }; TxController.prototype.send = function(req, res) { + console.log('TxController.prototype.send', res, res); + console.log('req.body', req.body); this.node.sendTransaction(req.body.rawtx, function(err, txid) { if(err) { // TODO handle specific errors From 5d0691eb1085e6db1334606fad50363e4ec65e8c Mon Sep 17 00:00:00 2001 From: Eugene Krevenets Date: Fri, 18 Dec 2015 18:17:02 +0100 Subject: [PATCH 17/18] remove logs --- lib/transactions.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/transactions.js b/lib/transactions.js index d7b1ad3fe..097f108eb 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -396,8 +396,6 @@ TxController.prototype.list = function(req, res) { }; TxController.prototype.send = function(req, res) { - console.log('TxController.prototype.send', res, res); - console.log('req.body', req.body); this.node.sendTransaction(req.body.rawtx, function(err, txid) { if(err) { // TODO handle specific errors From 4c27f342c096beaec467266c3d6c33d0fc559287 Mon Sep 17 00:00:00 2001 From: Samuel Reed Date: Fri, 18 Dec 2015 11:30:29 -0600 Subject: [PATCH 18/18] Fix /addrs/:addrs test. --- test/addresses.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/addresses.js b/test/addresses.js index 2c4ba17ed..d526d7f51 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -321,7 +321,7 @@ describe('Addresses', function() { addresses = new AddressController(node); req = { - addrs: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK,moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', + addrs: ['mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK','moZY18rGNmh4YCPeugtGW46AkkWMQttBUD'], query: {} }; });