diff --git a/api/controllers/blocks.js b/api/controllers/blocks.js index 8eafd3ea..a1ed647e 100644 --- a/api/controllers/blocks.js +++ b/api/controllers/blocks.js @@ -30,6 +30,9 @@ Blocks.blockHashParam = function(req, res, next, blockHash) { .then(next) .catch(BitcoreNode.errors.Blocks.NotFound, function() { res.status(404).send('Block with id ' + blockHash + ' not found'); + }) + .catch(function() { + console.log(arguments); }); }; @@ -45,6 +48,9 @@ Blocks.heightParam = function(req, res, next, height) { .then(next) .catch(BitcoreNode.errors.Blocks.NotFound, function() { res.status(404).send('Block with height ' + height + ' not found'); + }) + .catch(function() { + console.log(arguments); }); }; @@ -68,17 +74,38 @@ Blocks.list = function(req, res) { var offset = parseInt(req.query.offset || 0); var limit = parseInt(req.query.limit || 10); + if (from < 0) { + res.status(422); + res.send('/v1/blocks/ "from" must be valid block height (a positive integer)'); + return; + } + if (to < 0) { + res.status(422); + res.send('/v1/blocks/ "to" must be valid block height (a positive integer)'); + return; + } + if (offset < 0) { + res.status(422); + res.send('/v1/blocks/ "offset" must be a positive integer'); + return; + } + if (limit < 0) { + res.status(422); + res.send('/v1/blocks/ "limit" must be a positive integer'); + return; + } if (to < from) { res.status(422); res.send('/v1/blocks/ "to" must be >= "from"'); return; } - // TODO: add more parameter validation // TODO: return block_summary instead of block_full node.blockService.listBlocks(from, to, offset, limit) .then(function(blocks) { - res.send(blocks); + res.send(blocks.map(function(b) { + return b.toObject(); + })); }); }; @@ -91,7 +118,7 @@ Blocks.getLatest = function(req, res) { }; Blocks.get = function(req, res) { - $.checkState(req.block instanceof Block); + $.checkState(req.block instanceof Block, JSON.stringify(req.block)); res.send(req.block.toObject()); }; diff --git a/api/controllers/transactions.js b/api/controllers/transactions.js index 2dd73599..5bf4244f 100644 --- a/api/controllers/transactions.js +++ b/api/controllers/transactions.js @@ -32,6 +32,9 @@ Transactions.txHashParam = function(req, res, next, txHash) { .then(next) .catch(BitcoreNode.errors.Transactions.NotFound, function() { res.status(404).send('Transaction with id ' + txHash + ' not found'); + }) + .catch(function() { + console.log(arguments); }); }; diff --git a/api/test/app.js b/api/test/app.js index b0443d8e..2551e032 100644 --- a/api/test/app.js +++ b/api/test/app.js @@ -1,7 +1,20 @@ 'use strict'; var BitcoreHTTP = require('../lib/http'); +var bitcore = require('bitcore'); +var _app = null; module.exports = function(nodeMock) { - return process.env.INTEGRATION === 'true' ? BitcoreHTTP.create().app : new BitcoreHTTP(nodeMock).app; + if (process.env.INTEGRATION === 'true') { + if (_app) { + return _app; + } + var config = require('config'); + var network = config.get('BitcoreHTTP.BitcoreNode').network; + console.log('Starting test suite', network, 'network'); + bitcore.Networks.defaultNetwork = bitcore.Networks.get(network); + _app = BitcoreHTTP.create(config.get('BitcoreHTTP')).app; + return _app; + } + return new BitcoreHTTP(nodeMock).app; }; diff --git a/api/test/mocha.opts b/api/test/mocha.opts new file mode 100644 index 00000000..19d98572 --- /dev/null +++ b/api/test/mocha.opts @@ -0,0 +1,2 @@ +--recursive +-R spec diff --git a/api/test/v1/blocks.js b/api/test/v1/blocks.js index 18a541f0..863de1e9 100644 --- a/api/test/v1/blocks.js +++ b/api/test/v1/blocks.js @@ -53,17 +53,22 @@ describe('BitcoreHTTP v1 blocks routes', function() { var start = from - 1e5; var end = to - 1e5; var section = blockList.slice(start, end); - return Promise.resolve(section.slice(offset, offset + limit)); + var ret = section.slice(offset, offset + limit); + return Promise.resolve(ret); }; app = require('../app')(nodeMock); agent = request(app); }); + var toObject = function(b) { + return b.toObject(); + }; + describe('/blocks', function() { it('works with default parameters', function(cb) { - agent.get('/v1/blocks/') + agent.get('/v1/blocks/?from=100000') .expect(200) - .expect(JSON.stringify(blockList), cb); + .expect(blockList.map(toObject), cb); }); it('fails with to end) { - return; + if (height >= end) { + return Promise.resolve(); } - console.log('fetching block', height); return self.getBlockByHeight(height) .then(function(block) { - blocks.push(block.toObject()); + blocks.push(block); return fetchBlock(height + 1); }) .catch(function(err) { - console.log(err); + // block not found, ignore }); }; return fetchBlock(start) diff --git a/lib/services/transaction.js b/lib/services/transaction.js index e4987d76..d042a28c 100644 --- a/lib/services/transaction.js +++ b/lib/services/transaction.js @@ -20,6 +20,7 @@ var LevelUp = require('levelup'); var Promise = require('bluebird'); var bitcore = require('bitcore'); var config = require('config'); +var BitcoreNode = require('../../'); var _ = bitcore.deps._; var $ = bitcore.util.preconditions; @@ -53,7 +54,7 @@ var Index = { output: 'txo-', // txo-- -> serialized Output spent: 'txs-', // txo---- -> block height of confirmation for spend address: 'txa-', // txa-
-- -> Output - addressSpent: 'txas-', + addressSpent: 'txas-', // txa-
-- -> { // heightSpent: number, (may be -1 for unconfirmed tx) // spentTx: string, spentTxInputIndex: number, spendInput: Input @@ -84,10 +85,14 @@ function TransactionService(opts) { } TransactionService.Index = Index; -TransactionService.transactionRPCtoBitcore = function(rpcResponse) { - if (rpcResponse.error) { - throw new bitcore.Error(rpcResponse.error); +var txNotFound = function(error) { + if (error.message === 'No information available about transaction') { + throw new BitcoreNode.errors.Transactions.NotFound(); } + throw error; +}; + +TransactionService.transactionRPCtoBitcore = function(rpcResponse) { return new bitcore.Transaction(rpcResponse.result); }; @@ -99,10 +104,12 @@ TransactionService.prototype.getTransaction = function(transactionId) { } return Promise.try(function() { - return self.rpc.getRawTransactionAsync(transactionId); - }).then(function(rawTransaction) { - return TransactionService.transactionRPCtoBitcore(rawTransaction); - }); + return self.rpc.getRawTransactionAsync(transactionId); + }) + .catch(txNotFound) + .then(function(rawTransaction) { + return TransactionService.transactionRPCtoBitcore(rawTransaction); + }); }; TransactionService.prototype._confirmOutput = function(ops, block, transaction) { diff --git a/package.json b/package.json index 915775c0..b302e0b5 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,8 @@ "dependencies": { "async": "0.9.0", "bitcoind-rpc": "^0.2.1", - "bitcore": "bitpay/bitcore", - "bitcore-p2p": "^0.13.0", + "bitcore": "^0.12.0", + "bitcore-p2p": "^0.15.0", "bluebird": "^2.9.12", "body-parser": "^1.12.0", "bufferput": "bitpay/node-bufferput", diff --git a/test/networkmonitor.js b/test/networkmonitor.js index 3674eff9..f7ed4e6f 100644 --- a/test/networkmonitor.js +++ b/test/networkmonitor.js @@ -67,7 +67,6 @@ describe('NetworkMonitor', function() { it('broadcasts errors in underlying peer', function(cb) { var nm = new NetworkMonitor(busMock, peerMock); nm.on('error', function() { - console.log('under'); cb(); }); nm.start(); diff --git a/test/services/block.js b/test/services/block.js index a329113b..58f28141 100644 --- a/test/services/block.js +++ b/test/services/block.js @@ -80,7 +80,7 @@ describe('BlockService', function() { describe('block confirmation', function() { - var mockRpc, transactionMock, database, blockService, writeLock; + var mockRpc, transactionMock, database, blockService; var thenCaller = { then: function(arg) { @@ -118,7 +118,7 @@ describe('BlockService', function() { var expectedOps = [{ type: 'put', key: 'header-000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f', - value: '{"version":1,"prevHash":"0000000000000000000000000000000000000000000000000000000000000000","merkleRoot":"3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a","time":1231006505,"bits":486604799,"nonce":2083236893}' + value: '{"version":1,"prevHash":"0000000000000000000000000000000000000000000000000000000000000000","merkleRoot":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b","time":1231006505,"bits":486604799,"nonce":2083236893}' }, { type: 'put', key: 'nxt-0000000000000000000000000000000000000000000000000000000000000000', @@ -149,10 +149,10 @@ describe('BlockService', function() { it('makes the expected calls when confirming the block #170', function(callback) { database.batchAsync = function(ops) { - ops.should.deep.equal([{ + var eops = [{ type: 'put', key: 'header-00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee', - value: '{"version":1,"prevHash":"55bd840a78798ad0da853f68974f3d183e2bd1db6a842c1feecf222a00000000","merkleRoot":"ff104ccb05421ab93e63f8c3ce5c2c2e9dbb37de2764b3a3175c8166562cac7d","time":1231731025,"bits":486604799,"nonce":1889418792}' + value: '{"version":1,"prevHash":"000000002a22cfee1f2c846adbd12b3e183d4f97683f85dad08a79780a84bd55","merkleRoot":"7dac2c5666815c17a3b36427de37bb9d2e2c5ccec3f8633eb91a4205cb4c10ff","time":1231731025,"bits":486604799,"nonce":1889418792}' }, { type: 'put', key: 'nxt-000000002a22cfee1f2c846adbd12b3e183d4f97683f85dad08a79780a84bd55', @@ -173,7 +173,8 @@ describe('BlockService', function() { type: 'put', key: 'tip', value: block170.id - }]); + }]; + ops.should.deep.equal(eops); return callback(); }; blockService.writeLock.onFirstCall().returns(thenCaller); diff --git a/test/services/transaction.js b/test/services/transaction.js index 4994ad3a..f8b9c723 100644 --- a/test/services/transaction.js +++ b/test/services/transaction.js @@ -107,40 +107,23 @@ describe('TransactionService', function() { } }); service._confirmTransaction(ops, block170, block170.transactions[1]).then(function() { - ops.map(function(k) { - if (bitcore.util.js.isValidJSON(k.value)) { - k.value = JSON.parse(k.value); - } - return k; - }).should.deep.equal([{ + ops.should.deep.equal([{ type: 'put', key: 'btx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16', value: '00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee' }, { type: 'put', key: 'txo-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-0', - value: { - satoshis: 1000000000, - script: '65 0x04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_CHECKSIG' - } + value: '{"satoshis":1000000000,"script":"65 0x04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_CHECKSIG"}' }, { type: 'put', key: 'txo-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-1', - value: { - satoshis: 4000000000, - script: '65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 OP_CHECKSIG' - } + value: '{"satoshis":4000000000,"script":"65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 OP_CHECKSIG"}' }, { type: 'put', key: 'txo-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-0', - value: { - prevTxId: '0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9', - outputIndex: 0, - sequenceNumber: 4294967295, - script: '71 0x304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901', - heightConfirmed: 170 - } - }, ]); + value: '{"prevTxId":"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9","outputIndex":0,"sequenceNumber":4294967295,"script":"47304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901","scriptString":"71 0x304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901","heightConfirmed":170}' + }]); /* TODO: This should work if address spent is accepted for public key. Add test for P2PKH if not accepted * { type: 'put', key: 'txas-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16-0',