From f7186e0b3ce95a04a1213464e527539f3773d045 Mon Sep 17 00:00:00 2001 From: cubedro Date: Tue, 28 Apr 2015 17:42:44 +0300 Subject: [PATCH 1/6] added history request timeout --- app.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 2bfb45b..2dd91de 100644 --- a/app.js +++ b/app.js @@ -4,6 +4,7 @@ var path = require('path'); var favicon = require('serve-favicon'); var bodyParser = require('body-parser'); var askedForHistory = false; +var askedForHistoryTime = 0; var Primus = require('primus'), api, @@ -63,13 +64,14 @@ api.on('connection', function(spark) { var info = Nodes.add(data); spark.emit('ready'); - if(Nodes.getHistory().requiresUpdate() && !askedForHistory && Nodes.canNodeUpdate(data.id)) + if(Nodes.getHistory().requiresUpdate() && Nodes.canNodeUpdate(data.id) && (!askedForHistory || (new Date()).getTime() - askedForHistoryTime > 120000)) { var range = Nodes.getHistory().getHistoryRequestInterval(); console.log("asked " + data.id + " for history"); console.log('interval', range); spark.emit('history', range); askedForHistory = true; + askedForHistoryTime = (new Date()).getTime(); } client.write({action: 'add', data: info}); @@ -90,13 +92,14 @@ api.on('connection', function(spark) { client.write({action: 'charts', data: Nodes.getCharts()}); } - if(Nodes.getHistory().requiresUpdate() && !askedForHistory && Nodes.canNodeUpdate(data.id)) + if(Nodes.getHistory().requiresUpdate() && Nodes.canNodeUpdate(data.id) && (!askedForHistory || (new Date()).getTime() - askedForHistoryTime > 120000)) { var range = Nodes.getHistory().getHistoryRequestInterval(); console.log("asked " + data.id + " for history"); console.log('interval', range); spark.emit('history', range); askedForHistory = true; + askedForHistoryTime = (new Date()).getTime(); } } }); From 6e3fb3559d5944572f4a6f9849863503af47ea8c Mon Sep 17 00:00:00 2001 From: cubedro Date: Tue, 28 Apr 2015 18:22:11 +0300 Subject: [PATCH 2/6] added node avg propagation time --- models/node.js | 11 +++++++++++ public/js/filters.js | 17 +++++++++++++++++ views/index.jade | 3 +++ 3 files changed, 31 insertions(+) diff --git a/models/node.js b/models/node.js index 20150e9..8f479d3 100644 --- a/models/node.js +++ b/models/node.js @@ -27,6 +27,7 @@ var Node = function Node(data) uncles: [] }, blocktimeAvg: 0, + propagationAvg: 0, blockTimes: [], difficulty: [], latency: 0, @@ -108,6 +109,16 @@ Node.prototype.setStats = function(stats, history) if(typeof stats !== 'undefined' && typeof stats.block !== 'undefined' && typeof stats.block.number !== 'undefined') { this.history = history; + + var positives = _.filter(history, function(p) { + return p >= 0; + }); + + if(positives.length > 0) + stats.propagationAvg = Math.round(_.sum(positives)/positives.length); + else + stats.propagationAvg = 0; + this.stats = stats; return this.getStats(); diff --git a/public/js/filters.js b/public/js/filters.js index 24a318b..456448a 100644 --- a/public/js/filters.js +++ b/public/js/filters.js @@ -174,6 +174,23 @@ angular.module('netStatsApp.filters', []) return 'text-danger' }; }) +.filter('propagationAvgTimeClass', function() { + return function(propagation) { + if(propagation == 0) + return 'text-info'; + + if(propagation < 1000) + return 'text-success'; + + if(propagation < 3000) + return 'text-warning'; + + if(propagation < 7000) + return 'text-orange'; + + return 'text-danger' + }; +}) .filter('latencyFilter', function() { return function(stats) { if(stats.active === false) diff --git a/views/index.jade b/views/index.jade index e3da879..67bb36f 100644 --- a/views/index.jade +++ b/views/index.jade @@ -174,6 +174,8 @@ block content th.th-peerPropagationTime i.icon-gas(data-toggle="tooltip", data-placement="top", title="Propagation time", ng-click="orderTable(['-stats.active', '-stats.block.number', 'stats.block.propagation'], false)") th.th-peerPropagationChart + th.th-peerPropagationAvg + i.icon-gas(data-toggle="tooltip", data-placement="top", title="Average propagation time", ng-click="orderTable(['-stats.active', 'stats.propagationAvg'], false)") th i.icon-bulb(data-toggle="tooltip", data-placement="top", title="Up-time", ng-click="orderTable(['-stats.active', '-stats.uptime'], false)") tbody(ng-cloak) @@ -203,4 +205,5 @@ block content div.propagationBox span {{node.stats.block.propagation | blockPropagationFilter}} td.peerPropagationChart(class="{{node.id}}") + td(class="{{ node.stats.propagationAvg | propagationAvgTimeClass }}") {{ node.stats.propagationAvg | blockPropagationFilter }} td(class="{{ node.stats.uptime | upTimeClass : node.stats.active }}") {{ node.stats.uptime | upTimeFilter }} From f202ff059a2f2b9cb622bb312fd6f957c8279d3a Mon Sep 17 00:00:00 2001 From: cubedro Date: Tue, 28 Apr 2015 18:26:54 +0300 Subject: [PATCH 3/6] fixed avg propagation time color when inactive --- public/js/filters.js | 13 ++++++++----- views/index.jade | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/public/js/filters.js b/public/js/filters.js index 456448a..38adac5 100644 --- a/public/js/filters.js +++ b/public/js/filters.js @@ -175,17 +175,20 @@ angular.module('netStatsApp.filters', []) }; }) .filter('propagationAvgTimeClass', function() { - return function(propagation) { - if(propagation == 0) + return function(stats) { + if( ! stats.active) + return 'text-gray'; + + if(stats.propagationAvg == 0) return 'text-info'; - if(propagation < 1000) + if(stats.propagationAvg < 1000) return 'text-success'; - if(propagation < 3000) + if(stats.propagationAvg < 3000) return 'text-warning'; - if(propagation < 7000) + if(stats.propagationAvg < 7000) return 'text-orange'; return 'text-danger' diff --git a/views/index.jade b/views/index.jade index 67bb36f..25116e6 100644 --- a/views/index.jade +++ b/views/index.jade @@ -205,5 +205,5 @@ block content div.propagationBox span {{node.stats.block.propagation | blockPropagationFilter}} td.peerPropagationChart(class="{{node.id}}") - td(class="{{ node.stats.propagationAvg | propagationAvgTimeClass }}") {{ node.stats.propagationAvg | blockPropagationFilter }} + td(class="{{ node.stats | propagationAvgTimeClass }}") {{ node.stats.propagationAvg | blockPropagationFilter }} td(class="{{ node.stats.uptime | upTimeClass : node.stats.active }}") {{ node.stats.uptime | upTimeFilter }} From 422b8eb061a2951272204fc250d3b44152d5d51e Mon Sep 17 00:00:00 2001 From: cubedro Date: Tue, 28 Apr 2015 18:44:41 +0300 Subject: [PATCH 4/6] added avg block propagation --- models/history.js | 8 +++++++- public/js/controllers.js | 7 +++++-- public/js/filters.js | 27 +++++++++++++++------------ views/index.jade | 6 +++--- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/models/history.js b/models/history.js index 1f97152..24cf539 100644 --- a/models/history.js +++ b/models/history.js @@ -159,6 +159,7 @@ History.prototype.getNodePropagation = function(id) History.prototype.getBlockPropagation = function() { var propagation = []; + var avgPropagation = 0; _.forEach(this._items, function(n, key) { @@ -171,6 +172,11 @@ History.prototype.getBlockPropagation = function() }); }); + if(propagation.length > 0) + { + var avgPropagation = Math.round(_.sum(propagation) / propagation.length); + } + var x = d3.scale.linear() .domain([MIN_PROPAGATION_RANGE, MAX_PROPAGATION_RANGE]) .interpolate(d3.interpolateRound); @@ -187,7 +193,7 @@ History.prototype.getBlockPropagation = function() return {x: val.x, dx: val.dx, y: val.y, frequency: val.length, cumulative: freqCum, cumpercent: cumPercent}; }); - return histogram; + return {histogram: histogram, avg: avgPropagation}; } History.prototype.getUncleCount = function() diff --git a/public/js/controllers.js b/public/js/controllers.js index 8a599aa..f584cb8 100644 --- a/public/js/controllers.js +++ b/public/js/controllers.js @@ -14,6 +14,7 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { $scope.lastDifficulty = 0; $scope.upTimeTotal = 0; $scope.avgBlockTime = 0; + $scope.blockPropagationAvg = 0; $scope.avgHashrate = 0; $scope.uncleCount = 0; $scope.bestStats = {}; @@ -140,7 +141,8 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { break; case "blockPropagationChart": - $scope.blockPropagationChart = data; + $scope.blockPropagationChart = data.histogram; + $scope.blockPropagationAvg = data.avg; break; @@ -159,7 +161,8 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { $scope.difficultyChart = data.difficulty; $scope.transactionDensity = data.transactions; $scope.gasSpending = data.gasSpending; - $scope.blockPropagationChart = data.propagation; + $scope.blockPropagationChart = data.propagation.histogram; + $scope.blockPropagationAvg = data.propagation.avg; $scope.uncleCountChart = data.uncleCount; $scope.uncleCount = data.uncleCount[0] + data.uncleCount[1]; diff --git a/public/js/filters.js b/public/js/filters.js index 38adac5..abae0c9 100644 --- a/public/js/filters.js +++ b/public/js/filters.js @@ -175,20 +175,20 @@ angular.module('netStatsApp.filters', []) }; }) .filter('propagationAvgTimeClass', function() { - return function(stats) { - if( ! stats.active) + return function(propagationAvg, active) { + if( ! active) return 'text-gray'; - if(stats.propagationAvg == 0) + if(propagationAvg == 0) return 'text-info'; - if(stats.propagationAvg < 1000) + if(propagationAvg < 1000) return 'text-success'; - if(stats.propagationAvg < 3000) + if(propagationAvg < 3000) return 'text-warning'; - if(stats.propagationAvg < 7000) + if(propagationAvg < 7000) return 'text-orange'; return 'text-danger' @@ -232,30 +232,33 @@ angular.module('netStatsApp.filters', []) }; }) .filter('blockPropagationFilter', function() { - return function(ms) { + return function(ms, prefix) { + if(typeof prefix === 'undefined') + prefix = '+'; + var result = 0; if(ms < 1000) { - return (ms === 0 ? "" : "+") + ms + " ms"; + return (ms === 0 ? "" : prefix) + ms + " ms"; } if(ms < 1000*60) { result = ms/1000; - return "+" + result.toFixed(1) + " s"; + return prefix + result.toFixed(1) + " s"; } if(ms < 1000*60*60) { result = ms/1000/60; - return "+" + Math.round(result) + " min"; + return prefix + Math.round(result) + " min"; } if(ms < 1000*60*60*24) { result = ms/1000/60/60; - return "+" + Math.round(result) + " h"; + return prefix + Math.round(result) + " h"; } result = ms/1000/60/60/24; - return "+" + Math.round(result) + " days"; + return prefix + Math.round(result) + " days"; }; }) .filter('avgTimeFilter', function() { diff --git a/views/index.jade b/views/index.jade index 25116e6..b7b7176 100644 --- a/views/index.jade +++ b/views/index.jade @@ -101,10 +101,10 @@ block content span.big-details.spark-difficulty div.col-xs-3.stat-holder.xpull-right - div.big-info.chart.xdouble-chart.text-info + div.big-info.chart.xdouble-chart(class="{{ blockPropagationAvg | propagationAvgTimeClass : true }}") //- i.icon-gas span.small-title block propagation - //- span.small-value {{ lastDifficulty | number }} + span.small-value {{ blockPropagationAvg | blockPropagationFilter : '' }} histogram.big-details.d3-blockpropagation(data="blockPropagationChart") div.col-xs-3.stat-holder.pull-right @@ -205,5 +205,5 @@ block content div.propagationBox span {{node.stats.block.propagation | blockPropagationFilter}} td.peerPropagationChart(class="{{node.id}}") - td(class="{{ node.stats | propagationAvgTimeClass }}") {{ node.stats.propagationAvg | blockPropagationFilter }} + td(class="{{ node.stats.propagationAvg | propagationAvgTimeClass : node.stats.active }}") {{ node.stats.propagationAvg | blockPropagationFilter : '' }} td(class="{{ node.stats.uptime | upTimeClass : node.stats.active }}") {{ node.stats.uptime | upTimeFilter }} From 4f08b3ae6f18b349b446e4876ccbe4defa4557b5 Mon Sep 17 00:00:00 2001 From: cubedro Date: Wed, 29 Apr 2015 02:10:23 +0300 Subject: [PATCH 5/6] fixed block add if lower than previous --- models/history.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/models/history.js b/models/history.js index 24cf539..278646f 100644 --- a/models/history.js +++ b/models/history.js @@ -33,7 +33,7 @@ var History = function History(data) History.prototype.add = function(block, id) { - if(typeof block !== 'undefined' && typeof block.number !== 'undefined' && typeof block.uncles !== 'undefined' && typeof block.transactions !== 'undefined' && typeof block.difficulty !== 'undefined' && (this._items.length === 0 || block.number >= (this.bestBlock().height - MAX_HISTORY + 1))) + if(typeof block !== 'undefined' && typeof block.number !== 'undefined' && typeof block.uncles !== 'undefined' && typeof block.transactions !== 'undefined' && typeof block.difficulty !== 'undefined') { var historyBlock = this.search(block.number); @@ -82,8 +82,11 @@ History.prototype.add = function(block, id) propagTimes: [] } - item.propagTimes.push({node: id, received: now, propagation: block.propagation}); - this._save(item); + if(this._items.length === 0 || block.number >= (this.bestBlock().height - MAX_HISTORY + 1)) + { + item.propagTimes.push({node: id, received: now, propagation: block.propagation}); + this._save(item); + } } return block; From 2fa175c24db1232f9ed8e5793bf529886e93bff2 Mon Sep 17 00:00:00 2001 From: cubedro Date: Wed, 29 Apr 2015 02:33:49 +0300 Subject: [PATCH 6/6] added best block check before requesting history --- app.js | 23 ++++++++++++----------- models/collection.js | 12 +++++++++++- models/history.js | 12 +++++++++++- models/node.js | 5 +++++ 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/app.js b/app.js index 2dd91de..2a38c8d 100644 --- a/app.js +++ b/app.js @@ -64,16 +64,6 @@ api.on('connection', function(spark) { var info = Nodes.add(data); spark.emit('ready'); - if(Nodes.getHistory().requiresUpdate() && Nodes.canNodeUpdate(data.id) && (!askedForHistory || (new Date()).getTime() - askedForHistoryTime > 120000)) - { - var range = Nodes.getHistory().getHistoryRequestInterval(); - console.log("asked " + data.id + " for history"); - console.log('interval', range); - spark.emit('history', range); - askedForHistory = true; - askedForHistoryTime = (new Date()).getTime(); - } - client.write({action: 'add', data: info}); client.write({action: 'charts', data: Nodes.getCharts()}); } @@ -110,7 +100,8 @@ api.on('connection', function(spark) { askedForHistory = false; }); - spark.on('node-ping', function(data){ + spark.on('node-ping', function(data) + { spark.emit('node-pong'); }); @@ -121,6 +112,16 @@ api.on('connection', function(spark) { var stats = Nodes.updateLatency(data.id, data.latency); client.write({action: 'latency', data: stats}); + + if(Nodes.getHistory().requiresUpdate() && Nodes.canNodeUpdate(data.id) && (!askedForHistory || (new Date()).getTime() - askedForHistoryTime > 120000)) + { + var range = Nodes.getHistory().getHistoryRequestInterval(); + console.log("asked " + data.id + " for history"); + console.log('interval', range); + spark.emit('history', range); + askedForHistory = true; + askedForHistoryTime = (new Date()).getTime(); + } } }); diff --git a/models/collection.js b/models/collection.js index d2c81c9..819993c 100644 --- a/models/collection.js +++ b/models/collection.js @@ -139,9 +139,19 @@ Collection.prototype.getHistory = function() Collection.prototype.canNodeUpdate = function(id) { var node = this.getNode({id: id}); + if(!node) return false; - return node.canUpdate(); + + if(node.canUpdate()) + { + var diff = this._history.bestBlockNumber() - node.getBlockNumber(); + + if(diff <= 0) + return true; + } + + return false; } module.exports = Collection; \ No newline at end of file diff --git a/models/history.js b/models/history.js index 278646f..d190b58 100644 --- a/models/history.js +++ b/models/history.js @@ -128,11 +128,21 @@ History.prototype.prevMaxBlock = function(number) return this._items[index]; } -History.prototype.bestBlock = function(obj) +History.prototype.bestBlock = function() { return _.max(this._items, 'height'); } +History.prototype.bestBlockNumber = function() +{ + var best = this.bestBlock(); + + if(typeof best.height !== 'undefined') + return best.height; + + return 0; +} + History.prototype.getNodePropagation = function(id) { var propagation = new Array(MAX_PEER_PROPAGATION); diff --git a/models/node.js b/models/node.js index 8f479d3..a9ae4b6 100644 --- a/models/node.js +++ b/models/node.js @@ -150,6 +150,11 @@ Node.prototype.setState = function(active) this.uptime.history.push({status: (active ? 'up' : 'down'), time: (new Date()).getTime()}); } +Node.prototype.getBlockNumber = function() +{ + return this.stats.block.number; +} + Node.prototype.canUpdate = function() { return this.info.canUpdateHistory || false;