diff --git a/db.js b/db.js index ab87ef8c8..ccf551492 100644 --- a/db.js +++ b/db.js @@ -74,6 +74,12 @@ var BlockStat = new Schema( "uncleCount": Number }); +var TxStat = new Schema( +{ + "timestamp": {type: Number, index: {unique: true}}, + "txns": Number +}, {collection: "TxStat"}); + // create indices Transaction.index({timestamp:-1}); Transaction.index({blockNumber:-1}); @@ -86,11 +92,13 @@ Block.index({miner:1}); Block.index({miner:1, blockNumber:-1}); mongoose.model('BlockStat', BlockStat); +mongoose.model('TxStat', TxStat); mongoose.model('Block', Block); mongoose.model('Account', Account); mongoose.model('Contract', Contract); mongoose.model('Transaction', Transaction); module.exports.BlockStat = mongoose.model('BlockStat'); +module.exports.TxStat = mongoose.model('TxStat'); module.exports.Block = mongoose.model('Block'); module.exports.Contract = mongoose.model('Contract'); module.exports.Transaction = mongoose.model('Transaction'); diff --git a/routes/stats.js b/routes/stats.js index 31e71469e..db44a16c0 100644 --- a/routes/stats.js +++ b/routes/stats.js @@ -1,6 +1,7 @@ var mongoose = require( 'mongoose' ); var Block = mongoose.model( 'Block' ); var BlockStat = mongoose.model( 'BlockStat' ); +var TxStat = mongoose.model( 'TxStat' ); var Transaction = mongoose.model( 'Transaction' ); var filters = require('./filters'); @@ -104,58 +105,20 @@ var getTxStats = function(req, res) { } } - // select mod - var rngs = [ 60*60, 2*60*60, 4*60*60, 6*60*60, 12*60*60, - 24*60*60, 7*24*60*60, 14*24*60*60, 30*24*60*60, 60*24*60*60 - ]; - var mods = [ 30*60, 30*60, 60*60, 60*60, 60*60, - 60*60, 24*60*60, 24*60*60, 24*60*60, 24*60*60, - 24*60*60 - ]; - var i = 0; - rngs.forEach(function(r) { - if (range > r) { - i++; - } - return; - }); - var mod = mods[i]; - var timebefore = parseInt((new Date()).getTime() / 1000) - range; - timebefore -= timebefore % mod; - Transaction.aggregate([{ - $match: { - timestamp: { - $gte: timebefore + + TxStat.find({ timestamp: { $gte: timebefore } }, "timestamp txns") + .lean(true).sort('-timestamp').limit(100) + .exec(function (err, docs) { + if (err || !docs) { + console.error(err); + res.status(500).send(); + res.end(); + return; } - } - }, { - $group: { - _id: { - timestamp: { - $subtract: [ '$timestamp', { $mod: [ '$timestamp', mod ] } ] - } - }, - timestamp: { $min: '$timestamp' }, - txns: { $sum: 1 }, - amount: { $sum: '$value' } - } - }, { - $project: { - "_id": 0, - "timestamp": 1, - "txns": 1, - "amount": 1 - } - }]).sort('timestamp').exec(function(err, result) { - if (err || !result) { - console.error(err); - res.status(500).send(); - } else { - res.write(JSON.stringify(result)); + res.write(JSON.stringify(docs)); res.end(); - } - }); + }); } /** diff --git a/tools/stats.js b/tools/stats.js index 2c912ed25..c3783841d 100644 --- a/tools/stats.js +++ b/tools/stats.js @@ -7,6 +7,8 @@ var Web3 = require('web3'); var mongoose = require( 'mongoose' ); var BlockStat = require( '../db.js' ).BlockStat; +var TxStat = require( '../db.js' ).TxStat; +var Transaction = require( '../db.js' ).Transaction; var updateStats = function(range, interval, rescan) { var latestBlock = web3.eth.blockNumber; @@ -58,6 +60,79 @@ var getStats = function(web3, blockNumber, nextBlock, endNumber, interval, resca } } +/** + * Aggregate transaction stats + */ +var updateTxStats = function(settings, range) { + var days = settings.stats && settings.stats.txnDays || 3; + + var defaultRange = 24*days*60*60; + // check validity of range + if (range && range < 60 * 60 * 24 * 7) { + if (range < 3600) { // minimal 1 hour + range = 3600; + } + } else { + range = defaultRange; + } + + // select mod + var rngs = [ 60*60, 2*60*60, 4*60*60, 6*60*60, 12*60*60, + 24*60*60, 7*24*60*60, 14*24*60*60, 30*24*60*60, 60*24*60*60 + ]; + var mods = [ 30*60, 30*60, 60*60, 60*60, 60*60, + 60*60, 24*60*60, 24*60*60, 24*60*60, 24*60*60, + 24*60*60 + ]; + var i = 0; + rngs.forEach(function(r) { + if (range > r) { + i++; + } + return; + }); + var mod = mods[i]; + + var timebefore = parseInt((new Date()).getTime() / 1000) - range; + timebefore -= timebefore % mod; + Transaction.aggregate([{ + $match: { + timestamp: { + $gte: timebefore + } + } + }, { + $group: { + _id: { + timestamp: { + $subtract: [ '$timestamp', { $mod: [ '$timestamp', mod ] } ] + } + }, + timestamp: { $min: '$timestamp' }, + txns: { $sum: 1 } + } + }, { + $project: { + "_id": 0, + "timestamp": 1, + "txns": 1 + } + }]).sort('timestamp').exec(function(err, results) { + if (err || !results) { + console.error(err); + } else { + results.forEach(function(result) { + var txstat = { + "timestamp": result.timestamp, + "txns": result.txns + } + console.log(' - txstat ' + result.timestamp + ' / txns = ' + result.txns); + TxStat.collection.update({ timestamp: result.timestamp }, { $set: txstat }, { upsert: true }); + }); + } + }); +} + /** * Checks if the a record exists for the block number * if record exists: abort @@ -117,6 +192,11 @@ var rescan = false; /* rescan: true - rescan range */ var range = 1000; var interval = 100; +// tx stats +var notxstats = false; +// interval +var txStatInterval = 10 * 60 * 1000; + /** * RESCAN=1000:100000 means interval;range * @@ -142,6 +222,15 @@ if (process.env.RESCAN) { rescan = true; } +/** + * Usage: + * - one time execute updateTxStats() + * NOTXSTATS=1 tools/stats.js + */ +if (process.env.NOTXSTATS) { + notxstats = true; +} + // load config.json var config = { nodeAddr: 'localhost', gethPort: 8545, bulkSize: 100 }; try { @@ -171,3 +260,12 @@ if (!rescan) { updateStats(range, interval); }, statInterval); } + +// update TxStats +updateTxStats(config.settings, 24*14*60*60); /* scan 14 days */ + +if (!notxstats) { + setInterval(function() { + updateTxStats(config.settings, 24*60*60); /* update */ + }, txStatInterval); +}