add /transactions/:hash/inputs|outputs/:index

This commit is contained in:
Manuel Araoz 2015-03-11 19:20:38 -03:00
parent 63cb77fa2a
commit 81e1ec13d2
3 changed files with 95 additions and 12 deletions

View File

@ -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
@ -87,6 +96,32 @@ Transactions.list = function(req, res) {
});
};
var buildIOHelper = function(name) {
$.checkArgument(name === 'inputs' || name === 'outputs');
return function(req, res) {
$.checkState(req.tx instanceof Transaction);
if (_.isNumber(req.index)) {
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
*/
@ -102,4 +137,9 @@ Transactions.getTxError = function(req, res) {
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;

View File

@ -6,7 +6,6 @@ var Blocks = require('../controllers/blocks');
var Transactions = require('../controllers/transactions');
var Addresses = require('../controllers/addresses');
function initRouter(node) {
var router = express.Router();
@ -25,6 +24,7 @@ function initRouter(node) {
router.param('height', Blocks.heightParam);
router.param('txHash', Transactions.txHashParam);
router.param('address', Addresses.addressParam);
router.param('index', Transactions.indexParam);
// Node routes
router.get('/node', NodeStatus.getStatus);
@ -40,12 +40,12 @@ function initRouter(node) {
router.post('/transactions/send', Transactions.send);
// Input routes
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/inputs', mockResponse);
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/inputs/:index([0-9]+)', 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]+)', Transactions.getInputs);
// Output routes
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/outputs', mockResponse);
router.get('/transactions/:txHash([A-Fa-f0-9]{64})/outputs/:index([0-9]+)', 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]+)', Transactions.getOutputs);
// Address routes
router.get('/addresses/:address', Addresses.get);
@ -56,6 +56,8 @@ function initRouter(node) {
// error routes
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);
return router;

View File

@ -40,16 +40,23 @@ describe('BitcoreHTTP v1 transactions routes', function() {
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() {
it('fails with invalid txHash', function(cb) {
agent.get('/v1/transactions/abad1dea')
.expect(422)
.expect('/v1/transactions/ parameter must be a 64 digit hex', cb);
failsWithInvalidHash(agent, '/v1/transactions/abad1dea', cb);
});
it('returns 404 with non existent transaction', function(cb) {
agent.get('/v1/transactions/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000')
.expect(404)
.expect('Transaction with id 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000 not found', cb);
reportsNotFound(agent, '/v1/transactions/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000', cb);
});
Object.keys(mockTransactions).forEach(function(hash) {
it('works with valid txHash ...' + hash.substring(hash.length - 8), function(cb) {
@ -99,5 +106,39 @@ describe('BitcoreHTTP v1 transactions routes', function() {
.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);
});
Object.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));
}
});
});
};
testIO('inputs');
testIO('outputs');
});