Merge pull request #316 from matiu/feat/unsync-500

Feat/unsync 500
This commit is contained in:
Gustavo Maximiliano Cortez 2015-05-27 10:08:36 -03:00
commit b9d2d44007
7 changed files with 159 additions and 130 deletions

View File

@ -11,6 +11,18 @@ var async = require('async');
var tDb = require('../../lib/TransactionDb').default(); var tDb = require('../../lib/TransactionDb').default();
var checkSync = function(req, res) {
if (req.historicSync) {
var i = req.historicSync.info()
if (i.status !== 'finished') {
common.notReady(req, res, i.syncPercentage);
return false;
}
}
return true;
};
var getAddr = function(req, res, next) { var getAddr = function(req, res, next) {
var a; var a;
try { try {
@ -47,6 +59,7 @@ var getAddrs = function(req, res, next) {
}; };
exports.show = function(req, res, next) { exports.show = function(req, res, next) {
if (!checkSync(req, res)) return;
var a = getAddr(req, res, next); var a = getAddr(req, res, next);
if (a) { if (a) {
@ -56,13 +69,18 @@ exports.show = function(req, res, next) {
} else { } else {
return res.jsonp(a.getObj()); return res.jsonp(a.getObj());
} }
}, {txLimit: req.query.noTxList?0:-1, ignoreCache: req.param('noCache')}); }, {
txLimit: req.query.noTxList ? 0 : -1,
ignoreCache: req.param('noCache')
});
} }
}; };
exports.utxo = function(req, res, next) { exports.utxo = function(req, res, next) {
if (!checkSync(req, res)) return;
var a = getAddr(req, res, next); var a = getAddr(req, res, next);
if (a) { if (a) {
a.update(function(err) { a.update(function(err) {
@ -71,11 +89,15 @@ exports.utxo = function(req, res, next) {
else { else {
return res.jsonp(a.unspent); return res.jsonp(a.unspent);
} }
}, {onlyUnspent:1, ignoreCache: req.param('noCache')}); }, {
onlyUnspent: 1,
ignoreCache: req.param('noCache')
});
} }
}; };
exports.multiutxo = function(req, res, next) { exports.multiutxo = function(req, res, next) {
if (!checkSync(req, res)) return;
var as = getAddrs(req, res, next); var as = getAddrs(req, res, next);
if (as) { if (as) {
var utxos = []; var utxos = [];
@ -84,7 +106,10 @@ exports.multiutxo = function(req, res, next) {
if (err) callback(err); if (err) callback(err);
utxos = utxos.concat(a.unspent); utxos = utxos.concat(a.unspent);
callback(); callback();
}, {onlyUnspent:1, ignoreCache: req.param('noCache')}); }, {
onlyUnspent: 1,
ignoreCache: req.param('noCache')
});
}, function(err) { // finished callback }, function(err) { // finished callback
if (err) return common.handleErrors(err, res); if (err) return common.handleErrors(err, res);
res.jsonp(utxos); res.jsonp(utxos);
@ -93,6 +118,7 @@ exports.multiutxo = function(req, res, next) {
}; };
exports.multitxs = function(req, res, next) { exports.multitxs = function(req, res, next) {
if (!checkSync(req, res)) return;
function processTxs(txs, from, to, cb) { function processTxs(txs, from, to, cb) {
txs = _.uniq(_.flatten(txs), 'txid'); txs = _.uniq(_.flatten(txs), 'txid');
@ -109,9 +135,11 @@ exports.multitxs = function(req, res, next) {
} }
var txIndex = {}; var txIndex = {};
_.each(txs, function (tx) { txIndex[tx.txid] = tx; }); _.each(txs, function(tx) {
txIndex[tx.txid] = tx;
});
async.each(txs, function (tx, callback) { async.each(txs, function(tx, callback) {
tDb.fromIdWithInfo(tx.txid, function(err, tx) { tDb.fromIdWithInfo(tx.txid, function(err, tx) {
if (err) console.log(err); if (err) console.log(err);
if (tx && tx.info) { if (tx && tx.info) {
@ -119,9 +147,9 @@ exports.multitxs = function(req, res, next) {
} }
callback(); callback();
}); });
}, function (err) { }, function(err) {
if (err) return cb(err); if (err) return cb(err);
var transactions = _.pluck(txs, 'info'); var transactions = _.pluck(txs, 'info');
if (paginated) { if (paginated) {
transactions = { transactions = {
@ -146,10 +174,13 @@ exports.multitxs = function(req, res, next) {
if (err) callback(err); if (err) callback(err);
txs.push(a.transactions); txs.push(a.transactions);
callback(); callback();
}, {ignoreCache: req.param('noCache'), includeTxInfo: true}); }, {
ignoreCache: req.param('noCache'),
includeTxInfo: true
});
}, function(err) { // finished callback }, function(err) { // finished callback
if (err) return common.handleErrors(err, res); if (err) return common.handleErrors(err, res);
processTxs(txs, from, to, function (err, transactions) { processTxs(txs, from, to, function(err, transactions) {
if (err) return common.handleErrors(err, res); if (err) return common.handleErrors(err, res);
res.jsonp(transactions); res.jsonp(transactions);
}); });
@ -158,6 +189,7 @@ exports.multitxs = function(req, res, next) {
}; };
exports.balance = function(req, res, next) { exports.balance = function(req, res, next) {
if (!checkSync(req, res)) return;
var a = getAddr(req, res, next); var a = getAddr(req, res, next);
if (a) if (a)
a.update(function(err) { a.update(function(err) {
@ -166,10 +198,13 @@ exports.balance = function(req, res, next) {
} else { } else {
return res.jsonp(a.balanceSat); return res.jsonp(a.balanceSat);
} }
}, {ignoreCache: req.param('noCache')}); }, {
ignoreCache: req.param('noCache')
});
}; };
exports.totalReceived = function(req, res, next) { exports.totalReceived = function(req, res, next) {
if (!checkSync(req, res)) return;
var a = getAddr(req, res, next); var a = getAddr(req, res, next);
if (a) if (a)
a.update(function(err) { a.update(function(err) {
@ -178,10 +213,13 @@ exports.totalReceived = function(req, res, next) {
} else { } else {
return res.jsonp(a.totalReceivedSat); return res.jsonp(a.totalReceivedSat);
} }
}, {ignoreCache: req.param('noCache')}); }, {
ignoreCache: req.param('noCache')
});
}; };
exports.totalSent = function(req, res, next) { exports.totalSent = function(req, res, next) {
if (!checkSync(req, res)) return;
var a = getAddr(req, res, next); var a = getAddr(req, res, next);
if (a) if (a)
a.update(function(err) { a.update(function(err) {
@ -190,10 +228,13 @@ exports.totalSent = function(req, res, next) {
} else { } else {
return res.jsonp(a.totalSentSat); return res.jsonp(a.totalSentSat);
} }
}, {ignoreCache: req.param('noCache')}); }, {
ignoreCache: req.param('noCache')
});
}; };
exports.unconfirmedBalance = function(req, res, next) { exports.unconfirmedBalance = function(req, res, next) {
if (!checkSync(req, res)) return;
var a = getAddr(req, res, next); var a = getAddr(req, res, next);
if (a) if (a)
a.update(function(err) { a.update(function(err) {
@ -202,5 +243,7 @@ exports.unconfirmedBalance = function(req, res, next) {
} else { } else {
return res.jsonp(a.unconfirmedBalanceSat); return res.jsonp(a.unconfirmedBalanceSat);
} }
}, {ignoreCache: req.param('noCache')}); }, {
ignoreCache: req.param('noCache')
});
}; };

View File

@ -1,5 +1,8 @@
'use strict'; 'use strict';
exports.notReady = function (err, res, p) {
res.status(503).send('Server not yet ready. Sync Percentage:' + p);
};
exports.handleErrors = function (err, res) { exports.handleErrors = function (err, res) {
if (err) { if (err) {

View File

@ -12,40 +12,33 @@ var Status = require('../models/Status'),
*/ */
exports.show = function(req, res) { exports.show = function(req, res) {
if (! req.query.q) { var option = req.query.q;
res.status(400).send('Bad Request'); var statusObject = new Status();
}
else {
var option = req.query.q;
var statusObject = new Status();
var returnJsonp = function (err) { var returnJsonp = function (err) {
if (err || ! statusObject) if (err || ! statusObject)
return common.handleErrors(err, res); return common.handleErrors(err, res);
else { else {
res.jsonp(statusObject); res.jsonp(statusObject);
}
};
switch(option) {
case 'getInfo':
statusObject.getInfo(returnJsonp);
break;
case 'getDifficulty':
statusObject.getDifficulty(returnJsonp);
break;
case 'getTxOutSetInfo':
statusObject.getTxOutSetInfo(returnJsonp);
break;
case 'getLastBlockHash':
statusObject.getLastBlockHash(returnJsonp);
break;
case 'getBestBlockHash':
statusObject.getBestBlockHash(returnJsonp);
break;
default:
res.status(400).send('Bad Request');
} }
};
switch(option) {
case 'getDifficulty':
statusObject.getDifficulty(returnJsonp);
break;
case 'getTxOutSetInfo':
statusObject.getTxOutSetInfo(returnJsonp);
break;
case 'getLastBlockHash':
statusObject.getLastBlockHash(returnJsonp);
break;
case 'getBestBlockHash':
statusObject.getBestBlockHash(returnJsonp);
break;
case 'getInfo':
default:
statusObject.getInfo(returnJsonp);
} }
}; };

View File

@ -1,43 +1,43 @@
'use strict'; 'use strict';
var imports = require('soop').imports(); var imports = require('soop').imports();
var async = require('async'); var async = require('async');
var bitcore = require('bitcore'); var bitcore = require('bitcore');
var BitcoreAddress = bitcore.Address; var BitcoreAddress = bitcore.Address;
var BitcoreTransaction = bitcore.Transaction; var BitcoreTransaction = bitcore.Transaction;
var BitcoreUtil = bitcore.util; var BitcoreUtil = bitcore.util;
var Parser = bitcore.BinaryParser; var Parser = bitcore.BinaryParser;
var Buffer = bitcore.Buffer; var Buffer = bitcore.Buffer;
var TransactionDb = imports.TransactionDb || require('../../lib/TransactionDb').default(); var TransactionDb = imports.TransactionDb || require('../../lib/TransactionDb').default();
var BlockDb = imports.BlockDb || require('../../lib/BlockDb').default(); var BlockDb = imports.BlockDb || require('../../lib/BlockDb').default();
var config = require('../../config/config'); var config = require('../../config/config');
var CONCURRENCY = 5; var CONCURRENCY = 5;
function Address(addrStr) { function Address(addrStr) {
this.balanceSat = 0; this.balanceSat = 0;
this.totalReceivedSat = 0; this.totalReceivedSat = 0;
this.totalSentSat = 0; this.totalSentSat = 0;
this.unconfirmedBalanceSat = 0; this.unconfirmedBalanceSat = 0;
this.txApperances = 0; this.txApperances = 0;
this.unconfirmedTxApperances= 0; this.unconfirmedTxApperances = 0;
this.seen = {}; this.seen = {};
// TODO store only txids? +index? +all? // TODO store only txids? +index? +all?
this.transactions = []; this.transactions = [];
this.unspent = []; this.unspent = [];
var a = new BitcoreAddress(addrStr); var a = new BitcoreAddress(addrStr);
a.validate(); a.validate();
this.addrStr = addrStr; this.addrStr = addrStr;
Object.defineProperty(this, 'totalSent', { Object.defineProperty(this, 'totalSent', {
get: function() { get: function() {
return parseFloat(this.totalSentSat) / parseFloat(BitcoreUtil.COIN); return parseFloat(this.totalSentSat) / parseFloat(BitcoreUtil.COIN);
}, },
set: function(i) { set: function(i) {
this.totalSentSat = i * BitcoreUtil.COIN; this.totalSentSat = i * BitcoreUtil.COIN;
}, },
enumerable: 1, enumerable: 1,
}); });
@ -46,8 +46,8 @@ function Address(addrStr) {
get: function() { get: function() {
return parseFloat(this.balanceSat) / parseFloat(BitcoreUtil.COIN); return parseFloat(this.balanceSat) / parseFloat(BitcoreUtil.COIN);
}, },
set: function(i) { set: function(i) {
this.balance = i * BitcoreUtil.COIN; this.balance = i * BitcoreUtil.COIN;
}, },
enumerable: 1, enumerable: 1,
}); });
@ -56,8 +56,8 @@ function Address(addrStr) {
get: function() { get: function() {
return parseFloat(this.totalReceivedSat) / parseFloat(BitcoreUtil.COIN); return parseFloat(this.totalReceivedSat) / parseFloat(BitcoreUtil.COIN);
}, },
set: function(i) { set: function(i) {
this.totalReceived = i * BitcoreUtil.COIN; this.totalReceived = i * BitcoreUtil.COIN;
}, },
enumerable: 1, enumerable: 1,
}); });
@ -67,8 +67,8 @@ function Address(addrStr) {
get: function() { get: function() {
return parseFloat(this.unconfirmedBalanceSat) / parseFloat(BitcoreUtil.COIN); return parseFloat(this.unconfirmedBalanceSat) / parseFloat(BitcoreUtil.COIN);
}, },
set: function(i) { set: function(i) {
this.unconfirmedBalanceSat = i * BitcoreUtil.COIN; this.unconfirmedBalanceSat = i * BitcoreUtil.COIN;
}, },
enumerable: 1, enumerable: 1,
}); });
@ -78,18 +78,18 @@ function Address(addrStr) {
Address.prototype.getObj = function() { Address.prototype.getObj = function() {
// Normalize json address // Normalize json address
return { return {
'addrStr': this.addrStr, 'addrStr': this.addrStr,
'balance': this.balance, 'balance': this.balance,
'balanceSat': this.balanceSat, 'balanceSat': this.balanceSat,
'totalReceived': this.totalReceived, 'totalReceived': this.totalReceived,
'totalReceivedSat': this.totalReceivedSat, 'totalReceivedSat': this.totalReceivedSat,
'totalSent': this.totalSent, 'totalSent': this.totalSent,
'totalSentSat': this.totalSentSat, 'totalSentSat': this.totalSentSat,
'unconfirmedBalance': this.unconfirmedBalance, 'unconfirmedBalance': this.unconfirmedBalance,
'unconfirmedBalanceSat': this.unconfirmedBalanceSat, 'unconfirmedBalanceSat': this.unconfirmedBalanceSat,
'unconfirmedTxApperances': this.unconfirmedTxApperances, 'unconfirmedTxApperances': this.unconfirmedTxApperances,
'txApperances': this.txApperances, 'txApperances': this.txApperances,
'transactions': this.transactions 'transactions': this.transactions
}; };
}; };
@ -103,7 +103,8 @@ Address.prototype._addTxItem = function(txItem, txList, includeInfo) {
} }
}; };
var add=0, addSpend=0; var add = 0,
addSpend = 0;
var v = txItem.value_sat; var v = txItem.value_sat;
var seen = this.seen; var seen = this.seen;
@ -112,35 +113,38 @@ Address.prototype._addTxItem = function(txItem, txList, includeInfo) {
seen[txItem.txid] = 1; seen[txItem.txid] = 1;
add = 1; add = 1;
addTx({ txid: txItem.txid, ts: txItem.ts }); addTx({
txid: txItem.txid,
ts: txItem.ts
});
} }
// Spent tx // Spent tx
if (txItem.spentTxId && !seen[txItem.spentTxId] ) { if (txItem.spentTxId && !seen[txItem.spentTxId]) {
addTx({ txid: txItem.spentTxId, ts: txItem.spentTs }); addTx({
seen[txItem.spentTxId]=1; txid: txItem.spentTxId,
addSpend=1; ts: txItem.spentTs
});
seen[txItem.spentTxId] = 1;
addSpend = 1;
} }
if (txItem.isConfirmed) { if (txItem.isConfirmed) {
this.txApperances += add; this.txApperances += add;
this.totalReceivedSat += v; this.totalReceivedSat += v;
if (! txItem.spentTxId ) { if (!txItem.spentTxId) {
//unspent //unspent
this.balanceSat += v; this.balanceSat += v;
} } else if (!txItem.spentIsConfirmed) {
else if(!txItem.spentIsConfirmed) {
// unspent // unspent
this.balanceSat += v; this.balanceSat += v;
this.unconfirmedBalanceSat -= v; this.unconfirmedBalanceSat -= v;
this.unconfirmedTxApperances += addSpend; this.unconfirmedTxApperances += addSpend;
} } else {
else {
// spent // spent
this.totalSentSat += v; this.totalSentSat += v;
this.txApperances += addSpend; this.txApperances += addSpend;
} }
} } else {
else {
this.unconfirmedBalanceSat += v; this.unconfirmedBalanceSat += v;
this.unconfirmedTxApperances += add; this.unconfirmedTxApperances += add;
} }
@ -156,29 +160,29 @@ Address.prototype.update = function(next, opts) {
if (!self.addrStr) return next(); if (!self.addrStr) return next();
opts = opts || {}; opts = opts || {};
if (! ('ignoreCache' in opts) ) if (!('ignoreCache' in opts))
opts.ignoreCache = config.ignoreCache; opts.ignoreCache = config.ignoreCache;
// should collect txList from address? // should collect txList from address?
var txList = opts.txLimit === 0 ? null: []; var txList = opts.txLimit === 0 ? null : [];
var tDb = TransactionDb; var tDb = TransactionDb;
var bDb = BlockDb; var bDb = BlockDb;
tDb.fromAddr(self.addrStr, opts, function(err,txOut){ tDb.fromAddr(self.addrStr, opts, function(err, txOut) {
if (err) return next(err); if (err) return next(err);
bDb.fillConfirmations(txOut, function(err) { bDb.fillConfirmations(txOut, function(err) {
if (err) return next(err); if (err) return next(err);
tDb.cacheConfirmations(txOut, function(err) { tDb.cacheConfirmations(txOut, function(err) {
// console.log('[Address.js.161:txOut:]',txOut); //TODO // console.log('[Address.js.161:txOut:]',txOut); //TODO
if (err) return next(err); if (err) return next(err);
if (opts.onlyUnspent) { if (opts.onlyUnspent) {
txOut = txOut.filter(function(x){ txOut = txOut.filter(function(x) {
return !x.spentTxId; return !x.spentTxId;
}); });
tDb.fillScriptPubKey(txOut, function() { tDb.fillScriptPubKey(txOut, function() {
self.unspent = txOut.map(function(x){ self.unspent = txOut.map(function(x) {
return { return {
address: self.addrStr, address: self.addrStr,
txid: x.txid, txid: x.txid,
@ -192,12 +196,11 @@ Address.prototype.update = function(next, opts) {
}); });
return next(); return next();
}); });
} } else {
else { txOut.forEach(function(txItem) {
txOut.forEach(function(txItem){
self._addTxItem(txItem, txList, opts.includeTxInfo); self._addTxItem(txItem, txList, opts.includeTxInfo);
}); });
if (txList) if (txList)
self.transactions = txList; self.transactions = txList;
return next(); return next();
@ -208,4 +211,3 @@ Address.prototype.update = function(next, opts) {
}; };
module.exports = require('soop')(Address); module.exports = require('soop')(Address);

View File

@ -26,8 +26,8 @@ module.exports = function(app, historicSync, peerSync) {
app.set('json spaces', 0); app.set('json spaces', 0);
app.enable('jsonp callback'); app.enable('jsonp callback');
app.use(config.apiPrefix + '/sync', setHistoric); app.use(config.apiPrefix, setHistoric);
app.use(config.apiPrefix + '/peer', setPeer); app.use(config.apiPrefix, setPeer);
app.use(express.logger('dev')); app.use(express.logger('dev'));
app.use(express.json()); app.use(express.json());
app.use(express.urlencoded()); app.use(express.urlencoded());

View File

@ -131,18 +131,6 @@ if (config.enableRatelimiter) {
require('./plugins/ratelimiter').init(expressApp, config.ratelimiter); require('./plugins/ratelimiter').init(expressApp, config.ratelimiter);
} }
if (config.enableMailbox) {
require('./plugins/mailbox').init(ios, config.mailbox);
}
if (config.enableCleaner) {
require('./plugins/cleaner').init(config.cleaner);
}
if (config.enableMonitor) {
require('./plugins/monitor').init(config.monitor);
}
if (config.enableEmailstore) { if (config.enableEmailstore) {
require('./plugins/emailstore').init(config.emailstore); require('./plugins/emailstore').init(config.emailstore);
} }

View File

@ -1,7 +1,7 @@
{ {
"name": "insight-bitcore-api", "name": "insight-bitcore-api",
"description": "An open-source bitcoin blockchain API. The Insight API provides you with a convenient, powerful and simple way to query and broadcast data on the bitcoin network and build your own services with it.", "description": "An open-source bitcoin blockchain API. The Insight API provides you with a convenient, powerful and simple way to query and broadcast data on the bitcoin network and build your own services with it.",
"version": "0.2.12", "version": "0.2.13",
"author": { "author": {
"name": "Ryan X Charles", "name": "Ryan X Charles",
"email": "ryan@bitpay.com" "email": "ryan@bitpay.com"