diff --git a/app/controllers/blocks.js b/app/controllers/blocks.js index 24788120a..f73b21c83 100644 --- a/app/controllers/blocks.js +++ b/app/controllers/blocks.js @@ -4,6 +4,7 @@ * Module dependencies. */ var common = require('./common'); +var multi = common.multi; var async = require('async'); var bdb = require('../../lib/BlockDb').default(); var tdb = require('../../lib/TransactionDb').default(); @@ -11,19 +12,34 @@ var tdb = require('../../lib/TransactionDb').default(); /** * Find block by hash ... */ -exports.block = function(req, res, next, hash) { +exports.block = multi(function(hash, cb) { bdb.fromHashWithInfo(hash, function(err, block) { if (err || !block) return common.handleErrors(err, res, next); else { tdb.getPoolInfo(block.info.tx[0], function(info) { block.info.poolInfo = info; - req.block = block.info; - return next(); + cb(null, block.info); }); } }); -}; +}, 'block'); + + +/** + * Find block header by hash ... + */ +exports.blockHeader = multi(function(hash, cb) { + bdb.fromHashWithInfo(hash, function(err, block) { + if (err || !block) + return common.handleErrors(err, res, next); + else { + delete block.info.tx; + cb(null, block.info); + } + }); +}, 'block'); + /** @@ -35,19 +51,50 @@ exports.show = function(req, res) { } }; +/** + * Show block hash + */ +exports.showBlockHash = function(req, res) { + if (req.blockHash) { + res.jsonp(req.blockHash); + } +}; + /** * Show block by Height */ -exports.blockindex = function(req, res, next, height) { +exports.blockIndex = multi(function(height, cb) { bdb.blockIndex(height, function(err, hashStr) { if (err) { console.log(err); - res.status(400).send('Bad Request'); // TODO + return cb(err); // TODO } else { - res.jsonp(hashStr); + cb(null, hashStr); } }); -}; +}, 'blockHash'); + + +/** + * Show block header by Height + */ +exports.blockHeaderByIndex = multi(function(height, cb) { + bdb.blockIndex(height, function(err, hashStr) { + if (err) { + console.log(err); + return cb(err); + } else { + bdb.fromHashWithInfo(hashStr.blockHash, function(err, block) { + if (err || !block) + return cb(err); + else { + delete block.info.tx; + cb(null, block.info); + } + }); + } + }); +}, 'block'); var getBlock = function(blockhash, cb) { bdb.fromHashWithInfo(blockhash, function(err, block) { diff --git a/app/controllers/common.js b/app/controllers/common.js index d7fb9af67..666d50b3e 100644 --- a/app/controllers/common.js +++ b/app/controllers/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,22 @@ exports.handleErrors = function (err, res) { res.status(404).send('Not found'); } }; + +exports.multi = function(f, outkey) { + return function(req, res, next, inputdata) { + var inputs; + if (inputdata.indexOf(',') >= 0) { + inputs = inputdata.split(','); + } + else inputs = [inputdata]; + async.mapSeries(inputs, f, function(err, results) { + if (err) { + return exports.handleErrors(err, res); + } + req[outkey] = results; + if (req[outkey].length == 1) + req[outkey] = req[outkey][0] + return next(); + }); + }; +} diff --git a/app/controllers/transactions.js b/app/controllers/transactions.js index bb1621918..d1ff6482a 100644 --- a/app/controllers/transactions.js +++ b/app/controllers/transactions.js @@ -6,6 +6,7 @@ var Address = require('../models/Address'); var async = require('async'); var common = require('./common'); +var multi = common.multi; var util = require('util'); var Rpc = require('../../lib/Rpc'); @@ -40,36 +41,32 @@ exports.send = function(req, res) { }); }; -exports.rawTransaction = function (req, res, next, txid) { +exports.rawTransaction = multi(function(txid, cb) { bitcoreRpc.getRawTransaction(txid, function (err, transaction) { if (err || !transaction) - return common.handleErrors(err, res); + return cb(err); else { - req.rawTransaction = { 'rawtx': transaction.result }; - return next(); + return cb(null, transaction.result); } }); -}; +}, 'rawTransaction'); /** * Find transaction by hash ... */ -exports.transaction = function(req, res, next, txid) { - - tDb.fromIdWithInfo(txid, function(err, tx) { - if (err || ! tx) - return common.handleErrors(err, res); - - bdb.fillVinConfirmations(tx.info, function(err) { - if (err) - return common.handleErrors(err, res); +exports.transaction = multi(function(txid, cb) { + tDb.fromIdWithInfo(txid, function(err, tx) { + if (err || ! tx) + return cb(err); + + bdb.fillVinConfirmations(tx.info, function(err) { + if (err) + return cb(err); + return cb(null, tx.info); + }); - req.transaction = tx.info; - return next(); }); - - }); -}; +}, 'transaction'); /** diff --git a/config/routes.js b/config/routes.js index fbb896cc8..afd60d78d 100644 --- a/config/routes.js +++ b/config/routes.js @@ -17,8 +17,14 @@ module.exports = function(app) { app.get(apiPrefix + '/block/:blockHash', blocks.show); app.param('blockHash', blocks.block); - app.get(apiPrefix + '/block-index/:height', blocks.blockindex); - app.param('height', blocks.blockindex); + app.get(apiPrefix + '/blockheader/:blockHeaderHash', blocks.show); + app.param('blockHeaderHash', blocks.blockHeader); + + app.get(apiPrefix + '/block-index/:height', blocks.showBlockHash); + app.param('height', blocks.blockIndex); + + app.get(apiPrefix + '/blockheader-by-index/:headerHeight', blocks.show); + app.param('headerHeight', blocks.blockHeaderByIndex); // Transaction routes var transactions = require('../app/controllers/transactions'); @@ -26,10 +32,14 @@ module.exports = function(app) { app.param('txid', transactions.transaction); app.get(apiPrefix + '/txs', transactions.list); app.post(apiPrefix + '/tx/send', transactions.send); + app.get(apiPrefix + '/multitx/:txids', transactions.show); + app.param('txids', transactions.transaction); // Raw Routes app.get(apiPrefix + '/rawtx/:txid', transactions.showRaw); app.param('txid', transactions.rawTransaction); + app.get(apiPrefix + '/rawmultitx/:txids', transactions.showRaw); + app.param('txids', transactions.rawTransaction); // Address routes var addresses = require('../app/controllers/addresses'); diff --git a/lib/BlockDb.js b/lib/BlockDb.js index 41c5b86ea..c899b8468 100644 --- a/lib/BlockDb.js +++ b/lib/BlockDb.js @@ -382,6 +382,7 @@ BlockDb.prototype._fillConfirmationsOneVin = function(o, chainHeight, cb) { o.confirmations = chainHeight - height + 1; } o.unconfirmedInput = ! o.isConfirmed; + o.confirmedIn = height; return cb(); }); }; @@ -426,6 +427,7 @@ BlockDb.prototype.fillVinConfirmations = function(tx, cb) { if (!vin) return cb(); async.eachLimit(vin, CONCURRENCY, function(v, e_c) { + tx.confirmedIn = height - tx.confirmations + 1; self._fillConfirmationsOneVin(v, height, e_c); }, cb); }); diff --git a/lib/TransactionDb.js b/lib/TransactionDb.js index c80c13282..153b17cfb 100644 --- a/lib/TransactionDb.js +++ b/lib/TransactionDb.js @@ -179,11 +179,18 @@ TransactionDb.prototype._fillSpent = function(info, cb) { }); }; +var valToSat = function(x) { return parseInt(x.replace('.', '')) } TransactionDb.prototype._fillOutpoints = function(txInfo, cb) { var self = this; - if (!txInfo || txInfo.isCoinBase) return cb(); + if (!txInfo) return cb(); + + for (var i = 0; i < txInfo.vout.length; i++) { + txInfo.vout[i].valueSat = valToSat(txInfo.vout[i].value); + } + + if (txInfo.isCoinBase) return cb(); var valueIn = 0; var incompleteInputs = 0; @@ -227,16 +234,17 @@ TransactionDb.prototype._fillOutpoints = function(txInfo, cb) { }); }, function() { - if (!incompleteInputs) { - txInfo.valueIn = valueIn / util.COIN; - txInfo.fees = (valueIn - (txInfo.valueOut * util.COIN)).toFixed(0) / util.COIN; - } else { - txInfo.incompleteInputs = 1; - } - return cb(); + if (!incompleteInputs) { + txInfo.valueIn = valueIn / util.COIN; + txInfo.fees = (valueIn - (txInfo.valueOut * util.COIN)).toFixed(0) / util.COIN; + } else { + txInfo.incompleteInputs = 1; + } + return cb(); }); }; + TransactionDb.prototype._getInfo = function(txid, next) { var self = this;