Merge pull request #39 from maraoz/complete/api
Completes all API endpoints, 100% coverage :)
This commit is contained in:
commit
eac49ad929
@ -32,11 +32,35 @@ Addresses.addressParam = function(req, res, next, address) {
|
|||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse address list
|
||||||
|
*/
|
||||||
|
Addresses.addressesParam = function(req, res, next, addresses) {
|
||||||
|
var addrList = addresses.split(',');
|
||||||
|
var allAddressesValid = _.every(addrList, function(addr) {
|
||||||
|
return Address.isValid(addr);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!allAddressesValid) {
|
||||||
|
res.status(422);
|
||||||
|
res.send('/v1/addresses/ parameter must be a bitcoin address list');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
req.addresses = addrList.map(function (a) {
|
||||||
|
return new Address(a);
|
||||||
|
});
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* controllers
|
* controllers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an address information
|
||||||
|
*/
|
||||||
Addresses.get = function(req, res) {
|
Addresses.get = function(req, res) {
|
||||||
$.checkState(req.address instanceof Address);
|
$.checkState(req.address instanceof Address);
|
||||||
node.getAddressInfo(req.address)
|
node.getAddressInfo(req.address)
|
||||||
@ -45,4 +69,17 @@ Addresses.get = function(req, res) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an address utxos
|
||||||
|
*/
|
||||||
|
Addresses.utxos = function(req, res) {
|
||||||
|
$.checkState(_.all(req.addresses, function(addr) {
|
||||||
|
return addr instanceof Address;
|
||||||
|
}));
|
||||||
|
node.getUTXOs(req.addresses)
|
||||||
|
.then(function(utxos) {
|
||||||
|
res.send(utxos);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = Addresses;
|
module.exports = Addresses;
|
||||||
|
|||||||
@ -35,6 +35,15 @@ Transactions.txHashParam = function(req, res, next, txHash) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sets an input or output index
|
||||||
|
*/
|
||||||
|
Transactions.indexParam = function(req, res, next, index) {
|
||||||
|
index = parseInt(index);
|
||||||
|
req.index = index;
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* controllers
|
* controllers
|
||||||
@ -74,6 +83,54 @@ Transactions.send = function(req, res) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a list of transactions given certain request options
|
||||||
|
*/
|
||||||
|
Transactions.list = function(req, res) {
|
||||||
|
var opts = {};
|
||||||
|
opts.address = req.address;
|
||||||
|
node.listTransactions(opts)
|
||||||
|
.then(function(transactions) {
|
||||||
|
res.send(transactions);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var buildIOHelper = function(name) {
|
||||||
|
$.checkArgument(name === 'inputs' || name === 'outputs');
|
||||||
|
return function(req, res) {
|
||||||
|
$.checkState(req.tx instanceof Transaction);
|
||||||
|
if (_.isNumber(req.index)) {
|
||||||
|
if (req.index >= req.tx[name].length) {
|
||||||
|
res.status(404).send('Transaction ' + name.substring(0, name.length - 1) + ' ' + req.index +
|
||||||
|
' for ' + req.tx.id + ' not found, it only has ' + req.tx[name].length + ' ' + name + '.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.send(req.tx[name][req.index].toJSON());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.send(req.tx[name].map(function(x) {
|
||||||
|
return x.toJSON();
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a transaction's outputs
|
||||||
|
*/
|
||||||
|
Transactions.getInputs = buildIOHelper('inputs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a transaction's outputs
|
||||||
|
*/
|
||||||
|
Transactions.getOutputs = buildIOHelper('outputs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* errors
|
||||||
|
*/
|
||||||
|
|
||||||
Transaction._sendError = function(res) {
|
Transaction._sendError = function(res) {
|
||||||
res.status(422);
|
res.status(422);
|
||||||
res.send('/v1/transactions/send parameter must be a raw transaction hex');
|
res.send('/v1/transactions/send parameter must be a raw transaction hex');
|
||||||
@ -85,4 +142,9 @@ Transactions.getTxError = function(req, res) {
|
|||||||
res.send('/v1/transactions/ parameter must be a 64 digit hex');
|
res.send('/v1/transactions/ parameter must be a 64 digit hex');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Transactions.indexError = function(req, res) {
|
||||||
|
res.status(422);
|
||||||
|
res.send('index parameter must be a positive integer');
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = Transactions;
|
module.exports = Transactions;
|
||||||
|
|||||||
@ -6,7 +6,6 @@ var Blocks = require('../controllers/blocks');
|
|||||||
var Transactions = require('../controllers/transactions');
|
var Transactions = require('../controllers/transactions');
|
||||||
var Addresses = require('../controllers/addresses');
|
var Addresses = require('../controllers/addresses');
|
||||||
|
|
||||||
|
|
||||||
function initRouter(node) {
|
function initRouter(node) {
|
||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
|
|
||||||
@ -14,17 +13,13 @@ function initRouter(node) {
|
|||||||
controller.setNode(node);
|
controller.setNode(node);
|
||||||
});
|
});
|
||||||
|
|
||||||
function mockResponse(req, res) {
|
|
||||||
res.send({
|
|
||||||
'message': 'This is a mocked response'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// parameter middleware
|
// parameter middleware
|
||||||
router.param('blockHash', Blocks.blockHashParam);
|
router.param('blockHash', Blocks.blockHashParam);
|
||||||
router.param('height', Blocks.heightParam);
|
router.param('height', Blocks.heightParam);
|
||||||
router.param('txHash', Transactions.txHashParam);
|
router.param('txHash', Transactions.txHashParam);
|
||||||
router.param('address', Addresses.addressParam);
|
router.param('address', Addresses.addressParam);
|
||||||
|
router.param('addresses', Addresses.addressesParam);
|
||||||
|
router.param('index', Transactions.indexParam);
|
||||||
|
|
||||||
// Node routes
|
// Node routes
|
||||||
router.get('/node', NodeStatus.getStatus);
|
router.get('/node', NodeStatus.getStatus);
|
||||||
@ -40,22 +35,22 @@ function initRouter(node) {
|
|||||||
router.post('/transactions/send', Transactions.send);
|
router.post('/transactions/send', Transactions.send);
|
||||||
|
|
||||||
// Input routes
|
// Input routes
|
||||||
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/inputs', mockResponse);
|
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/inputs', Transactions.getInputs);
|
||||||
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/inputs/:index([0-9]+)', mockResponse);
|
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/inputs/:index([0-9]+)', Transactions.getInputs);
|
||||||
|
|
||||||
// Output routes
|
// Output routes
|
||||||
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/outputs', mockResponse);
|
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/outputs', Transactions.getOutputs);
|
||||||
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/outputs/:index([0-9]+)', mockResponse);
|
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/outputs/:index([0-9]+)', Transactions.getOutputs);
|
||||||
|
|
||||||
// Address routes
|
// Address routes
|
||||||
router.get('/addresses/:address', Addresses.get);
|
router.get('/addresses/:address', Addresses.get);
|
||||||
router.get('/addresses/:address/transactions', mockResponse);
|
router.get('/addresses/:address/transactions', Transactions.list);
|
||||||
router.get('/addresses/:address/utxos', mockResponse);
|
router.get('/addresses/:addresses/utxos', Addresses.utxos);
|
||||||
// TODO: check if this is really restful
|
|
||||||
router.get('/addresses/:addresses/utxos', mockResponse);
|
|
||||||
|
|
||||||
// error routes
|
// error routes
|
||||||
router.get('/blocks/*', Blocks.getBlockError);
|
router.get('/blocks/*', Blocks.getBlockError);
|
||||||
|
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/inputs/*', Transactions.indexError);
|
||||||
|
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/outputs/*', Transactions.indexError);
|
||||||
router.get('/transactions/*', Transactions.getTxError);
|
router.get('/transactions/*', Transactions.getTxError);
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
|
|||||||
@ -2,65 +2,124 @@
|
|||||||
|
|
||||||
var mockAddresses = {
|
var mockAddresses = {
|
||||||
'1CT9huFgxMFveRvzZ7zPPJNoaMm2Fo64VH': {
|
'1CT9huFgxMFveRvzZ7zPPJNoaMm2Fo64VH': {
|
||||||
address: '1CT9huFgxMFveRvzZ7zPPJNoaMm2Fo64VH',
|
summary: {
|
||||||
transactions: [
|
address: '1CT9huFgxMFveRvzZ7zPPJNoaMm2Fo64VH',
|
||||||
'b944ef8c77f9b5f4a4276880f17256988bba4d0125abc54391548061a688ae09'
|
transactions: [
|
||||||
],
|
'b944ef8c77f9b5f4a4276880f17256988bba4d0125abc54391548061a688ae09'
|
||||||
unconfirmed: {
|
],
|
||||||
balance: 5000000000,
|
unconfirmed: {
|
||||||
received: 5000000000,
|
balance: 5000000000,
|
||||||
sent: 0,
|
received: 5000000000,
|
||||||
|
sent: 0,
|
||||||
|
},
|
||||||
|
confirmed: {
|
||||||
|
balance: 5000000000,
|
||||||
|
received: 5000000000,
|
||||||
|
sent: 0,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
confirmed: {
|
utxos: [{
|
||||||
balance: 5000000000,
|
satoshis: 5000000000,
|
||||||
received: 5000000000,
|
script: '4104b715afd59b31be928e073e375a6196d654a78d9aa709789665dd4aecf1b85ebc850ffb90a1c04f18565afe0be4a042ff6629c398f674a5c632b017d793dc8e04ac',
|
||||||
sent: 0,
|
txid: 'b944ef8c77f9b5f4a4276880f17256988bba4d0125abc54391548061a688ae09',
|
||||||
}
|
index: 0
|
||||||
|
}]
|
||||||
},
|
},
|
||||||
'1HZH6zHri1qc68s34MmE5MwG9xstbkFavo': {
|
'1HZH6zHri1qc68s34MmE5MwG9xstbkFavo': {
|
||||||
address: '1HZH6zHri1qc68s34MmE5MwG9xstbkFavo',
|
summary: {
|
||||||
transactions: [
|
address: '1HZH6zHri1qc68s34MmE5MwG9xstbkFavo',
|
||||||
'07ebb557e5782d4b9b7180c5b0b299ab1249d28f3454ccc19d4e7bd819e5ec35',
|
transactions: [
|
||||||
'7b309cef1b87471baee38a533c850ce25350f10e88a64e04da1ee08a69dbbba1',
|
'07ebb557e5782d4b9b7180c5b0b299ab1249d28f3454ccc19d4e7bd819e5ec35',
|
||||||
'0c88e745b5c1dffccc39a96f3e25e9486bcafde82b92441f463859df15685959',
|
'7b309cef1b87471baee38a533c850ce25350f10e88a64e04da1ee08a69dbbba1',
|
||||||
],
|
'0c88e745b5c1dffccc39a96f3e25e9486bcafde82b92441f463859df15685959',
|
||||||
unconfirmed: {
|
],
|
||||||
balance: 200000043000,
|
unconfirmed: {
|
||||||
received: 200000043000,
|
balance: 200000043000,
|
||||||
sent: 0,
|
received: 200000043000,
|
||||||
|
sent: 0,
|
||||||
|
},
|
||||||
|
confirmed: {
|
||||||
|
balance: 200000043000,
|
||||||
|
received: 200000043000,
|
||||||
|
sent: 0,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
confirmed: {
|
utxos: [{
|
||||||
balance: 200000043000,
|
satoshis: 200000000000,
|
||||||
received: 200000043000,
|
script: '76a914b59cc3ffe416e460a75baaae3d78cafc787e329d88ac',
|
||||||
sent: 0,
|
txid: '0c88e745b5c1dffccc39a96f3e25e9486bcafde82b92441f463859df15685959',
|
||||||
}
|
index: 1
|
||||||
|
}, {
|
||||||
|
satoshis: 1000,
|
||||||
|
script: '76a914b59cc3ffe416e460a75baaae3d78cafc787e329d88ac',
|
||||||
|
txid: '7b309cef1b87471baee38a533c850ce25350f10e88a64e04da1ee08a69dbbba1',
|
||||||
|
index: 46
|
||||||
|
}, {
|
||||||
|
satoshis: 42000,
|
||||||
|
script: '76a914b59cc3ffe416e460a75baaae3d78cafc787e329d88ac',
|
||||||
|
txid: '07ebb557e5782d4b9b7180c5b0b299ab1249d28f3454ccc19d4e7bd819e5ec35',
|
||||||
|
index: 41
|
||||||
|
}]
|
||||||
|
|
||||||
},
|
},
|
||||||
'1CEXio2gSCozXeSuKQJCDMEpgHfaiT48A3': {
|
'1CEXio2gSCozXeSuKQJCDMEpgHfaiT48A3': {
|
||||||
address: '1CEXio2gSCozXeSuKQJCDMEpgHfaiT48A3',
|
summary: {
|
||||||
transactions: [
|
address: '1CEXio2gSCozXeSuKQJCDMEpgHfaiT48A3',
|
||||||
'07ebb557e5782d4b9b7180c5b0b299ab1249d28f3454ccc19d4e7bd819e5ec35',
|
transactions: [
|
||||||
'b6025e6835966b31f40a9f0bb4a1717df0976ec23934934d2b2580a884c09b68',
|
'07ebb557e5782d4b9b7180c5b0b299ab1249d28f3454ccc19d4e7bd819e5ec35',
|
||||||
'6ae158f49c25435c472f1533bce7d090f9edeb75b20fc30297ee78c962f4295a',
|
'b6025e6835966b31f40a9f0bb4a1717df0976ec23934934d2b2580a884c09b68',
|
||||||
'35dd6607d21b3b0739fc0696d0633eaaa26f5ab10e2cbb0fa12353c2ccff6f83',
|
'6ae158f49c25435c472f1533bce7d090f9edeb75b20fc30297ee78c962f4295a',
|
||||||
'f14c1e10e8b0657068df4d53d8d93d1eb6b1f699041f7d505d5c482479c59634',
|
'35dd6607d21b3b0739fc0696d0633eaaa26f5ab10e2cbb0fa12353c2ccff6f83',
|
||||||
'9aa72c5b116a12f80b2d38b1f7bb43356d3a4f02637e7ac5abfeebb14862a3f8',
|
'f14c1e10e8b0657068df4d53d8d93d1eb6b1f699041f7d505d5c482479c59634',
|
||||||
'9a0a957583f5ea390b2b5573ace7d67a876aeb66c59ada5c0d79a6b7affb34f6',
|
'9aa72c5b116a12f80b2d38b1f7bb43356d3a4f02637e7ac5abfeebb14862a3f8',
|
||||||
'585d59d3223eef73ccdc3c19b4e85cb0cc66ea818f173cf6d54723785c7210a1',
|
'9a0a957583f5ea390b2b5573ace7d67a876aeb66c59ada5c0d79a6b7affb34f6',
|
||||||
'2952d4f79d2388c3cb931e92699ded43fe3b92f2a58f03ee0c68a0a5b0d73e46',
|
'585d59d3223eef73ccdc3c19b4e85cb0cc66ea818f173cf6d54723785c7210a1',
|
||||||
'f4e18bfbd9edc5ac0cfdd5b0869d77ef5cd38908afe106c02d189ac835569c87',
|
'2952d4f79d2388c3cb931e92699ded43fe3b92f2a58f03ee0c68a0a5b0d73e46',
|
||||||
'4fb1495d114e6853acbe95c38f0acad1b8f790f8979148015e8fbfc3d0c394e9',
|
'f4e18bfbd9edc5ac0cfdd5b0869d77ef5cd38908afe106c02d189ac835569c87',
|
||||||
],
|
'4fb1495d114e6853acbe95c38f0acad1b8f790f8979148015e8fbfc3d0c394e9',
|
||||||
unconfirmed: {
|
],
|
||||||
balance: 93350245,
|
unconfirmed: {
|
||||||
received: 1230747491,
|
balance: 93350245,
|
||||||
sent: 1137397246,
|
received: 1230747491,
|
||||||
|
sent: 1137397246,
|
||||||
|
},
|
||||||
|
confirmed: {
|
||||||
|
balance: 93350245,
|
||||||
|
received: 1230747491,
|
||||||
|
sent: 1137397246,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
confirmed: {
|
utxos: [{
|
||||||
balance: 93350245,
|
'satoshis': 5636607,
|
||||||
received: 1230747491,
|
'script': '76a9147b386f749b54b874f8ce5d2a344bd524f2d7c62188ac',
|
||||||
sent: 1137397246,
|
'txid': '9aa72c5b116a12f80b2d38b1f7bb43356d3a4f02637e7ac5abfeebb14862a3f8',
|
||||||
}
|
'index': 1
|
||||||
|
}, {
|
||||||
|
'satoshis': 47379701,
|
||||||
|
'script': '76a9147b386f749b54b874f8ce5d2a344bd524f2d7c62188ac',
|
||||||
|
'txid': 'f14c1e10e8b0657068df4d53d8d93d1eb6b1f699041f7d505d5c482479c59634',
|
||||||
|
'index': 1
|
||||||
|
}, {
|
||||||
|
'satoshis': 17254743,
|
||||||
|
'script': '76a9147b386f749b54b874f8ce5d2a344bd524f2d7c62188ac',
|
||||||
|
'txid': '35dd6607d21b3b0739fc0696d0633eaaa26f5ab10e2cbb0fa12353c2ccff6f83',
|
||||||
|
'index': 1
|
||||||
|
}, {
|
||||||
|
'satoshis': 8460000,
|
||||||
|
'script': '76a9147b386f749b54b874f8ce5d2a344bd524f2d7c62188ac',
|
||||||
|
'txid': 'b6025e6835966b31f40a9f0bb4a1717df0976ec23934934d2b2580a884c09b68',
|
||||||
|
'index': 0
|
||||||
|
}, {
|
||||||
|
'satoshis': 8460000,
|
||||||
|
'script': '76a9147b386f749b54b874f8ce5d2a344bd524f2d7c62188ac',
|
||||||
|
'txid': '6ae158f49c25435c472f1533bce7d090f9edeb75b20fc30297ee78c962f4295a',
|
||||||
|
'index': 0
|
||||||
|
}, {
|
||||||
|
'satoshis': 6159194,
|
||||||
|
'script': '76a9147b386f749b54b874f8ce5d2a344bd524f2d7c62188ac',
|
||||||
|
'txid': '07ebb557e5782d4b9b7180c5b0b299ab1249d28f3454ccc19d4e7bd819e5ec35',
|
||||||
|
'index': 100
|
||||||
|
}]
|
||||||
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var bitcore = require('bitcore');
|
var bitcore = require('bitcore');
|
||||||
var Block = bitcore.Block;
|
var _ = bitcore.deps._;
|
||||||
|
|
||||||
var mockTransactions = {};
|
var mockTransactions = {};
|
||||||
var blockHexs = require('./blocks.json');
|
var blocks = require('./blocks');
|
||||||
blockHexs.map(function(hex) {
|
_.each(blocks, function(block) {
|
||||||
var block = new Block(new Buffer(hex, 'hex'));
|
|
||||||
return block;
|
|
||||||
}).forEach(function(block) {
|
|
||||||
block.transactions.forEach(function(tx) {
|
block.transactions.forEach(function(tx) {
|
||||||
mockTransactions[tx.id] = tx;
|
mockTransactions[tx.id] = tx;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,29 +11,70 @@ var bitcore = require('bitcore');
|
|||||||
var _ = bitcore.deps._;
|
var _ = bitcore.deps._;
|
||||||
|
|
||||||
var BitcoreHTTP = require('../../lib/http');
|
var BitcoreHTTP = require('../../lib/http');
|
||||||
var BitcoreNode = require('../../../');
|
|
||||||
var mockAddresses = require('../data/addresses');
|
var mockAddresses = require('../data/addresses');
|
||||||
|
var mockTransactions = require('../data/transactions');
|
||||||
|
|
||||||
describe('BitcoreHTTP v1 addresses routes', function() {
|
describe('BitcoreHTTP v1 addresses routes', function() {
|
||||||
|
|
||||||
// mocks
|
// mocks
|
||||||
|
var transactionList = _.values(mockTransactions);
|
||||||
var nodeMock, app, agent;
|
var nodeMock, app, agent;
|
||||||
|
var txs_for_addr = function(addr) {
|
||||||
|
var amount = mockAddresses[addr].summary.transactions.length;
|
||||||
|
return transactionList.slice(0, amount);
|
||||||
|
};
|
||||||
|
var utxos_for_addrs = function(addrs) {
|
||||||
|
return _.reduce(addrs, function(utxos, addr) {
|
||||||
|
return utxos.concat(mockAddresses[addr].utxos);
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
var powerset = function(set) {
|
||||||
|
if (set.length === 0) {
|
||||||
|
return [
|
||||||
|
[]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
var sets = [];
|
||||||
|
var head = set.shift();
|
||||||
|
var tail = set;
|
||||||
|
powerset(tail).forEach(function(s) {
|
||||||
|
var copy = s.slice();
|
||||||
|
copy.push(head);
|
||||||
|
|
||||||
|
sets.push(copy);
|
||||||
|
sets.push(s);
|
||||||
|
});
|
||||||
|
return sets;
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
nodeMock = new EventEmitter();
|
nodeMock = new EventEmitter();
|
||||||
nodeMock.getAddressInfo = function(address) {
|
nodeMock.getAddressInfo = function(address) {
|
||||||
return Promise.resolve(mockAddresses[address.toString()]);
|
return Promise.resolve(mockAddresses[address.toString()]);
|
||||||
};
|
};
|
||||||
|
nodeMock.listTransactions = function(opts) {
|
||||||
|
return Promise.resolve(txs_for_addr(opts.address));
|
||||||
|
};
|
||||||
|
nodeMock.getUTXOs = function(addresses) {
|
||||||
|
return Promise.resolve(utxos_for_addrs(addresses));
|
||||||
|
};
|
||||||
app = new BitcoreHTTP(nodeMock).app;
|
app = new BitcoreHTTP(nodeMock).app;
|
||||||
agent = request(app);
|
agent = request(app);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('/addresses/:addresss', function() {
|
var failsWithInvalidAddress = function(agent, url, cb) {
|
||||||
|
agent.get(url)
|
||||||
|
.expect(422)
|
||||||
|
.expect('/v1/addresses/ parameter must be a valid bitcoin address', cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('/addresses/:address', function() {
|
||||||
it('fails with invalid address', function(cb) {
|
it('fails with invalid address', function(cb) {
|
||||||
agent.get('/v1/addresses/1BpbpfLdY7oBS9gK7aDXgvMgr1DpvNH3B2')
|
failsWithInvalidAddress(agent, '/v1/addresses/1BpbpfLdY7oBS9gK7aDXgvMgr1DpvNH3B2', cb);
|
||||||
.expect(422)
|
|
||||||
.expect('/v1/addresses/ parameter must be a valid bitcoin address', cb);
|
|
||||||
});
|
});
|
||||||
Object.keys(mockAddresses).forEach(function(addr) {
|
_.keys(mockAddresses).forEach(function(addr) {
|
||||||
var info = mockAddresses[addr];
|
var info = mockAddresses[addr];
|
||||||
it('works with valid address ' + addr, function(cb) {
|
it('works with valid address ' + addr, function(cb) {
|
||||||
agent.get('/v1/addresses/' + addr)
|
agent.get('/v1/addresses/' + addr)
|
||||||
@ -42,4 +83,45 @@ describe('BitcoreHTTP v1 addresses routes', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('/addresses/:address/transactions', function() {
|
||||||
|
it('fails with invalid address', function(cb) {
|
||||||
|
failsWithInvalidAddress(agent, '/v1/addresses/1BpbpfLdY7oBS9gK7aDXgvMgr1DpvNH3B2/transactions', cb);
|
||||||
|
});
|
||||||
|
_.keys(mockAddresses).forEach(function(addr) {
|
||||||
|
it('works with valid address ' + addr, function(cb) {
|
||||||
|
agent.get('/v1/addresses/' + addr + '/transactions')
|
||||||
|
.expect(200)
|
||||||
|
.expect(JSON.stringify(txs_for_addr(addr)), cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('/addresses/:address/utxos', function() {
|
||||||
|
it('fails with invalid address', function(cb) {
|
||||||
|
agent.get('/v1/addresses/1BpbpfLdY7oBS9gK7aDXgvMgr1DpvNH3B2/utxos')
|
||||||
|
.expect(422)
|
||||||
|
.expect('/v1/addresses/ parameter must be a bitcoin address list', cb);
|
||||||
|
|
||||||
|
});
|
||||||
|
_.keys(mockAddresses).forEach(function(addr) {
|
||||||
|
it('works with valid address ' + addr, function(cb) {
|
||||||
|
agent.get('/v1/addresses/' + addr + '/utxos')
|
||||||
|
.expect(200)
|
||||||
|
.expect(JSON.stringify(utxos_for_addrs([addr])), cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('/addresses/:addresses/utxos', function() {
|
||||||
|
powerset(_.keys(mockAddresses)).forEach(function(addresses) {
|
||||||
|
if (addresses.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var list = addresses.join(',');
|
||||||
|
it('works with valid addresses ' + list, function(cb) {
|
||||||
|
var path = '/v1/addresses/' + list + '/utxos';
|
||||||
|
agent.get(path)
|
||||||
|
.expect(200)
|
||||||
|
.expect(JSON.stringify(utxos_for_addrs(addresses)), cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -14,37 +14,27 @@ var BitcoreHTTP = require('../../lib/http');
|
|||||||
var BitcoreNode = require('../../../');
|
var BitcoreNode = require('../../../');
|
||||||
var mockBlocks = require('../data/blocks');
|
var mockBlocks = require('../data/blocks');
|
||||||
|
|
||||||
Object.values = function(obj) {
|
|
||||||
var vals = [];
|
|
||||||
for (var key in obj) {
|
|
||||||
if (obj.hasOwnProperty(key)) {
|
|
||||||
vals.push(obj[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('BitcoreHTTP v1 blocks routes', function() {
|
describe('BitcoreHTTP v1 blocks routes', function() {
|
||||||
|
|
||||||
// mocks
|
// mocks
|
||||||
var b1 = mockBlocks[Object.keys(mockBlocks)[0]];
|
var b1 = mockBlocks[_.keys(mockBlocks)[0]];
|
||||||
var firstBlock = mockBlocks[Object.keys(mockBlocks).splice(0, 1)[0]];
|
var firstBlock = mockBlocks[_.keys(mockBlocks).splice(0, 1)[0]];
|
||||||
var secondBlock = mockBlocks[Object.keys(mockBlocks).splice(1, 1)[0]];
|
var secondBlock = mockBlocks[_.keys(mockBlocks).splice(1, 1)[0]];
|
||||||
var lastBlock = mockBlocks[Object.keys(mockBlocks).splice(-1)[0]];
|
var lastBlock = mockBlocks[_.keys(mockBlocks).splice(-1)[0]];
|
||||||
var blockForHash = function(hash) {
|
var blockForHash = function(hash) {
|
||||||
return mockBlocks[hash];
|
return mockBlocks[hash];
|
||||||
};
|
};
|
||||||
var last3 = Object.keys(mockBlocks).splice(-3).map(blockForHash);
|
var last3 = _.keys(mockBlocks).splice(-3).map(blockForHash);
|
||||||
var some2 = Object.keys(mockBlocks).splice(2,2).map(blockForHash);
|
var some2 = _.keys(mockBlocks).splice(2,2).map(blockForHash);
|
||||||
var nodeMock, app, agent;
|
var nodeMock, app, agent;
|
||||||
var blockList = Object.values(mockBlocks);
|
var blockList = _.values(mockBlocks);
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
nodeMock = new EventEmitter();
|
nodeMock = new EventEmitter();
|
||||||
nodeMock.getBlock = function(blockHash) {
|
nodeMock.getBlock = function(blockHash) {
|
||||||
var block;
|
var block;
|
||||||
if (typeof blockHash === 'number') {
|
if (typeof blockHash === 'number') {
|
||||||
var height = blockHash;
|
var height = blockHash;
|
||||||
block = mockBlocks[Object.keys(mockBlocks)[height - 100000]];
|
block = mockBlocks[_.keys(mockBlocks)[height - 100000]];
|
||||||
} else {
|
} else {
|
||||||
block = mockBlocks[blockHash];
|
block = mockBlocks[blockHash];
|
||||||
}
|
}
|
||||||
@ -117,7 +107,7 @@ describe('BitcoreHTTP v1 blocks routes', function() {
|
|||||||
.expect(404)
|
.expect(404)
|
||||||
.expect('Block with id 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000 not found', cb);
|
.expect('Block with id 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000 not found', cb);
|
||||||
});
|
});
|
||||||
Object.keys(mockBlocks).forEach(function(hash) {
|
_.keys(mockBlocks).forEach(function(hash) {
|
||||||
var block = mockBlocks[hash];
|
var block = mockBlocks[hash];
|
||||||
it('works with valid blockHash ...' + hash.substring(hash.length - 8), function(cb) {
|
it('works with valid blockHash ...' + hash.substring(hash.length - 8), function(cb) {
|
||||||
agent.get('/v1/blocks/' + hash)
|
agent.get('/v1/blocks/' + hash)
|
||||||
|
|||||||
@ -19,7 +19,7 @@ describe('BitcoreHTTP v1 transactions routes', function() {
|
|||||||
|
|
||||||
// mocks
|
// mocks
|
||||||
var mockValidTx = new Transaction();
|
var mockValidTx = new Transaction();
|
||||||
var t1 = mockTransactions[Object.keys(mockTransactions)[0]];
|
var t1 = mockTransactions[_.keys(mockTransactions)[0]];
|
||||||
var nodeMock, app, agent;
|
var nodeMock, app, agent;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
nodeMock = new EventEmitter();
|
nodeMock = new EventEmitter();
|
||||||
@ -40,18 +40,25 @@ describe('BitcoreHTTP v1 transactions routes', function() {
|
|||||||
agent = request(app);
|
agent = request(app);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var failsWithInvalidHash = function(agent, url, cb) {
|
||||||
|
agent.get(url)
|
||||||
|
.expect(422)
|
||||||
|
.expect('/v1/transactions/ parameter must be a 64 digit hex', cb);
|
||||||
|
};
|
||||||
|
var reportsNotFound = function(agent, url, cb) {
|
||||||
|
agent.get(url)
|
||||||
|
.expect(404)
|
||||||
|
.expect('Transaction with id 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000 not found', cb);
|
||||||
|
};
|
||||||
|
|
||||||
describe('/transactions/:txHash', function() {
|
describe('/transactions/:txHash', function() {
|
||||||
it('fails with invalid txHash', function(cb) {
|
it('fails with invalid txHash', function(cb) {
|
||||||
agent.get('/v1/transactions/abad1dea')
|
failsWithInvalidHash(agent, '/v1/transactions/abad1dea', cb);
|
||||||
.expect(422)
|
|
||||||
.expect('/v1/transactions/ parameter must be a 64 digit hex', cb);
|
|
||||||
});
|
});
|
||||||
it('returns 404 with non existent transaction', function(cb) {
|
it('returns 404 with non existent transaction', function(cb) {
|
||||||
agent.get('/v1/transactions/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000')
|
reportsNotFound(agent, '/v1/transactions/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000', cb);
|
||||||
.expect(404)
|
|
||||||
.expect('Transaction with id 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000 not found', cb);
|
|
||||||
});
|
});
|
||||||
Object.keys(mockTransactions).forEach(function(hash) {
|
_.keys(mockTransactions).forEach(function(hash) {
|
||||||
it('works with valid txHash ...' + hash.substring(hash.length - 8), function(cb) {
|
it('works with valid txHash ...' + hash.substring(hash.length - 8), function(cb) {
|
||||||
agent.get('/v1/transactions/' + hash)
|
agent.get('/v1/transactions/' + hash)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
@ -99,5 +106,48 @@ describe('BitcoreHTTP v1 transactions routes', function() {
|
|||||||
.expect('Unable to broadcast transaction 8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87', cb);
|
.expect('Unable to broadcast transaction 8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87', cb);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
var testIO = function(name) {
|
||||||
|
describe('/transactions/:txHash/' + name + '/', function() {
|
||||||
|
it('fails with invalid txHash', function(cb) {
|
||||||
|
failsWithInvalidHash(agent, '/v1/transactions/abad1dea/' + name, cb);
|
||||||
|
});
|
||||||
|
it('returns 404 with non existent transaction', function(cb) {
|
||||||
|
reportsNotFound(agent,
|
||||||
|
'/v1/transactions/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000/' + name, cb);
|
||||||
|
});
|
||||||
|
_.keys(mockTransactions).forEach(function(hash) {
|
||||||
|
var tx = mockTransactions[hash];
|
||||||
|
var summary = hash.substring(hash.length - 8);
|
||||||
|
it('works with valid txHash ...' + summary + 'getting all ' + name, function(cb) {
|
||||||
|
agent.get('/v1/transactions/' + hash + '/' + name + '/')
|
||||||
|
.expect(200)
|
||||||
|
.expect(tx[name].map(function(x) {
|
||||||
|
return x.toJSON();
|
||||||
|
}), cb);
|
||||||
|
});
|
||||||
|
var canGetSpecificInput = function(i) {
|
||||||
|
var x = tx[name][i];
|
||||||
|
return function(cb) {
|
||||||
|
agent.get('/v1/transactions/' + hash + '/' + name + '/' + i)
|
||||||
|
.expect(200)
|
||||||
|
.expect(x.toJSON(), cb);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
for (var i = 0; i < tx[name].length; i++) {
|
||||||
|
it('works with valid txHash ...' + summary + ' ' + name + ' ' + i, canGetSpecificInput(i));
|
||||||
|
}
|
||||||
|
it('fails with invalid ' + name + ' index ' + i + ' for txHash ...' + summary, function(cb) {
|
||||||
|
agent.get('/v1/transactions/' + hash + '/' + name + '/' + i)
|
||||||
|
.expect(404, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('fails with invalid ' + name + ' format', function(cb) {
|
||||||
|
agent.get('/v1/transactions/' + t1.id + '/' + name + '/-1')
|
||||||
|
.expect(422)
|
||||||
|
.expect('index parameter must be a positive integer', cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
testIO('inputs');
|
||||||
|
testIO('outputs');
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user