commit
4fec7830ec
@ -94,37 +94,62 @@ exports.multiutxo = function(req, res, next) {
|
|||||||
|
|
||||||
exports.multitxs = function(req, res, next) {
|
exports.multitxs = function(req, res, next) {
|
||||||
|
|
||||||
function processTxs(txs, cb) {
|
function processTxs(txs, from, to, cb) {
|
||||||
txs = _.uniq(_.flatten(txs));
|
txs = _.uniq(_.flatten(txs), 'txid');
|
||||||
var transactions = [];
|
var nbTxs = txs.length;
|
||||||
|
var paginated = !_.isUndefined(from) || !_.isUndefined(to);
|
||||||
|
|
||||||
|
if (paginated) {
|
||||||
|
txs.sort(function(a, b) {
|
||||||
|
return (b.ts || b.ts) - (a.ts || a.ts);
|
||||||
|
});
|
||||||
|
var start = Math.max(from || 0, 0);
|
||||||
|
var end = Math.min(to || txs.length, txs.length);
|
||||||
|
txs = txs.slice(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
async.each(txs, function (tx, callback) {
|
async.each(txs, function (tx, callback) {
|
||||||
tDb.fromIdWithInfo(tx, 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) {
|
||||||
transactions.push(tx.info);
|
_.find(txs, { txid: tx.txid }).info = tx.info;
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
var transactions = _.pluck(txs, 'info');
|
||||||
|
if (paginated) {
|
||||||
|
transactions = {
|
||||||
|
totalItems: nbTxs,
|
||||||
|
from: +from,
|
||||||
|
to: +to,
|
||||||
|
items: transactions,
|
||||||
|
};
|
||||||
|
}
|
||||||
return cb(null, transactions);
|
return cb(null, transactions);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var from = req.query.from;
|
||||||
|
var to = req.query.to;
|
||||||
|
|
||||||
var as = getAddrs(req, res, next);
|
var as = getAddrs(req, res, next);
|
||||||
if (as) {
|
if (as) {
|
||||||
var txs = [];
|
var txs = [];
|
||||||
async.each(as, function(a, callback) {
|
async.each(as, function(a, callback) {
|
||||||
a.update(function(err) {
|
a.update(function(err) {
|
||||||
if (err) callback(err);
|
if (err) callback(err);
|
||||||
txs = txs.concat(a.transactions);
|
txs.push(a.transactions);
|
||||||
callback();
|
callback();
|
||||||
}, {ignoreCache: req.param('noCache')});
|
}, {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, 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);
|
||||||
|
return next();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,25 +93,31 @@ Address.prototype.getObj = function() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Address.prototype._addTxItem = function(txItem, txList) {
|
Address.prototype._addTxItem = function(txItem, txList, includeInfo) {
|
||||||
|
function addTx(data) {
|
||||||
|
if (!txList) return;
|
||||||
|
if (includeInfo) {
|
||||||
|
txList.push(data);
|
||||||
|
} else {
|
||||||
|
txList.push(data.txid);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
// Founding tx
|
// Founding tx
|
||||||
if ( !seen[txItem.txid] ) {
|
if (!seen[txItem.txid]) {
|
||||||
seen[txItem.txid]=1;
|
seen[txItem.txid] = 1;
|
||||||
add=1;
|
add = 1;
|
||||||
|
|
||||||
if (txList)
|
addTx({ txid: txItem.txid, ts: txItem.ts });
|
||||||
txList.push(txItem.txid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spent tx
|
// Spent tx
|
||||||
if (txItem.spentTxId && !seen[txItem.spentTxId] ) {
|
if (txItem.spentTxId && !seen[txItem.spentTxId] ) {
|
||||||
if (txList) {
|
addTx({ txid: txItem.spentTxId, ts: txItem.spentTs });
|
||||||
txList.push(txItem.spentTxId);
|
|
||||||
}
|
|
||||||
seen[txItem.spentTxId]=1;
|
seen[txItem.spentTxId]=1;
|
||||||
addSpend=1;
|
addSpend=1;
|
||||||
}
|
}
|
||||||
@ -143,6 +149,7 @@ Address.prototype._addTxItem = function(txItem, txList) {
|
|||||||
// opts are
|
// opts are
|
||||||
// .onlyUnspent
|
// .onlyUnspent
|
||||||
// .txLimit (=0 -> no txs, => -1 no limit)
|
// .txLimit (=0 -> no txs, => -1 no limit)
|
||||||
|
// .includeTxInfo
|
||||||
//
|
//
|
||||||
Address.prototype.update = function(next, opts) {
|
Address.prototype.update = function(next, opts) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -188,7 +195,7 @@ Address.prototype.update = function(next, opts) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
txOut.forEach(function(txItem){
|
txOut.forEach(function(txItem){
|
||||||
self._addTxItem(txItem, txList);
|
self._addTxItem(txItem, txList, opts.includeTxInfo);
|
||||||
});
|
});
|
||||||
if (txList)
|
if (txList)
|
||||||
self.transactions = txList;
|
self.transactions = txList;
|
||||||
|
|||||||
71
test/integration/txs.js
Normal file
71
test/integration/txs.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
|
var _ = require('lodash');
|
||||||
|
var async = require('async');
|
||||||
|
var assert = require('assert');
|
||||||
|
var fs = require('fs');
|
||||||
|
var Address = require('../../app/models/Address');
|
||||||
|
var addresses = require('../../app/controllers/addresses');
|
||||||
|
var TransactionDb = require('../../lib/TransactionDb').default();
|
||||||
|
var fixture = JSON.parse(fs.readFileSync('test/integration/txs.json'));
|
||||||
|
var should = require('chai');
|
||||||
|
var sinon = require('sinon');
|
||||||
|
|
||||||
|
var txDb;
|
||||||
|
describe('Transactions for multiple addresses', function() {
|
||||||
|
this.timeout(5000);
|
||||||
|
|
||||||
|
var req, res;
|
||||||
|
before(function(c) {
|
||||||
|
txDb = TransactionDb;
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
_.each(_.flatten(_.pluck(fixture, 'addrs')), function(addr) {
|
||||||
|
TransactionDb.deleteCacheForAddress(addr, function() {
|
||||||
|
if (++i === fixture.length) return c();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function(c) {
|
||||||
|
req = {};
|
||||||
|
res = {};
|
||||||
|
req.query = {};
|
||||||
|
res.jsonp = sinon.spy();
|
||||||
|
return c();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('All', function () {
|
||||||
|
_.each(fixture, function (f) {
|
||||||
|
it(f.test, function (done) {
|
||||||
|
req.param = sinon.stub().withArgs('addrs').returns(f.addrs.join(','));
|
||||||
|
var paginated = !_.isUndefined(f.from) || !_.isUndefined(f.to);
|
||||||
|
if (paginated) {
|
||||||
|
req.query = {
|
||||||
|
from: f.from,
|
||||||
|
to: f.to
|
||||||
|
};
|
||||||
|
}
|
||||||
|
addresses.multitxs(req, res, function() {
|
||||||
|
var txs = res.jsonp.getCall(0).args[0];
|
||||||
|
txs.should.exist;
|
||||||
|
if (paginated) {
|
||||||
|
txs.totalItems.should.equal(f.totalTransactions);
|
||||||
|
txs.items.length.should.equal(f.returnedTransactions);
|
||||||
|
if (f.transactions) {
|
||||||
|
JSON.stringify(_.pluck(txs.items, 'txid')).should.equal(JSON.stringify(f.transactions));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
txs.should.be.instanceof(Array);
|
||||||
|
txs.length.should.equal(f.returnedTransactions);
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
32
test/integration/txs.json
Normal file
32
test/integration/txs.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[{
|
||||||
|
"test": "should return non-paginated txs for single address",
|
||||||
|
"addrs": ["mtA6woo1wjCeu1dLkWgpSD3tRnRfrHt3FL"],
|
||||||
|
"totalTransactions": 13,
|
||||||
|
"returnedTransactions": 13
|
||||||
|
},{
|
||||||
|
"test": "should return paginated txs for single address",
|
||||||
|
"addrs": ["mtA6woo1wjCeu1dLkWgpSD3tRnRfrHt3FL"],
|
||||||
|
"totalTransactions": 13,
|
||||||
|
"from": 8,
|
||||||
|
"to": 12,
|
||||||
|
"returnedTransactions": 4
|
||||||
|
},{
|
||||||
|
"test": "should return non-paginated txs for multiple addresses",
|
||||||
|
"addrs": ["mqtYvjsUg59XpngBAYjFF51Xauc28a6Ckd","myDZmGN9euuRhM1mniSaXhQjNdqFmUzUkj"],
|
||||||
|
"totalTransactions": 4,
|
||||||
|
"returnedTransactions": 4
|
||||||
|
},{
|
||||||
|
"test": "should return paginated txs for multiple addresses",
|
||||||
|
"addrs": ["mqtYvjsUg59XpngBAYjFF51Xauc28a6Ckd","myDZmGN9euuRhM1mniSaXhQjNdqFmUzUkj", "n2NbTWCuUyTvpA2YKTpVD4SmCouFLcm8rS"],
|
||||||
|
"totalTransactions": 6,
|
||||||
|
"from": 2,
|
||||||
|
"to": 6,
|
||||||
|
"returnedTransactions": 4,
|
||||||
|
"transactions": [
|
||||||
|
"3e81723d069b12983b2ef694c9782d32fca26cc978de744acbc32c3d3496e915",
|
||||||
|
"b701b0680bc2b6f8b58f13d035a754486ecefd2438e3495cd8f395ab7f5e7ba9",
|
||||||
|
"80fb4fd2a6e5e795a4f30aebeda49424e7ed4d3630b128efb946aa964e0bc9c0",
|
||||||
|
"855e881892d7cd4a8fa81dbd8f6e9d142d02bffc10ffbe5428036ee55c3e3e0f"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue
Block a user