Merge pull request #80 from cubedro/develop
Added block propagation history
This commit is contained in:
commit
07b2466d67
12
app.js
12
app.js
@ -63,6 +63,9 @@ api.on('connection', function(spark) {
|
||||
spark.emit('ready');
|
||||
|
||||
client.write({action: 'add', data: info});
|
||||
|
||||
var blockPropagationChart = Nodes.blockPropagationChart();
|
||||
client.write({action: 'blockPropagationChart', data: blockPropagationChart});
|
||||
}
|
||||
});
|
||||
|
||||
@ -70,14 +73,16 @@ api.on('connection', function(spark) {
|
||||
{
|
||||
console.log('Latency: ', spark.latency);
|
||||
console.log('got update from ' + spark.id);
|
||||
console.log(data);
|
||||
|
||||
if(typeof data.id !== 'undefined' && typeof data.stats !== 'undefined')
|
||||
{
|
||||
data.stats.latency = spark.latency;
|
||||
var stats = Nodes.update(data.id, data.stats);
|
||||
|
||||
var stats = Nodes.update(data.id, data.stats);
|
||||
client.write({action: 'update', data: stats});
|
||||
|
||||
var blockPropagationChart = Nodes.blockPropagationChart();
|
||||
client.write({action: 'blockPropagationChart', data: blockPropagationChart});
|
||||
}
|
||||
});
|
||||
|
||||
@ -116,6 +121,9 @@ client.on('connection', function(spark) {
|
||||
console.log(data);
|
||||
|
||||
spark.emit('init', {nodes: Nodes.all()});
|
||||
|
||||
var blockPropagationChart = Nodes.blockPropagationChart();
|
||||
spark.write({action: 'blockPropagationChart', data: blockPropagationChart});
|
||||
});
|
||||
|
||||
spark.on('client-pong', function(data) {
|
||||
|
@ -1,9 +1,11 @@
|
||||
var _ = require('lodash');
|
||||
var Blockchain = require('./history');
|
||||
var Node = require('./node');
|
||||
|
||||
var Collection = function Collection()
|
||||
{
|
||||
this._list = [];
|
||||
this._history = new Blockchain();
|
||||
this._bestBlock = null;
|
||||
|
||||
return this;
|
||||
@ -24,36 +26,14 @@ Collection.prototype.update = function(id, stats)
|
||||
if(!node)
|
||||
return false;
|
||||
|
||||
if(this._bestBlock === null)
|
||||
{
|
||||
stats.block.received = (new Date()).getTime();
|
||||
stats.block.propagation = 0;
|
||||
this._bestBlock = stats.block;
|
||||
}
|
||||
else
|
||||
{
|
||||
var oldStats = node.getStats();
|
||||
var block = this._history.add(stats.block, id);
|
||||
var propagationHistory = this._history.getNodePropagation(id);
|
||||
|
||||
if(stats.block.number !== oldStats.stats.block.number)
|
||||
{
|
||||
stats.block.received = (new Date()).getTime();
|
||||
stats.block.arrived = block.arrived;
|
||||
stats.block.received = block.received;
|
||||
stats.block.propagation = block.propagation;
|
||||
|
||||
if(this._bestBlock.number < stats.block.number)
|
||||
{
|
||||
stats.block.propagation = 0;
|
||||
this._bestBlock = stats.block;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats.block.propagation = stats.block.received - this._bestBlock.received;
|
||||
}
|
||||
} else {
|
||||
stats.block.received = oldStats.stats.block.received;
|
||||
stats.block.propagation = oldStats.stats.block.propagation;
|
||||
}
|
||||
}
|
||||
|
||||
return node.setStats(stats);
|
||||
return node.setStats(stats, propagationHistory);
|
||||
}
|
||||
|
||||
Collection.prototype.updateLatency = function(id, latency)
|
||||
@ -118,4 +98,9 @@ Collection.prototype.all = function()
|
||||
return this._list;
|
||||
}
|
||||
|
||||
Collection.prototype.blockPropagationChart = function()
|
||||
{
|
||||
return this._history.getBlockPropagation();
|
||||
}
|
||||
|
||||
module.exports = Collection;
|
159
models/history.js
Normal file
159
models/history.js
Normal file
@ -0,0 +1,159 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
var MAX_HISTORY = 1008;
|
||||
var MAX_PROPAGATION = 36;
|
||||
var MAX_BLOCK_PROPAGATION = 96;
|
||||
|
||||
var History = function History(data)
|
||||
{
|
||||
// this._items = new Array(MAX_HISTORY);
|
||||
this._items = [];
|
||||
|
||||
var item = {
|
||||
height: 0,
|
||||
block: {
|
||||
number: 0,
|
||||
hash: '0x?',
|
||||
arrived: 0,
|
||||
received: 0,
|
||||
propagation: 0,
|
||||
difficulty: 0,
|
||||
gasUsed: 0,
|
||||
transactions: [],
|
||||
uncles: []
|
||||
},
|
||||
propagTimes: []
|
||||
};
|
||||
|
||||
// _.fill(this._items, item);
|
||||
}
|
||||
|
||||
History.prototype.add = function(block, id)
|
||||
{
|
||||
var historyBlock = this.search(block.number);
|
||||
|
||||
var now = (new Date()).getTime();
|
||||
block.arrived = now;
|
||||
block.received = now;
|
||||
block.propagation = 0;
|
||||
|
||||
if(historyBlock)
|
||||
{
|
||||
var propIndex = _.findIndex(historyBlock.propagTimes, {node: id});
|
||||
|
||||
if(propIndex === -1)
|
||||
{
|
||||
block.arrived = historyBlock.block.arrived;
|
||||
block.received = now;
|
||||
block.propagation = now - historyBlock.block.received;
|
||||
|
||||
historyBlock.propagTimes.push({node: id, received: now, propagation: block.propagation});
|
||||
}
|
||||
else
|
||||
{
|
||||
block.arrived = historyBlock.block.arrived;
|
||||
block.received = historyBlock.propagTimes[propIndex].received;
|
||||
block.propagation = historyBlock.propagTimes[propIndex].propagation;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var item = {
|
||||
height: block.number,
|
||||
block: block,
|
||||
propagTimes: []
|
||||
}
|
||||
|
||||
item.propagTimes.push({node: id, received: now, propagation: block.propagation});
|
||||
console.log('item: ', item);
|
||||
this._save(item);
|
||||
}
|
||||
this.getNodePropagation(id);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
History.prototype._save = function(block)
|
||||
{
|
||||
this._items.push(block);
|
||||
|
||||
if(this._items.length > MAX_HISTORY){
|
||||
this._items.shift();
|
||||
}
|
||||
}
|
||||
|
||||
History.prototype.search = function(number)
|
||||
{
|
||||
var index = _.findIndex(this._items, {height: number});
|
||||
|
||||
if(index < 0)
|
||||
return false;
|
||||
|
||||
return this._items[index];
|
||||
}
|
||||
|
||||
History.prototype.bestBlock = function(obj)
|
||||
{
|
||||
return _.max(this._items, 'height');
|
||||
}
|
||||
|
||||
History.prototype.getNodePropagation = function(id)
|
||||
{
|
||||
var propagation = new Array(MAX_PROPAGATION);
|
||||
var bestBlock = this.bestBlock().height;
|
||||
|
||||
_.fill(propagation, -1);
|
||||
|
||||
var sorted = _(this._items)
|
||||
.sortByOrder('height', false)
|
||||
.slice(0, MAX_PROPAGATION)
|
||||
.reverse()
|
||||
.forEach(function(n, key)
|
||||
{
|
||||
var index = MAX_PROPAGATION - 1 - bestBlock + n.height;
|
||||
|
||||
if(index > 0)
|
||||
{
|
||||
propagation[index] = _.result(_.find(n.propagTimes, 'node', id), 'propagation', -1);
|
||||
}
|
||||
})
|
||||
.value();
|
||||
|
||||
return propagation;
|
||||
}
|
||||
|
||||
History.prototype.getBlockPropagation = function()
|
||||
{
|
||||
var propagation = new Array(MAX_BLOCK_PROPAGATION);
|
||||
var bestBlock = this.bestBlock().height;
|
||||
var i = 0;
|
||||
|
||||
_.fill(propagation, -1);
|
||||
|
||||
var sorted = _(this._items)
|
||||
.sortByOrder('height', false)
|
||||
.slice(0, MAX_PROPAGATION)
|
||||
.reverse()
|
||||
.forEach(function(n, key)
|
||||
{
|
||||
if(i < MAX_BLOCK_PROPAGATION)
|
||||
{
|
||||
_.forEach(n.propagTimes, function(p, i)
|
||||
{
|
||||
propagation.push({block: n.height, propagation: _.result(p, 'propagation', -1)});
|
||||
propagation.shift();
|
||||
i++;
|
||||
});
|
||||
}
|
||||
})
|
||||
.value();
|
||||
|
||||
return propagation;
|
||||
}
|
||||
|
||||
History.prototype.history = function()
|
||||
{
|
||||
return _.chain(this._items).sortBy('number').reverse().value();
|
||||
}
|
||||
|
||||
module.exports = History;
|
@ -1,4 +1,5 @@
|
||||
var geoip = require('geoip-lite');
|
||||
var _ = require('lodash');
|
||||
|
||||
var MAX_HISTORY = 36;
|
||||
|
||||
@ -31,13 +32,13 @@ var Node = function Node(data)
|
||||
uptime: 0,
|
||||
lastUpdate: 0
|
||||
};
|
||||
this.blockHistory = [];
|
||||
this.history = new Array(MAX_HISTORY);
|
||||
this.uptime = {
|
||||
started: null,
|
||||
history: []
|
||||
};
|
||||
|
||||
this.initBlockHistory();
|
||||
_.fill(this.history, -1);
|
||||
|
||||
if(this.id === null) {
|
||||
this.uptime.started = (new Date()).getTime();
|
||||
@ -90,41 +91,14 @@ Node.prototype.setInfo = function(data)
|
||||
|
||||
Node.prototype.getInfo = function()
|
||||
{
|
||||
return {id: this.id, info: this.info, geo: this.geo, stats: this.stats, history: this.blockHistory};
|
||||
return {id: this.id, info: this.info, geo: this.geo, stats: this.stats, history: this.history};
|
||||
}
|
||||
|
||||
Node.prototype.initBlockHistory = function()
|
||||
{
|
||||
for(var i=0; i < MAX_HISTORY; i++)
|
||||
{
|
||||
this.blockHistory.push({
|
||||
number: 0,
|
||||
received: 0,
|
||||
propagation: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Node.prototype.setStats = function(stats)
|
||||
Node.prototype.setStats = function(stats, history)
|
||||
{
|
||||
if(typeof stats !== 'undefined' && typeof stats.block !== 'undefined' && typeof stats.block.number !== 'undefined')
|
||||
{
|
||||
stats.block.hash = stats.block.hash.replace('0x', '');
|
||||
|
||||
if(stats.block.number > this.stats.block.number)
|
||||
{
|
||||
if(this.blockHistory.length === MAX_HISTORY )
|
||||
this.blockHistory.shift();
|
||||
|
||||
var history = {
|
||||
number: stats.block.number,
|
||||
received: stats.block.received,
|
||||
propagation: stats.block.propagation
|
||||
};
|
||||
|
||||
this.blockHistory.push(history);
|
||||
}
|
||||
|
||||
this.history = history;
|
||||
this.stats = stats;
|
||||
|
||||
return this.getStats();
|
||||
@ -147,7 +121,7 @@ Node.prototype.setLatency = function(latency)
|
||||
|
||||
Node.prototype.getStats = function()
|
||||
{
|
||||
return {id: this.id, stats: this.stats, history: this.blockHistory};
|
||||
return {id: this.id, stats: this.stats, history: this.history};
|
||||
}
|
||||
|
||||
Node.prototype.setState = function(active)
|
||||
|
@ -193,25 +193,88 @@ div.small-title-miner {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
.hoverinfo {
|
||||
table i {
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
-moz-font-smoothing: subpixel-antialiased;
|
||||
}
|
||||
|
||||
table th,
|
||||
table td {
|
||||
border-color: #222 !important;
|
||||
}
|
||||
|
||||
table td {
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
table th {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
table th i {
|
||||
font-size: 20px;
|
||||
}
|
||||
table td i {
|
||||
position: relative;
|
||||
width: auto;
|
||||
left: -50%;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 3px !important;
|
||||
padding: 5px !important;
|
||||
line-height: 14px !important;
|
||||
line-height: 16px;
|
||||
}
|
||||
table td i:before {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
.hoverinfo .propagationBox {
|
||||
top: 3px;
|
||||
.table>tbody>tr>td,
|
||||
.table>thead>tr>th {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.jqstooltip {
|
||||
.th-nodename {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.th-latency {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.th-blockhash {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.th-blocktime {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.th-peerPropagationChart {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.nodeInfo .tooltip .tooltip-inner {
|
||||
max-width: 400px;
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#mapHolder {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
#mapHolder > svg {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.jqsfield {
|
||||
@ -241,127 +304,19 @@ div.small-title-miner {
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
|
||||
table i {
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
-moz-font-smoothing: subpixel-antialiased;
|
||||
}
|
||||
|
||||
table th,
|
||||
table td {
|
||||
border-color: #222 !important;
|
||||
}
|
||||
|
||||
table th {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
table th i {
|
||||
font-size: 20px;
|
||||
}
|
||||
table td i {
|
||||
.hoverinfo {
|
||||
position: relative;
|
||||
line-height: 16px;
|
||||
}
|
||||
table td i:before {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 5px;
|
||||
width: auto;
|
||||
left: -50%;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 3px !important;
|
||||
padding: 5px !important;
|
||||
line-height: 14px !important;
|
||||
}
|
||||
|
||||
#mapHolder {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
#mapHolder > svg {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.nodeInfo .tooltip .tooltip-inner {
|
||||
max-width: 400px;
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.table>tbody>tr>td,
|
||||
.table>thead>tr>th {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.th-nodename {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.th-latency {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.th-blockhash {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.th-blocktime {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.th-peerPropagationChart {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 639px) {
|
||||
/*.big-info {
|
||||
padding-bottom: 15px;
|
||||
padding-top: 15px;
|
||||
border: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
|
||||
.big-info .icon-full-width i {
|
||||
width: 70px;
|
||||
height: 60px;
|
||||
font-size: 60px;
|
||||
line-height: 60px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.big-info span {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.big-info span.small-title {
|
||||
font-size: 13px;
|
||||
line-height: 14px;
|
||||
letter-spacing: 1px;
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.big-info span.big-details {
|
||||
display: block;
|
||||
font-weight: 200;
|
||||
font-size: 46px;
|
||||
line-height: 50px;
|
||||
letter-spacing: -4px;
|
||||
}*/
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 479px) {
|
||||
/*.stat-holder {
|
||||
width: 100%;
|
||||
}*/
|
||||
}
|
||||
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
|
||||
display: none !important;
|
||||
}
|
||||
.hoverinfo .propagationBox {
|
||||
top: 3px;
|
||||
}
|
@ -91,8 +91,15 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
||||
switch(action) {
|
||||
case "init":
|
||||
$scope.nodes = data;
|
||||
$scope.$apply();
|
||||
|
||||
_.forEach($scope.nodes, function(node, index) {
|
||||
makePeerPropagationChart($scope.nodes[index]);
|
||||
});
|
||||
|
||||
if($scope.nodes.length > 0)
|
||||
toastr['success']("Got nodes list", "Got nodes!");
|
||||
|
||||
if($scope.nodes.length > 0) toastr['success']("Got nodes list", "Got nodes!");
|
||||
break;
|
||||
|
||||
case "add":
|
||||
@ -100,30 +107,42 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
||||
toastr['success']("New node "+ $scope.nodes[findIndex({id: data.id})].info.name +" connected!", "New node!");
|
||||
else
|
||||
toastr['info']("Node "+ $scope.nodes[findIndex({id: data.id})].info.name +" reconnected!", "Node is back!");
|
||||
|
||||
break;
|
||||
|
||||
case "update":
|
||||
var index = findIndex({id: data.id});
|
||||
$scope.nodes[index].stats = data.stats;
|
||||
$scope.nodes[index].history = data.history;
|
||||
makePeerPropagationChart(index);
|
||||
makePeerPropagationChart($scope.nodes[index]);
|
||||
|
||||
break;
|
||||
|
||||
case "info":
|
||||
$scope.nodes[findIndex({id: data.id})].info = data.info;
|
||||
|
||||
break;
|
||||
|
||||
case "blockPropagationChart":
|
||||
$scope.blockPropagationChart = data;
|
||||
makeBlockPropagationChart();
|
||||
|
||||
break;
|
||||
|
||||
case "inactive":
|
||||
$scope.nodes[findIndex({id: data.id})].stats = data.stats;
|
||||
toastr['error']("Node "+ $scope.nodes[findIndex({id: data.id})].info.name +" went away!", "Node connection was lost!");
|
||||
|
||||
break;
|
||||
|
||||
case "latency":
|
||||
$scope.nodes[findIndex({id: data.id})].stats.latency = data.latency;
|
||||
|
||||
break;
|
||||
|
||||
case "client-ping":
|
||||
socket.emit('client-pong');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -135,14 +154,12 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
||||
return _.findIndex($scope.nodes, search);
|
||||
}
|
||||
|
||||
function makePeerPropagationChart(index)
|
||||
function makePeerPropagationChart(node)
|
||||
{
|
||||
$scope.nodes[index].propagation = _.map($scope.nodes[index].history, function(block) {
|
||||
return block.propagation;
|
||||
});
|
||||
|
||||
jQuery('.' + $scope.nodes[index].id).sparkline($scope.nodes[index].propagation, {
|
||||
jQuery('.' + node.id).sparkline(node.history, {
|
||||
type: 'bar',
|
||||
negBarColor: '#7f7f7f',
|
||||
zeroAxis: false,
|
||||
height: 18,
|
||||
barWidth : 2,
|
||||
barSpacing : 1,
|
||||
@ -157,6 +174,30 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
||||
});
|
||||
}
|
||||
|
||||
function makeBlockPropagationChart()
|
||||
{
|
||||
jQuery('.spark-blockpropagation').sparkline(_.map($scope.blockPropagationChart, function(history) {
|
||||
if(typeof history.propagation === 'undefined')
|
||||
return -1;
|
||||
|
||||
return history.propagation;
|
||||
}), {
|
||||
type: 'bar',
|
||||
negBarColor: '#7f7f7f',
|
||||
zeroAxis: false,
|
||||
barWidth : 2,
|
||||
barSpacing : 1,
|
||||
tooltipSuffix: ' ms',
|
||||
colorMap: jQuery.range_map({
|
||||
'0:1': '#10a0de',
|
||||
'1:1000': '#7bcc3a',
|
||||
'1001:3000': '#FFD162',
|
||||
'3001:7000': '#ff8a00',
|
||||
'7001:': '#F74B4B'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function addNewNode(data)
|
||||
{
|
||||
var index = findIndex({id: data.id});
|
||||
@ -168,8 +209,7 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
||||
}
|
||||
|
||||
$scope.nodes[index] = data;
|
||||
$scope.nodes[index].history = data.history;
|
||||
makePeerPropagationChart(index);
|
||||
makePeerPropagationChart($scope.nodes[index]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -86,6 +86,9 @@ angular.module('netStatsApp.filters', [])
|
||||
})
|
||||
.filter('hashFilter', function() {
|
||||
return function(hash) {
|
||||
if(hash.substr(0,2) === '0x')
|
||||
hash = hash.substr(2,64);
|
||||
|
||||
return hash.substr(0, 8) + '...' + hash.substr(56, 8);
|
||||
}
|
||||
})
|
||||
|
@ -58,24 +58,29 @@ block content
|
||||
div.clearfix
|
||||
|
||||
div.row
|
||||
div.col-xs-4.stats-boxes(style="padding-top: 30px;")
|
||||
div.col-xs-6.stats-boxes(style="padding-top: 30px;")
|
||||
div.row
|
||||
div.col-xs-6.stat-holder
|
||||
div.col-xs-4.stat-holder
|
||||
div.big-info.chart
|
||||
span.small-title block time
|
||||
span.big-details.spark-blocktimes
|
||||
|
||||
div.col-xs-6.stat-holder
|
||||
div.col-xs-4.stat-holder
|
||||
div.big-info.chart
|
||||
span.small-title block propagation
|
||||
span.big-details.spark-blockpropagation
|
||||
|
||||
div.col-xs-4.stat-holder
|
||||
div.big-info.chart
|
||||
span.small-title difficulty
|
||||
span.big-details.spark-difficulty
|
||||
|
||||
div.col-xs-6.stat-holder
|
||||
div.col-xs-4.stat-holder
|
||||
div.big-info.chart
|
||||
span.small-title transactions
|
||||
span.big-details.spark-transactions
|
||||
|
||||
div.col-xs-6.stat-holder
|
||||
div.col-xs-4.stat-holder
|
||||
div.big-info.chart
|
||||
span.small-title gas spending
|
||||
span.big-details.spark-gasspending
|
||||
@ -91,13 +96,6 @@ block content
|
||||
div.block(ng-repeat="i in getNumber(miner.blocks) track by $index", class="{{miner.blocks | minerBlocksClass}}")
|
||||
div.clearfix
|
||||
|
||||
div.col-xs-2.stats-boxes(style="padding-top: 30px;")
|
||||
div.row
|
||||
//- div.col-xs-12.stat-holder
|
||||
//- div.big-info.chart
|
||||
//- span.small-title miners
|
||||
//- span.big-details test
|
||||
|
||||
div.col-xs-4
|
||||
div.col-xs-12
|
||||
nodemap#mapHolder(data="map")
|
||||
@ -149,7 +147,7 @@ block content
|
||||
td(class="{{ node.stats | blockClass : bestBlock }}")
|
||||
span.small {{node.stats.block.hash | hashFilter}}
|
||||
td(style="padding-left: 14px;") {{node.stats.block.transactions.length || 0}}
|
||||
td(class="{{ node.stats.block.received | timeClass : node.stats.active }}") {{node.stats.block.received | blockTimeFilter }}
|
||||
td(class="{{ node.stats.block.arrived | timeClass : node.stats.active }}") {{node.stats.block.arrived | blockTimeFilter }}
|
||||
td(class="{{ node.stats | propagationTimeClass : bestBlock }}") {{node.stats.block.propagation | blockPropagationFilter}}
|
||||
div.propagationBox
|
||||
td.peerPropagationChart(class="{{node.id}}")
|
||||
|
@ -3,6 +3,7 @@ html(ng-app="netStatsApp")
|
||||
head
|
||||
meta(name="viewport", content="width=device-width, initial-scale=1.0, maximum-scale=1.0")
|
||||
title= title
|
||||
style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; }
|
||||
link(rel='stylesheet', href='//fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700')
|
||||
link(rel='stylesheet', href='/css/bootstrap.min.css')
|
||||
link(rel='stylesheet', href='/css/toastr.min.css')
|
||||
|
Loading…
Reference in New Issue
Block a user