Merge pull request #111 from cubedro/develop
Stability improvements and refactoring
This commit is contained in:
commit
80d1cb60d7
@ -1,3 +1,7 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "0.12"
|
- "0.12"
|
||||||
|
- "0.11"
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
secure: Qdkmi13nqcXskABBhbuGZmRakh4orOW1dalkSCyUbzGuYf0OdYF8ttNVuJa0WSWI4KhNXhtz2p3I8dM95wL++LCVqXFmIvZtX8Nca36KlNxIPNXPjn0odayh+c4pgrhrbz8TDmDXl9IPuZmNz8HHtN7xmIn6YDcm13wA3gTmfwo=
|
||||||
|
108
app.js
108
app.js
@ -1,3 +1,4 @@
|
|||||||
|
var _ = require('lodash');
|
||||||
var express = require('express');
|
var express = require('express');
|
||||||
var app = express();
|
var app = express();
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
@ -48,56 +49,72 @@ api.on('connection', function(spark) {
|
|||||||
console.log('Got hello data from ', spark.id);
|
console.log('Got hello data from ', spark.id);
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
if(typeof data.secret === 'undefined' || data.secret !== WS_SECRET)
|
if( _.isUndefined(data.secret) || data.secret !== WS_SECRET )
|
||||||
{
|
{
|
||||||
spark.end(undefined, { reconnect: false });
|
spark.end(undefined, { reconnect: false });
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof data.id !== 'undefined' && typeof data.info !== 'undefined')
|
if( !_.isUndefined(data.id) && !_.isUndefined(data.info) )
|
||||||
{
|
{
|
||||||
data.ip = spark.address.ip;
|
data.ip = spark.address.ip;
|
||||||
data.spark = spark.id;
|
data.spark = spark.id;
|
||||||
data.latency = spark.latency;
|
data.latency = spark.latency;
|
||||||
|
|
||||||
var info = Nodes.add(data);
|
var info = Nodes.add( data );
|
||||||
spark.emit('ready');
|
spark.emit('ready');
|
||||||
|
|
||||||
client.write({action: 'add', data: info});
|
client.write({
|
||||||
client.write({action: 'charts', data: Nodes.getCharts()});
|
action: 'add',
|
||||||
|
data: info
|
||||||
|
});
|
||||||
|
|
||||||
|
client.write({
|
||||||
|
action: 'charts',
|
||||||
|
data: Nodes.getCharts()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
spark.on('update', function(data)
|
spark.on('update', function(data)
|
||||||
{
|
{
|
||||||
if(typeof data.id !== 'undefined' && typeof data.stats !== 'undefined')
|
if( !_.isUndefined(data.id) && !_.isUndefined(data.stats) )
|
||||||
{
|
{
|
||||||
data.stats.latency = spark.latency;
|
data.stats.latency = spark.latency;
|
||||||
|
|
||||||
var stats = Nodes.update(data.id, data.stats);
|
var stats = Nodes.update(data.id, data.stats);
|
||||||
|
|
||||||
if(stats !== false)
|
if(stats !== false)
|
||||||
{
|
{
|
||||||
client.write({action: 'update', data: stats});
|
client.write({
|
||||||
client.write({action: 'charts', data: Nodes.getCharts()});
|
action: 'update',
|
||||||
}
|
data: stats
|
||||||
|
});
|
||||||
|
|
||||||
if(Nodes.getHistory().requiresUpdate() && Nodes.canNodeUpdate(data.id) && (!askedForHistory || (new Date()).getTime() - askedForHistoryTime > 120000))
|
client.write({
|
||||||
{
|
action: 'charts',
|
||||||
var range = Nodes.getHistory().getHistoryRequestInterval();
|
data: Nodes.getCharts()
|
||||||
console.log("asked " + data.id + " for history");
|
});
|
||||||
console.log('interval', range);
|
|
||||||
spark.emit('history', range);
|
|
||||||
askedForHistory = true;
|
|
||||||
askedForHistoryTime = (new Date()).getTime();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
spark.on('history', function(data){
|
spark.on('history', function(data)
|
||||||
|
{
|
||||||
console.log("got history from " + data.id);
|
console.log("got history from " + data.id);
|
||||||
client.write({action: 'charts', data: Nodes.addHistory(data.id, data.history)});
|
|
||||||
|
client.write({
|
||||||
|
action: 'charts',
|
||||||
|
data: Nodes.addHistory(data.id, data.history)
|
||||||
|
});
|
||||||
|
|
||||||
askedForHistory = false;
|
askedForHistory = false;
|
||||||
|
|
||||||
|
client.write({
|
||||||
|
action: 'charts',
|
||||||
|
data: Nodes.getCharts()
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
spark.on('node-ping', function(data)
|
spark.on('node-ping', function(data)
|
||||||
@ -107,20 +124,25 @@ api.on('connection', function(spark) {
|
|||||||
|
|
||||||
spark.on('latency', function(data)
|
spark.on('latency', function(data)
|
||||||
{
|
{
|
||||||
if(typeof data.id !== 'undefined')
|
if( !_.isUndefined(data.id) )
|
||||||
{
|
{
|
||||||
var stats = Nodes.updateLatency(data.id, data.latency);
|
var stats = Nodes.updateLatency(data.id, data.latency);
|
||||||
|
|
||||||
client.write({action: 'latency', data: stats});
|
client.write({
|
||||||
|
action: 'latency',
|
||||||
|
data: stats
|
||||||
|
});
|
||||||
|
|
||||||
if(Nodes.getHistory().requiresUpdate() && Nodes.canNodeUpdate(data.id) && (!askedForHistory || (new Date()).getTime() - askedForHistoryTime > 120000))
|
if( Nodes.requiresUpdate(data.id) && (!askedForHistory || _.now() - askedForHistoryTime > 200000) )
|
||||||
{
|
{
|
||||||
var range = Nodes.getHistory().getHistoryRequestInterval();
|
var range = Nodes.getHistory().getHistoryRequestRange();
|
||||||
console.log("asked " + data.id + " for history");
|
|
||||||
console.log('interval', range);
|
console.log("asked " + data.id + " for history: " + range.min + " - " + range.max);
|
||||||
|
|
||||||
spark.emit('history', range);
|
spark.emit('history', range);
|
||||||
|
|
||||||
askedForHistory = true;
|
askedForHistory = true;
|
||||||
askedForHistoryTime = (new Date()).getTime();
|
askedForHistoryTime = _.now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -129,26 +151,38 @@ api.on('connection', function(spark) {
|
|||||||
{
|
{
|
||||||
var stats = Nodes.inactive(spark.id);
|
var stats = Nodes.inactive(spark.id);
|
||||||
|
|
||||||
client.write({action: 'inactive', data: stats});
|
client.write({
|
||||||
|
action: 'inactive',
|
||||||
|
data: stats
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('connection', function(spark) {
|
client.on('connection', function(clientSpark)
|
||||||
spark.on('ready', function(data){
|
{
|
||||||
spark.emit('init', {nodes: Nodes.all()});
|
clientSpark.on('ready', function(data)
|
||||||
|
{
|
||||||
|
clientSpark.emit('init', { nodes: Nodes.all() });
|
||||||
|
|
||||||
spark.write({action: 'charts', data: Nodes.getCharts()});
|
clientSpark.write({
|
||||||
|
action: 'charts',
|
||||||
|
data: Nodes.getCharts()
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
spark.on('client-pong', function(data) {
|
clientSpark.on('client-pong', function(data)
|
||||||
var latency = Math.ceil(((new Date()).getTime() - clientLatency)/2);
|
{
|
||||||
spark.emit('client-latency', { latency: latency });
|
var latency = Math.ceil( (_.now() - clientLatency) / 2 );
|
||||||
|
|
||||||
|
clientSpark.emit('client-latency', { latency: latency });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var latencyTimeout = setInterval(function(){
|
var latencyTimeout = setInterval( function ()
|
||||||
clientLatency = (new Date()).getTime();
|
{
|
||||||
client.write({action: 'client-ping'});
|
clientLatency = _.now();
|
||||||
|
|
||||||
|
client.write({ action: 'client-ping' });
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
// view engine setup
|
// view engine setup
|
||||||
|
@ -4,9 +4,8 @@ var Node = require('./node');
|
|||||||
|
|
||||||
var Collection = function Collection()
|
var Collection = function Collection()
|
||||||
{
|
{
|
||||||
this._list = [];
|
this._items = [];
|
||||||
this._history = new Blockchain();
|
this._blockchain = new Blockchain();
|
||||||
this._bestBlock = null;
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -26,12 +25,12 @@ Collection.prototype.update = function(id, stats)
|
|||||||
if(!node)
|
if(!node)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var block = this._history.add(stats.block, id);
|
var block = this._blockchain.add(stats.block, id);
|
||||||
|
|
||||||
if(! block)
|
if(! block)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var propagationHistory = this._history.getNodePropagation(id);
|
var propagationHistory = this._blockchain.getNodePropagation(id);
|
||||||
|
|
||||||
stats.block.arrived = block.arrived;
|
stats.block.arrived = block.arrived;
|
||||||
stats.block.received = block.received;
|
stats.block.received = block.received;
|
||||||
@ -47,8 +46,11 @@ Collection.prototype.addHistory = function(id, blocks)
|
|||||||
if(!node)
|
if(!node)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (var i = blocks.length - 1; i >= 0; i--) {
|
blocks = blocks.reverse();
|
||||||
this._history.add(blocks[i], id);
|
|
||||||
|
for (var i = 0; i <= blocks.length - 1; i++)
|
||||||
|
{
|
||||||
|
this._blockchain.add(blocks[i], id);
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.getCharts();
|
return this.getCharts();
|
||||||
@ -78,7 +80,7 @@ Collection.prototype.inactive = function(id)
|
|||||||
|
|
||||||
Collection.prototype.getIndex = function(search)
|
Collection.prototype.getIndex = function(search)
|
||||||
{
|
{
|
||||||
return _.findIndex(this._list, search);
|
return _.findIndex(this._items, search);
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection.prototype.getNode = function(search)
|
Collection.prototype.getNode = function(search)
|
||||||
@ -86,15 +88,15 @@ Collection.prototype.getNode = function(search)
|
|||||||
var index = this.getIndex(search);
|
var index = this.getIndex(search);
|
||||||
|
|
||||||
if(index >= 0)
|
if(index >= 0)
|
||||||
return this._list[index];
|
return this._items[index];
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection.prototype.getNodeByIndex = function(index)
|
Collection.prototype.getNodeByIndex = function(index)
|
||||||
{
|
{
|
||||||
if(this._list[index])
|
if(this._items[index])
|
||||||
return this._list[index];
|
return this._items[index];
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -103,7 +105,7 @@ Collection.prototype.getIndexOrNew = function(search, data)
|
|||||||
{
|
{
|
||||||
var index = this.getIndex(search);
|
var index = this.getIndex(search);
|
||||||
|
|
||||||
return (index >= 0 ? index : this._list.push(new Node(data)) - 1);
|
return (index >= 0 ? index : this._items.push(new Node(data)) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection.prototype.getNodeOrNew = function(search, data)
|
Collection.prototype.getNodeOrNew = function(search, data)
|
||||||
@ -113,27 +115,27 @@ Collection.prototype.getNodeOrNew = function(search, data)
|
|||||||
|
|
||||||
Collection.prototype.all = function()
|
Collection.prototype.all = function()
|
||||||
{
|
{
|
||||||
return this._list;
|
return this._items;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection.prototype.blockPropagationChart = function()
|
Collection.prototype.blockPropagationChart = function()
|
||||||
{
|
{
|
||||||
return this._history.getBlockPropagation();
|
return this._blockchain.getBlockPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection.prototype.getUncleCount = function()
|
Collection.prototype.getUncleCount = function()
|
||||||
{
|
{
|
||||||
return this._history.getUncleCount();
|
return this._blockchain.getUncleCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection.prototype.getCharts = function()
|
Collection.prototype.getCharts = function()
|
||||||
{
|
{
|
||||||
return this._history.getCharts();
|
return this._blockchain.getCharts();
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection.prototype.getHistory = function()
|
Collection.prototype.getHistory = function()
|
||||||
{
|
{
|
||||||
return this._history;
|
return this._blockchain;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection.prototype.canNodeUpdate = function(id)
|
Collection.prototype.canNodeUpdate = function(id)
|
||||||
@ -145,13 +147,17 @@ Collection.prototype.canNodeUpdate = function(id)
|
|||||||
|
|
||||||
if(node.canUpdate())
|
if(node.canUpdate())
|
||||||
{
|
{
|
||||||
var diff = this._history.bestBlockNumber() - node.getBlockNumber();
|
var diff = this._blockchain.bestBlockNumber() - node.getBlockNumber();
|
||||||
|
|
||||||
if(diff <= 0)
|
return (diff <= 0);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collection.prototype.requiresUpdate = function(id)
|
||||||
|
{
|
||||||
|
return ( this.canNodeUpdate(id) && this._blockchain.requiresUpdate() );
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = Collection;
|
module.exports = Collection;
|
@ -33,26 +33,30 @@ var History = function History(data)
|
|||||||
|
|
||||||
History.prototype.add = function(block, id)
|
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')
|
if( !_.isUndefined(block) && !_.isUndefined(block.number) && !_.isUndefined(block.uncles) && !_.isUndefined(block.transactions) && !_.isUndefined(block.difficulty) && block.number > 0 )
|
||||||
{
|
{
|
||||||
var historyBlock = this.search(block.number);
|
var historyBlock = this.search(block.number);
|
||||||
|
|
||||||
var now = (new Date()).getTime();
|
var now = _.now();
|
||||||
block.arrived = now;
|
block.arrived = now;
|
||||||
block.received = now;
|
block.received = now;
|
||||||
block.propagation = 0;
|
block.propagation = 0;
|
||||||
|
|
||||||
if(historyBlock)
|
if( historyBlock )
|
||||||
{
|
{
|
||||||
var propIndex = _.findIndex(historyBlock.propagTimes, {node: id});
|
var propIndex = _.findIndex( historyBlock.propagTimes, { node: id } );
|
||||||
|
|
||||||
if(propIndex === -1)
|
if( propIndex === -1 )
|
||||||
{
|
{
|
||||||
block.arrived = historyBlock.block.arrived;
|
block.arrived = historyBlock.block.arrived;
|
||||||
block.received = now;
|
block.received = now;
|
||||||
block.propagation = now - historyBlock.block.received;
|
block.propagation = now - historyBlock.block.received;
|
||||||
|
|
||||||
historyBlock.propagTimes.push({node: id, received: now, propagation: block.propagation});
|
historyBlock.propagTimes.push({
|
||||||
|
node: id,
|
||||||
|
received: now,
|
||||||
|
propagation: block.propagation
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -65,26 +69,32 @@ History.prototype.add = function(block, id)
|
|||||||
{
|
{
|
||||||
var prevBlock = this.prevMaxBlock(block.number);
|
var prevBlock = this.prevMaxBlock(block.number);
|
||||||
|
|
||||||
if(prevBlock)
|
if( prevBlock )
|
||||||
{
|
{
|
||||||
block.time = block.arrived - prevBlock.block.arrived;
|
block.time = block.arrived - prevBlock.block.arrived;
|
||||||
|
|
||||||
if(block.number < this.bestBlock().height)
|
if(block.number < this.bestBlock().height)
|
||||||
block.time = (block.timestamp - prevBlock.block.timestamp)*1000;
|
block.time = (block.timestamp - prevBlock.block.timestamp) * 1000;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
block.time = 0;
|
block.time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var item = {
|
var item = {
|
||||||
height: block.number,
|
height: block.number,
|
||||||
block: block,
|
block: block,
|
||||||
propagTimes: []
|
propagTimes: []
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this._items.length === 0 || block.number >= (this.bestBlock().height - MAX_HISTORY + 1))
|
if( this._items.length === 0 || block.number >= (this.bestBlockNumber() - MAX_HISTORY + 1) )
|
||||||
{
|
{
|
||||||
item.propagTimes.push({node: id, received: now, propagation: block.propagation});
|
item.propagTimes.push({
|
||||||
|
node: id,
|
||||||
|
received: now,
|
||||||
|
propagation: block.propagation
|
||||||
|
});
|
||||||
|
|
||||||
this._save(item);
|
this._save(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,16 +109,17 @@ History.prototype._save = function(block)
|
|||||||
{
|
{
|
||||||
this._items.unshift(block);
|
this._items.unshift(block);
|
||||||
|
|
||||||
if(this._items.length > MAX_HISTORY){
|
if(this._items.length > MAX_HISTORY)
|
||||||
|
{
|
||||||
this._items.pop();
|
this._items.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._items = _.sortByOrder(this._items, 'height', false);
|
this._items = _.sortByOrder( this._items, 'height', false );
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.search = function(number)
|
History.prototype.search = function(number)
|
||||||
{
|
{
|
||||||
var index = _.findIndex(this._items, {height: number});
|
var index = _.findIndex( this._items, { height: number } );
|
||||||
|
|
||||||
if(index < 0)
|
if(index < 0)
|
||||||
return false;
|
return false;
|
||||||
@ -118,7 +129,7 @@ History.prototype.search = function(number)
|
|||||||
|
|
||||||
History.prototype.prevMaxBlock = function(number)
|
History.prototype.prevMaxBlock = function(number)
|
||||||
{
|
{
|
||||||
var index = _.findIndex(this._items, function(item) {
|
var index = _.findIndex(this._items, function (item) {
|
||||||
return item.height < number;
|
return item.height < number;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -137,7 +148,7 @@ History.prototype.bestBlockNumber = function()
|
|||||||
{
|
{
|
||||||
var best = this.bestBlock();
|
var best = this.bestBlock();
|
||||||
|
|
||||||
if(typeof best.height !== 'undefined')
|
if( !_.isUndefined(best.height) )
|
||||||
return best.height;
|
return best.height;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -145,23 +156,22 @@ History.prototype.bestBlockNumber = function()
|
|||||||
|
|
||||||
History.prototype.getNodePropagation = function(id)
|
History.prototype.getNodePropagation = function(id)
|
||||||
{
|
{
|
||||||
var propagation = new Array(MAX_PEER_PROPAGATION);
|
var propagation = new Array( MAX_PEER_PROPAGATION );
|
||||||
var bestBlock = this.bestBlock().height;
|
var bestBlock = this.bestBlockNumber();
|
||||||
|
|
||||||
|
|
||||||
_.fill(propagation, -1);
|
_.fill(propagation, -1);
|
||||||
|
|
||||||
var sorted = _(this._items)
|
var sorted = _( this._items )
|
||||||
.sortByOrder('height', false)
|
.sortByOrder( 'height', false )
|
||||||
.slice(0, MAX_PEER_PROPAGATION)
|
.slice( 0, MAX_PEER_PROPAGATION )
|
||||||
.reverse()
|
.reverse()
|
||||||
.forEach(function(n, key)
|
.forEach(function (item, key)
|
||||||
{
|
{
|
||||||
var index = MAX_PEER_PROPAGATION - 1 - bestBlock + n.height;
|
var index = MAX_PEER_PROPAGATION - 1 - bestBlock + item.height;
|
||||||
|
|
||||||
if(index > 0)
|
if(index > 0)
|
||||||
{
|
{
|
||||||
propagation[index] = _.result(_.find(n.propagTimes, 'node', id), 'propagation', -1);
|
propagation[index] = _.result(_.find(item.propagTimes, 'node', id), 'propagation', -1);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.value();
|
.value();
|
||||||
@ -174,9 +184,9 @@ History.prototype.getBlockPropagation = function()
|
|||||||
var propagation = [];
|
var propagation = [];
|
||||||
var avgPropagation = 0;
|
var avgPropagation = 0;
|
||||||
|
|
||||||
_.forEach(this._items, function(n, key)
|
_.forEach(this._items, function (n, key)
|
||||||
{
|
{
|
||||||
_.forEach(n.propagTimes, function(p, i)
|
_.forEach(n.propagTimes, function (p, i)
|
||||||
{
|
{
|
||||||
var prop = _.result(p, 'propagation', -1);
|
var prop = _.result(p, 'propagation', -1);
|
||||||
|
|
||||||
@ -187,57 +197,69 @@ History.prototype.getBlockPropagation = function()
|
|||||||
|
|
||||||
if(propagation.length > 0)
|
if(propagation.length > 0)
|
||||||
{
|
{
|
||||||
var avgPropagation = Math.round(_.sum(propagation) / propagation.length);
|
var avgPropagation = Math.round( _.sum(propagation) / propagation.length );
|
||||||
}
|
}
|
||||||
|
|
||||||
var x = d3.scale.linear()
|
var x = d3.scale.linear()
|
||||||
.domain([MIN_PROPAGATION_RANGE, MAX_PROPAGATION_RANGE])
|
.domain([ MIN_PROPAGATION_RANGE, MAX_PROPAGATION_RANGE ])
|
||||||
.interpolate(d3.interpolateRound);
|
.interpolate( d3.interpolateRound );
|
||||||
|
|
||||||
var data = d3.layout.histogram()
|
var data = d3.layout.histogram()
|
||||||
.frequency(false)
|
.frequency( false )
|
||||||
.bins(x.ticks(MAX_BINS))
|
.bins( x.ticks(MAX_BINS) )
|
||||||
(propagation);
|
( propagation );
|
||||||
|
|
||||||
var freqCum = 0;
|
var freqCum = 0;
|
||||||
var histogram = data.map(function(val) {
|
var histogram = data.map(function (val) {
|
||||||
freqCum += val.length;
|
freqCum += val.length;
|
||||||
var cumPercent = (freqCum / Math.max(1, propagation.length));
|
var cumPercent = ( freqCum / Math.max(1, propagation.length) );
|
||||||
return {x: val.x, dx: val.dx, y: val.y, frequency: val.length, cumulative: freqCum, cumpercent: cumPercent};
|
|
||||||
|
return {
|
||||||
|
x: val.x,
|
||||||
|
dx: val.dx,
|
||||||
|
y: val.y,
|
||||||
|
frequency: val.length,
|
||||||
|
cumulative: freqCum,
|
||||||
|
cumpercent: cumPercent
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return {histogram: histogram, avg: avgPropagation};
|
return {
|
||||||
|
histogram: histogram,
|
||||||
|
avg: avgPropagation
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.getUncleCount = function()
|
History.prototype.getUncleCount = function()
|
||||||
{
|
{
|
||||||
var uncles = _(this._items)
|
var uncles = _( this._items )
|
||||||
.sortByOrder('height', false)
|
.sortByOrder( 'height', false )
|
||||||
.map(function(item)
|
.map(function (item)
|
||||||
{
|
{
|
||||||
return item.block.uncles.length;
|
return item.block.uncles.length;
|
||||||
})
|
})
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
var uncleBins = _.fill(Array(MAX_BINS), 0);
|
var uncleBins = _.fill( Array(MAX_BINS), 0 );
|
||||||
|
|
||||||
var sumMapper = function(array, key) {
|
var sumMapper = function (array, key)
|
||||||
|
{
|
||||||
uncleBins[key] = _.sum(array);
|
uncleBins[key] = _.sum(array);
|
||||||
return _.sum(array);
|
return _.sum(array);
|
||||||
};
|
};
|
||||||
|
|
||||||
_.map(_.chunk(uncles, MAX_UNCLES_PER_BIN), sumMapper);
|
_.map(_.chunk( uncles, MAX_UNCLES_PER_BIN ), sumMapper);
|
||||||
|
|
||||||
return uncleBins;
|
return uncleBins;
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.getBlockTimes = function()
|
History.prototype.getBlockTimes = function()
|
||||||
{
|
{
|
||||||
var blockTimes = _(this._items)
|
var blockTimes = _( this._items )
|
||||||
.sortByOrder('height', false)
|
.sortByOrder( 'height', false )
|
||||||
.slice(0, MAX_BINS)
|
.slice(0, MAX_BINS)
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(function(item)
|
.map(function (item)
|
||||||
{
|
{
|
||||||
return item.block.time;
|
return item.block.time;
|
||||||
})
|
})
|
||||||
@ -248,11 +270,11 @@ History.prototype.getBlockTimes = function()
|
|||||||
|
|
||||||
History.prototype.getDifficulty = function()
|
History.prototype.getDifficulty = function()
|
||||||
{
|
{
|
||||||
var difficultyHistory = _(this._items)
|
var difficultyHistory = _( this._items )
|
||||||
.sortByOrder('height', false)
|
.sortByOrder( 'height', false )
|
||||||
.slice(0, MAX_BINS)
|
.slice(0, MAX_BINS)
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(function(item)
|
.map(function (item)
|
||||||
{
|
{
|
||||||
return item.block.difficulty;
|
return item.block.difficulty;
|
||||||
})
|
})
|
||||||
@ -263,11 +285,11 @@ History.prototype.getDifficulty = function()
|
|||||||
|
|
||||||
History.prototype.getTransactionsCount = function()
|
History.prototype.getTransactionsCount = function()
|
||||||
{
|
{
|
||||||
var txCount = _(this._items)
|
var txCount = _( this._items )
|
||||||
.sortByOrder('height', false)
|
.sortByOrder( 'height', false )
|
||||||
.slice(0, MAX_BINS)
|
.slice(0, MAX_BINS)
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(function(item)
|
.map(function (item)
|
||||||
{
|
{
|
||||||
return item.block.transactions.length;
|
return item.block.transactions.length;
|
||||||
})
|
})
|
||||||
@ -278,11 +300,11 @@ History.prototype.getTransactionsCount = function()
|
|||||||
|
|
||||||
History.prototype.getGasSpending = function()
|
History.prototype.getGasSpending = function()
|
||||||
{
|
{
|
||||||
var gasSpending = _(this._items)
|
var gasSpending = _( this._items )
|
||||||
.sortByOrder('height', false)
|
.sortByOrder( 'height', false )
|
||||||
.slice(0, MAX_BINS)
|
.slice(0, MAX_BINS)
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(function(item)
|
.map(function (item)
|
||||||
{
|
{
|
||||||
return item.block.gasUsed;
|
return item.block.gasUsed;
|
||||||
})
|
})
|
||||||
@ -293,85 +315,113 @@ History.prototype.getGasSpending = function()
|
|||||||
|
|
||||||
History.prototype.getAvgHashrate = function()
|
History.prototype.getAvgHashrate = function()
|
||||||
{
|
{
|
||||||
if(this._items.length === 0)
|
if( _.isEmpty(this._items) )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var difficultyHistory = _(this._items)
|
var difficultyHistory = _( this._items )
|
||||||
.map(function(item)
|
.map(function (item)
|
||||||
{
|
{
|
||||||
return item.block.difficulty;
|
return item.block.difficulty;
|
||||||
})
|
})
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
var avgDifficulty = _.sum(difficultyHistory)/difficultyHistory.length;
|
var avgDifficulty = _.sum(difficultyHistory) / difficultyHistory.length;
|
||||||
|
|
||||||
var blocktimeHistory = _(this._items)
|
var blocktimeHistory = _( this._items )
|
||||||
.map(function(item)
|
.map(function (item)
|
||||||
{
|
{
|
||||||
return item.block.time;
|
return item.block.time;
|
||||||
})
|
})
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
var avgBlocktime = _.sum(blocktimeHistory)/blocktimeHistory.length;
|
var avgBlocktime = _.sum(blocktimeHistory) / blocktimeHistory.length;
|
||||||
|
|
||||||
return avgDifficulty/1000 * 12 * (12/avgBlocktime);
|
return avgDifficulty / 1000 * 12 * ( 12 / avgBlocktime );
|
||||||
|
}
|
||||||
|
|
||||||
|
History.prototype.getMinersCount = function()
|
||||||
|
{
|
||||||
|
var miners = _( this._items )
|
||||||
|
.sortByOrder( 'height', false )
|
||||||
|
.slice(0, MAX_BINS)
|
||||||
|
.map(function (item)
|
||||||
|
{
|
||||||
|
return item.block.miner;
|
||||||
|
})
|
||||||
|
.value();
|
||||||
|
|
||||||
|
var minerCount = [];
|
||||||
|
|
||||||
|
_.forEach( _.countBy(miners), function (cnt, miner)
|
||||||
|
{
|
||||||
|
minerCount.push({ miner: miner, name: false, blocks: cnt });
|
||||||
|
});
|
||||||
|
|
||||||
|
return _(minerCount)
|
||||||
|
.sortByOrder( 'blocks', false )
|
||||||
|
.slice(0, 5)
|
||||||
|
.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.getCharts = function()
|
History.prototype.getCharts = function()
|
||||||
{
|
{
|
||||||
var chartHistory = _(this._items)
|
var chartHistory = _( this._items )
|
||||||
.sortByOrder('height', false)
|
.sortByOrder( 'height', false )
|
||||||
.slice(0, MAX_BINS)
|
.slice(0, MAX_BINS)
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(function(item)
|
.map(function (item)
|
||||||
{
|
{
|
||||||
var chart = {
|
return {
|
||||||
height: item.height,
|
height: item.height,
|
||||||
blocktime: item.block.time/1000,
|
blocktime: item.block.time / 1000,
|
||||||
difficulty: item.block.difficulty,
|
difficulty: item.block.difficulty,
|
||||||
uncles: item.block.uncles.length,
|
uncles: item.block.uncles.length,
|
||||||
transactions: item.block.transactions.length,
|
transactions: item.block.transactions.length,
|
||||||
gasSpending: item.block.gasUsed
|
gasSpending: item.block.gasUsed,
|
||||||
}
|
miner: item.block.miner
|
||||||
return chart;
|
};
|
||||||
})
|
})
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
var chart = {
|
return {
|
||||||
height: _.pluck(chartHistory, 'height'),
|
height : _.pluck( chartHistory, 'height' ),
|
||||||
blocktime: _.pluck(chartHistory, 'blocktime'),
|
blocktime : _.pluck( chartHistory, 'blocktime' ),
|
||||||
avgBlocktime: _.sum(_.pluck(chartHistory, 'blocktime')) / (chartHistory.length === 0 ? 1 : chartHistory.length),
|
avgBlocktime : _.sum(_.pluck( chartHistory, 'blocktime' )) / (chartHistory.length === 0 ? 1 : chartHistory.length),
|
||||||
difficulty: _.pluck(chartHistory, 'difficulty'),
|
difficulty : _.pluck( chartHistory, 'difficulty' ),
|
||||||
uncles: _.pluck(chartHistory, 'uncles'),
|
uncles : _.pluck( chartHistory, 'uncles' ),
|
||||||
transactions: _.pluck(chartHistory, 'transactions'),
|
transactions : _.pluck( chartHistory, 'transactions' ),
|
||||||
gasSpending: _.pluck(chartHistory, 'gasSpending'),
|
gasSpending : _.pluck( chartHistory, 'gasSpending' ),
|
||||||
propagation: this.getBlockPropagation(),
|
miners : this.getMinersCount(),
|
||||||
uncleCount: this.getUncleCount(),
|
propagation : this.getBlockPropagation(),
|
||||||
avgHashrate: this.getAvgHashrate()
|
uncleCount : this.getUncleCount(),
|
||||||
}
|
avgHashrate : this.getAvgHashrate()
|
||||||
|
};
|
||||||
return chart;
|
|
||||||
}
|
|
||||||
|
|
||||||
History.prototype.history = function()
|
|
||||||
{
|
|
||||||
return this._items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.requiresUpdate = function()
|
History.prototype.requiresUpdate = function()
|
||||||
{
|
{
|
||||||
return ! (this._items.length === MAX_HISTORY);
|
return ( this._items.length < MAX_HISTORY && !_.isEmpty(this._items) );
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.getHistoryRequestInterval = function()
|
History.prototype.getHistoryRequestRange = function()
|
||||||
{
|
{
|
||||||
if(this._items.length === 0)
|
if( _.isEmpty(this._items) )
|
||||||
return null;
|
return false;
|
||||||
|
|
||||||
var max = _.min(this._items, 'height').height - 1;
|
var blocks = _.pluck( this._items, 'height' );
|
||||||
var min = max - Math.min(50, (MAX_HISTORY - this._items.length + 1)) + 1;
|
var best = _.max( blocks );
|
||||||
|
var range = _.range( _.max([ 0, best - MAX_HISTORY ]), best + 1);
|
||||||
|
|
||||||
return {max: max, min: min};
|
var missing = _.difference( range, blocks );
|
||||||
|
|
||||||
|
var max = _.max(missing);
|
||||||
|
var min = max - Math.min( 50, (MAX_HISTORY - this._items.length + 1) ) + 1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
max: max,
|
||||||
|
min: min,
|
||||||
|
list: _( missing ).reverse().slice(0, 50).reverse().value()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = History;
|
module.exports = History;
|
||||||
|
102
models/node.js
102
models/node.js
@ -20,93 +20,103 @@ var Node = function Node(data)
|
|||||||
number: 0,
|
number: 0,
|
||||||
gasLimit: 0,
|
gasLimit: 0,
|
||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
|
time: 0,
|
||||||
arrival: 0,
|
arrival: 0,
|
||||||
propagation: 0,
|
propagation: 0,
|
||||||
received: 0,
|
received: 0,
|
||||||
transactions: [],
|
transactions: [],
|
||||||
uncles: []
|
uncles: []
|
||||||
},
|
},
|
||||||
blocktimeAvg: 0,
|
|
||||||
propagationAvg: 0,
|
propagationAvg: 0,
|
||||||
blockTimes: [],
|
|
||||||
difficulty: [],
|
|
||||||
latency: 0,
|
latency: 0,
|
||||||
uptime: 0,
|
uptime: 0,
|
||||||
lastUpdate: 0
|
lastUpdate: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
this.history = new Array(MAX_HISTORY);
|
this.history = new Array(MAX_HISTORY);
|
||||||
|
|
||||||
this.uptime = {
|
this.uptime = {
|
||||||
started: null,
|
started: null,
|
||||||
history: []
|
history: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.init(data);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node.prototype.init = function(data)
|
||||||
|
{
|
||||||
_.fill(this.history, -1);
|
_.fill(this.history, -1);
|
||||||
|
|
||||||
if(this.id === null) {
|
if( this.id === null )
|
||||||
this.uptime.started = (new Date()).getTime();
|
{
|
||||||
|
this.uptime.started = _.now();
|
||||||
this.setState(true);
|
this.setState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof data.id !== 'undefined')
|
if( !_.isUndefined(data.id) )
|
||||||
this.id = data.id;
|
this.id = data.id;
|
||||||
|
|
||||||
if(typeof data.info !== 'undefined') {
|
this.setInfo(data);
|
||||||
this.info = data.info;
|
|
||||||
|
|
||||||
if(typeof data.info.canUpdateHistory === 'undefined')
|
if( !_.isUndefined(data.latency) )
|
||||||
data.info.canUpdateHistory = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof data.ip !== 'undefined'){
|
|
||||||
if(data.ip === '::ffff:127.0.0.1')
|
|
||||||
data.ip = '84.117.82.122';
|
|
||||||
this.info.ip = data.ip;
|
|
||||||
this.setGeo(data.ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof data.spark !== 'undefined')
|
|
||||||
this.spark = data.spark;
|
|
||||||
|
|
||||||
if(typeof data.latency !== 'undefined')
|
|
||||||
this.stats.latency = data.latency;
|
this.stats.latency = data.latency;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node.prototype.setGeo = function(ip)
|
|
||||||
{
|
|
||||||
this.geo = geoip.lookup(ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node.prototype.setInfo = function(data)
|
Node.prototype.setInfo = function(data)
|
||||||
{
|
{
|
||||||
if(typeof data.info !== 'undefined') {
|
if( !_.isUndefined(data.info) )
|
||||||
|
{
|
||||||
this.info = data.info;
|
this.info = data.info;
|
||||||
|
|
||||||
if(typeof data.info.canUpdateHistory === 'undefined')
|
if( _.isUndefined(data.info.canUpdateHistory) )
|
||||||
data.info.canUpdateHistory = false;
|
data.info.canUpdateHistory = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof data.ip !== 'undefined'){
|
if( !_.isUndefined(data.ip) )
|
||||||
|
{
|
||||||
|
if(data.ip === '::ffff:127.0.0.1')
|
||||||
|
data.ip = '84.117.82.122';
|
||||||
|
|
||||||
this.info.ip = data.ip;
|
this.info.ip = data.ip;
|
||||||
this.setGeo(data.ip);
|
this.setGeo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof data.spark !== 'undefined')
|
if( !_.isUndefined(data.spark) )
|
||||||
this.spark = data.spark;
|
this.spark = data.spark;
|
||||||
|
|
||||||
if(this.uptime.history.length > 0 && this.uptime.history[this.uptime.history.length - 1].status == 'down')
|
var uptimeCnt = this.uptime.history.length;
|
||||||
|
|
||||||
|
if( uptimeCnt > 0 && this.uptime.history[uptimeCnt - 1].status === 'down' )
|
||||||
this.setState(true);
|
this.setState(true);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node.prototype.setGeo = function()
|
||||||
|
{
|
||||||
|
this.geo = geoip.lookup(this.info.ip);
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node.prototype.getInfo = function()
|
Node.prototype.getInfo = function()
|
||||||
{
|
{
|
||||||
return {id: this.id, info: this.info, geo: this.geo, stats: this.stats, history: this.history};
|
return {
|
||||||
|
id: this.id,
|
||||||
|
info: this.info,
|
||||||
|
geo: this.geo,
|
||||||
|
stats: this.stats,
|
||||||
|
history: this.history
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Node.prototype.setStats = function(stats, history)
|
Node.prototype.setStats = function(stats, history)
|
||||||
{
|
{
|
||||||
if(typeof stats !== 'undefined' && typeof stats.block !== 'undefined' && typeof stats.block.number !== 'undefined')
|
if( !_.isUndefined(stats) && !_.isUndefined(stats.block) && !_.isUndefined(stats.block.number) )
|
||||||
{
|
{
|
||||||
this.history = history;
|
this.history = history;
|
||||||
|
|
||||||
@ -115,7 +125,7 @@ Node.prototype.setStats = function(stats, history)
|
|||||||
});
|
});
|
||||||
|
|
||||||
if(positives.length > 0)
|
if(positives.length > 0)
|
||||||
stats.propagationAvg = Math.round(_.sum(positives)/positives.length);
|
stats.propagationAvg = Math.round( _.sum(positives) / positives.length );
|
||||||
else
|
else
|
||||||
stats.propagationAvg = 0;
|
stats.propagationAvg = 0;
|
||||||
|
|
||||||
@ -129,11 +139,14 @@ Node.prototype.setStats = function(stats, history)
|
|||||||
|
|
||||||
Node.prototype.setLatency = function(latency)
|
Node.prototype.setLatency = function(latency)
|
||||||
{
|
{
|
||||||
if(typeof latency !== 'undefined')
|
if( !_.isUndefined(latency) )
|
||||||
{
|
{
|
||||||
this.stats.latency = latency;
|
this.stats.latency = latency;
|
||||||
|
|
||||||
return { id: this.id, latency: latency };
|
return {
|
||||||
|
id: this.id,
|
||||||
|
latency: latency
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -141,13 +154,20 @@ Node.prototype.setLatency = function(latency)
|
|||||||
|
|
||||||
Node.prototype.getStats = function()
|
Node.prototype.getStats = function()
|
||||||
{
|
{
|
||||||
return {id: this.id, stats: this.stats, history: this.history};
|
return {
|
||||||
|
id: this.id,
|
||||||
|
stats: this.stats,
|
||||||
|
history: this.history
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Node.prototype.setState = function(active)
|
Node.prototype.setState = function(active)
|
||||||
{
|
{
|
||||||
this.stats.active = active;
|
this.stats.active = active;
|
||||||
this.uptime.history.push({status: (active ? 'up' : 'down'), time: (new Date()).getTime()});
|
this.uptime.history.push({
|
||||||
|
status: (active ? 'up' : 'down'),
|
||||||
|
time: _.now()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Node.prototype.getBlockNumber = function()
|
Node.prototype.getBlockNumber = function()
|
||||||
|
@ -130,6 +130,13 @@ span.small-title span.small {
|
|||||||
font-size: 50px;
|
font-size: 50px;
|
||||||
line-height: 55px;
|
line-height: 55px;
|
||||||
letter-spacing: -4px;
|
letter-spacing: -4px;
|
||||||
|
word-spacing: nowrap !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-info .big-details-holder {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
left: 99px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.big-info.chart {
|
.big-info.chart {
|
||||||
|
@ -94,8 +94,8 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
|||||||
|
|
||||||
function socketAction(action, data)
|
function socketAction(action, data)
|
||||||
{
|
{
|
||||||
console.log('Action: ', action);
|
// console.log('Action: ', action);
|
||||||
console.log('Data: ', data);
|
// console.log('Data: ', data);
|
||||||
|
|
||||||
switch(action) {
|
switch(action) {
|
||||||
case "init":
|
case "init":
|
||||||
@ -155,16 +155,19 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "charts":
|
case "charts":
|
||||||
$scope.lastBlocksTime = data.blocktime;
|
|
||||||
$scope.avgBlockTime = data.avgBlocktime;
|
$scope.avgBlockTime = data.avgBlocktime;
|
||||||
$scope.avgHashrate = data.avgHashrate;
|
$scope.avgHashrate = data.avgHashrate;
|
||||||
|
$scope.lastBlocksTime = data.blocktime;
|
||||||
$scope.difficultyChart = data.difficulty;
|
$scope.difficultyChart = data.difficulty;
|
||||||
$scope.transactionDensity = data.transactions;
|
|
||||||
$scope.gasSpending = data.gasSpending;
|
|
||||||
$scope.blockPropagationChart = data.propagation.histogram;
|
$scope.blockPropagationChart = data.propagation.histogram;
|
||||||
$scope.blockPropagationAvg = data.propagation.avg;
|
$scope.blockPropagationAvg = data.propagation.avg;
|
||||||
$scope.uncleCountChart = data.uncleCount;
|
$scope.uncleCountChart = data.uncleCount;
|
||||||
$scope.uncleCount = data.uncleCount[0] + data.uncleCount[1];
|
$scope.uncleCount = data.uncleCount[0] + data.uncleCount[1];
|
||||||
|
$scope.transactionDensity = data.transactions;
|
||||||
|
$scope.gasSpending = data.gasSpending;
|
||||||
|
$scope.miners = data.miners;
|
||||||
|
|
||||||
|
getMinersNames();
|
||||||
|
|
||||||
jQuery('.spark-blocktimes').sparkline($scope.lastBlocksTime, {type: 'bar', tooltipSuffix: ' s'});
|
jQuery('.spark-blocktimes').sparkline($scope.lastBlocksTime, {type: 'bar', tooltipSuffix: ' s'});
|
||||||
jQuery('.spark-difficulty').sparkline($scope.difficultyChart, {type: 'bar'});
|
jQuery('.spark-difficulty').sparkline($scope.difficultyChart, {type: 'bar'});
|
||||||
@ -225,6 +228,23 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMinersNames()
|
||||||
|
{
|
||||||
|
if($scope.miners.length > 0)
|
||||||
|
{
|
||||||
|
_.forIn($scope.miners, function(value, key)
|
||||||
|
{
|
||||||
|
if(value.name !== false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var name = _.result(_.find(_.pluck($scope.nodes, 'info'), 'coinbase', value.miner), 'name');
|
||||||
|
|
||||||
|
if(typeof name !== 'undefined')
|
||||||
|
$scope.miners[key].name = name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addNewNode(data)
|
function addNewNode(data)
|
||||||
{
|
{
|
||||||
var index = findIndex({id: data.id});
|
var index = findIndex({id: data.id});
|
||||||
@ -267,22 +287,6 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
|||||||
|
|
||||||
$scope.lastBlock = $scope.bestStats.block.received;
|
$scope.lastBlock = $scope.bestStats.block.received;
|
||||||
$scope.lastDifficulty = $scope.bestStats.block.difficulty;
|
$scope.lastDifficulty = $scope.bestStats.block.difficulty;
|
||||||
|
|
||||||
if(typeof $scope.bestStats.miners !== 'undefined') {
|
|
||||||
$scope.miners = $scope.bestStats.miners;
|
|
||||||
console.log($scope.miners);
|
|
||||||
|
|
||||||
_.forIn($scope.miners, function(value, key)
|
|
||||||
{
|
|
||||||
if(value.name !== false)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var name = _.result(_.find(_.pluck($scope.nodes, 'info'), 'coinbase', value.miner), 'name');
|
|
||||||
|
|
||||||
if(typeof name !== 'undefined')
|
|
||||||
$scope.miners[key].name = name;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.upTimeTotal = _.reduce($scope.nodes, function(total, node) {
|
$scope.upTimeTotal = _.reduce($scope.nodes, function(total, node) {
|
||||||
|
@ -7,7 +7,7 @@ block content
|
|||||||
div.big-info.bestblock.text-info
|
div.big-info.bestblock.text-info
|
||||||
div.pull-left.icon-full-width
|
div.pull-left.icon-full-width
|
||||||
i.icon-block
|
i.icon-block
|
||||||
div.pull-left
|
div.big-details-holder
|
||||||
span.small-title best block
|
span.small-title best block
|
||||||
span.big-details {{'#'}}{{ bestBlock | number}}
|
span.big-details {{'#'}}{{ bestBlock | number}}
|
||||||
div.clearfix
|
div.clearfix
|
||||||
@ -15,7 +15,7 @@ block content
|
|||||||
div.big-info.uncleCount.text-info
|
div.big-info.uncleCount.text-info
|
||||||
div.pull-left.icon-full-width
|
div.pull-left.icon-full-width
|
||||||
i.icon-uncle
|
i.icon-uncle
|
||||||
div.pull-left
|
div.big-details-holder
|
||||||
span.small-title uncles #[ ]
|
span.small-title uncles #[ ]
|
||||||
span.small (current / last 50)
|
span.small (current / last 50)
|
||||||
span.big-details {{ bestStats.block.uncles.length }}/{{ uncleCount }}
|
span.big-details {{ bestStats.block.uncles.length }}/{{ uncleCount }}
|
||||||
@ -24,7 +24,7 @@ block content
|
|||||||
div.big-info.blocktime(class="{{ lastBlock | timeClass : true }}")
|
div.big-info.blocktime(class="{{ lastBlock | timeClass : true }}")
|
||||||
div.pull-left.icon-full-width
|
div.pull-left.icon-full-width
|
||||||
i.icon-time
|
i.icon-time
|
||||||
div.pull-left
|
div.big-details-holder
|
||||||
span.small-title last block
|
span.small-title last block
|
||||||
span.big-details {{ lastBlock | blockTimeFilter }}
|
span.big-details {{ lastBlock | blockTimeFilter }}
|
||||||
div.clearfix
|
div.clearfix
|
||||||
@ -32,7 +32,7 @@ block content
|
|||||||
div.big-info.avgblocktime(class="{{ avgBlockTime | avgTimeClass }}")
|
div.big-info.avgblocktime(class="{{ avgBlockTime | avgTimeClass }}")
|
||||||
div.pull-left.icon-full-width
|
div.pull-left.icon-full-width
|
||||||
i.icon-gas
|
i.icon-gas
|
||||||
div.pull-left
|
div.big-details-holder
|
||||||
span.small-title avg block time
|
span.small-title avg block time
|
||||||
span.big-details {{ avgBlockTime | avgTimeFilter }}
|
span.big-details {{ avgBlockTime | avgTimeFilter }}
|
||||||
div.clearfix
|
div.clearfix
|
||||||
@ -40,7 +40,7 @@ block content
|
|||||||
div.big-info.difficulty.text-orange
|
div.big-info.difficulty.text-orange
|
||||||
div.pull-left.icon-full-width
|
div.pull-left.icon-full-width
|
||||||
i.icon-hashrate
|
i.icon-hashrate
|
||||||
div.pull-left
|
div.big-details-holder
|
||||||
span.small-title avg network hashrate
|
span.small-title avg network hashrate
|
||||||
span.big-details {{ avgHashrate | number : 1 }} MH/s
|
span.big-details {{ avgHashrate | number : 1 }} MH/s
|
||||||
div.clearfix
|
div.clearfix
|
||||||
@ -48,7 +48,7 @@ block content
|
|||||||
div.big-info.difficulty.text-danger
|
div.big-info.difficulty.text-danger
|
||||||
div.pull-left.icon-full-width
|
div.pull-left.icon-full-width
|
||||||
i.icon-difficulty
|
i.icon-difficulty
|
||||||
div.pull-left
|
div.big-details-holder
|
||||||
span.small-title difficulty
|
span.small-title difficulty
|
||||||
span.big-details {{ lastDifficulty | number }}
|
span.big-details {{ lastDifficulty | number }}
|
||||||
div.clearfix
|
div.clearfix
|
||||||
|
Loading…
Reference in New Issue
Block a user