Feat/pool fee in api (#39)
* Initial poolFee commit This is defined by the following in the pool_config ``` "poolFee": 0.2, "_comment_poolFee": "This is only used for API purpose to display pool fee percentage", ``` * Added poolFee function This function looks at the user defined `poolFee` in their pool_config and if it doesn't exist it will calculate it based on `rewardRecipients` * Fix to show % * Added poolFee * Added poolFee * Added poolFee * Added poolFee * Added poolFee * Added poolFee * Added poolFee * Added poolFee * Added poolFee * Added poolFee * Added poolFee * Spacing fix * Changing gears -- instead of providing additional configuration, we're just going to expose the rewardRecipients. This allows the consuming client to filter community donation addresses, etc. as needed. In addition, I've replaced all tabs in libs/stats.js with spaces.
This commit is contained in:
parent
d7826dcad7
commit
250377de5a
535
libs/stats.js
535
libs/stats.js
|
@ -26,31 +26,31 @@ function rediscreateClient(port, host, pass) {
|
||||||
* @returns {Array} array of items in [[key,value],[key,value],...] format.
|
* @returns {Array} array of items in [[key,value],[key,value],...] format.
|
||||||
*/
|
*/
|
||||||
function sortProperties(obj, sortedBy, isNumericSort, reverse) {
|
function sortProperties(obj, sortedBy, isNumericSort, reverse) {
|
||||||
sortedBy = sortedBy || 1; // by default first key
|
sortedBy = sortedBy || 1; // by default first key
|
||||||
isNumericSort = isNumericSort || false; // by default text sort
|
isNumericSort = isNumericSort || false; // by default text sort
|
||||||
reverse = reverse || false; // by default no reverse
|
reverse = reverse || false; // by default no reverse
|
||||||
|
|
||||||
var reversed = (reverse) ? -1 : 1;
|
var reversed = (reverse) ? -1 : 1;
|
||||||
|
|
||||||
var sortable = [];
|
var sortable = [];
|
||||||
for (var key in obj) {
|
for (var key in obj) {
|
||||||
if (obj.hasOwnProperty(key)) {
|
if (obj.hasOwnProperty(key)) {
|
||||||
sortable.push([key, obj[key]]);
|
sortable.push([key, obj[key]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isNumericSort)
|
if (isNumericSort)
|
||||||
sortable.sort(function (a, b) {
|
sortable.sort(function (a, b) {
|
||||||
return reversed * (a[1][sortedBy] - b[1][sortedBy]);
|
return reversed * (a[1][sortedBy] - b[1][sortedBy]);
|
||||||
});
|
});
|
||||||
else
|
else
|
||||||
sortable.sort(function (a, b) {
|
sortable.sort(function (a, b) {
|
||||||
var x = a[1][sortedBy].toLowerCase(),
|
var x = a[1][sortedBy].toLowerCase(),
|
||||||
y = b[1][sortedBy].toLowerCase();
|
y = b[1][sortedBy].toLowerCase();
|
||||||
return x < y ? reversed * -1 : x > y ? reversed : 0;
|
return x < y ? reversed * -1 : x > y ? reversed : 0;
|
||||||
});
|
});
|
||||||
return sortable; // array in format [ [ key1, val1 ], [ key2, val2 ], ... ]
|
return sortable; // array in format [ [ key1, val1 ], [ key2, val2 ], ... ]
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(logger, portalConfig, poolConfigs){
|
module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
|
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
@ -104,17 +104,17 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
if (_this.stats.pools[pool.name].pending && _this.stats.pools[pool.name].pending.blocks)
|
if (_this.stats.pools[pool.name].pending && _this.stats.pools[pool.name].pending.blocks)
|
||||||
for (var i=0; i<_this.stats.pools[pool.name].pending.blocks.length; i++)
|
for (var i=0; i<_this.stats.pools[pool.name].pending.blocks.length; i++)
|
||||||
allBlocks[pool.name+"-"+_this.stats.pools[pool.name].pending.blocks[i].split(':')[2]] = _this.stats.pools[pool.name].pending.blocks[i];
|
allBlocks[pool.name+"-"+_this.stats.pools[pool.name].pending.blocks[i].split(':')[2]] = _this.stats.pools[pool.name].pending.blocks[i];
|
||||||
|
|
||||||
if (_this.stats.pools[pool.name].confirmed && _this.stats.pools[pool.name].confirmed.blocks)
|
if (_this.stats.pools[pool.name].confirmed && _this.stats.pools[pool.name].confirmed.blocks)
|
||||||
for (var i=0; i<_this.stats.pools[pool.name].confirmed.blocks.length; i++)
|
for (var i=0; i<_this.stats.pools[pool.name].confirmed.blocks.length; i++)
|
||||||
allBlocks[pool.name+"-"+_this.stats.pools[pool.name].confirmed.blocks[i].split(':')[2]] = _this.stats.pools[pool.name].confirmed.blocks[i];
|
allBlocks[pool.name+"-"+_this.stats.pools[pool.name].confirmed.blocks[i].split(':')[2]] = _this.stats.pools[pool.name].confirmed.blocks[i];
|
||||||
|
|
||||||
pcb();
|
pcb();
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
cback(allBlocks);
|
cback(allBlocks);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function gatherStatHistory(){
|
function gatherStatHistory(){
|
||||||
var retentionTime = (((Date.now() / 1000) - portalConfig.website.stats.historicalRetention) | 0).toString();
|
var retentionTime = (((Date.now() / 1000) - portalConfig.website.stats.historicalRetention) | 0).toString();
|
||||||
redisStats.zrangebyscore(['statHistory', retentionTime, '+inf'], function(err, replies){
|
redisStats.zrangebyscore(['statHistory', retentionTime, '+inf'], function(err, replies){
|
||||||
|
@ -134,34 +134,34 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWorkerStats(address) {
|
function getWorkerStats(address) {
|
||||||
address = address.split(".")[0];
|
address = address.split(".")[0];
|
||||||
if (address.length > 0 && address.startsWith('t')) {
|
if (address.length > 0 && address.startsWith('t')) {
|
||||||
for (var h in statHistory) {
|
for (var h in statHistory) {
|
||||||
for(var pool in statHistory[h].pools) {
|
for(var pool in statHistory[h].pools) {
|
||||||
|
|
||||||
statHistory[h].pools[pool].workers.sort(sortWorkersByHashrate);
|
statHistory[h].pools[pool].workers.sort(sortWorkersByHashrate);
|
||||||
|
|
||||||
|
for(var w in statHistory[h].pools[pool].workers){
|
||||||
|
if (w.startsWith(address)) {
|
||||||
|
if (history[w] == null) {
|
||||||
|
history[w] = [];
|
||||||
|
}
|
||||||
|
if (workers[w] == null && stats.pools[pool].workers[w] != null) {
|
||||||
|
workers[w] = stats.pools[pool].workers[w];
|
||||||
|
}
|
||||||
|
if (statHistory[h].pools[pool].workers[w].hashrate) {
|
||||||
|
history[w].push({time: statHistory[h].time, hashrate:statHistory[h].pools[pool].workers[w].hashrate});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JSON.stringify({"workers": workers, "history": history});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
for(var w in statHistory[h].pools[pool].workers){
|
|
||||||
if (w.startsWith(address)) {
|
|
||||||
if (history[w] == null) {
|
|
||||||
history[w] = [];
|
|
||||||
}
|
|
||||||
if (workers[w] == null && stats.pools[pool].workers[w] != null) {
|
|
||||||
workers[w] = stats.pools[pool].workers[w];
|
|
||||||
}
|
|
||||||
if (statHistory[h].pools[pool].workers[w].hashrate) {
|
|
||||||
history[w].push({time: statHistory[h].time, hashrate:statHistory[h].pools[pool].workers[w].hashrate});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return JSON.stringify({"workers": workers, "history": history});
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addStatPoolHistory(stats){
|
function addStatPoolHistory(stats){
|
||||||
var data = {
|
var data = {
|
||||||
time: stats.time,
|
time: stats.time,
|
||||||
|
@ -176,10 +176,10 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
}
|
}
|
||||||
_this.statPoolHistory.push(data);
|
_this.statPoolHistory.push(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
var magnitude = 100000000;
|
var magnitude = 100000000;
|
||||||
var coinPrecision = magnitude.toString().length - 1;
|
var coinPrecision = magnitude.toString().length - 1;
|
||||||
|
|
||||||
function roundTo(n, digits) {
|
function roundTo(n, digits) {
|
||||||
if (digits === undefined) {
|
if (digits === undefined) {
|
||||||
digits = 0;
|
digits = 0;
|
||||||
|
@ -193,7 +193,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
var satoshisToCoins = function(satoshis){
|
var satoshisToCoins = function(satoshis){
|
||||||
return roundTo((satoshis / magnitude), coinPrecision);
|
return roundTo((satoshis / magnitude), coinPrecision);
|
||||||
};
|
};
|
||||||
|
|
||||||
var coinsToSatoshies = function(coins){
|
var coinsToSatoshies = function(coins){
|
||||||
return Math.round(coins * magnitude);
|
return Math.round(coins * magnitude);
|
||||||
};
|
};
|
||||||
|
@ -201,7 +201,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
function coinsRound(number) {
|
function coinsRound(number) {
|
||||||
return roundTo(number, coinPrecision);
|
return roundTo(number, coinPrecision);
|
||||||
}
|
}
|
||||||
|
|
||||||
function readableSeconds(t) {
|
function readableSeconds(t) {
|
||||||
var seconds = Math.round(t);
|
var seconds = Math.round(t);
|
||||||
var minutes = Math.floor(seconds/60);
|
var minutes = Math.floor(seconds/60);
|
||||||
|
@ -220,7 +220,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
_this.stats.coins = redisClients[0].coins;
|
_this.stats.coins = redisClients[0].coins;
|
||||||
cback();
|
cback();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getPayout = function(address, cback){
|
this.getPayout = function(address, cback){
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function(callback){
|
function(callback){
|
||||||
|
@ -232,38 +232,38 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
cback(coinsRound(total).toFixed(8));
|
cback(coinsRound(total).toFixed(8));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getTotalSharesByAddress = function(address, cback) {
|
this.getTotalSharesByAddress = function(address, cback) {
|
||||||
var a = address.split(".")[0];
|
var a = address.split(".")[0];
|
||||||
var client = redisClients[0].client,
|
var client = redisClients[0].client,
|
||||||
coins = redisClients[0].coins,
|
coins = redisClients[0].coins,
|
||||||
shares = [];
|
shares = [];
|
||||||
|
|
||||||
var pindex = parseInt(0);
|
var pindex = parseInt(0);
|
||||||
var totalShares = parseFloat(0);
|
var totalShares = parseFloat(0);
|
||||||
async.each(_this.stats.pools, function(pool, pcb) {
|
async.each(_this.stats.pools, function(pool, pcb) {
|
||||||
pindex++;
|
pindex++;
|
||||||
var coin = String(_this.stats.pools[pool.name].name);
|
var coin = String(_this.stats.pools[pool.name].name);
|
||||||
client.hscan(coin + ':shares:roundCurrent', 0, "match", a+"*", "count", 1000, function(error, result) {
|
client.hscan(coin + ':shares:roundCurrent', 0, "match", a+"*", "count", 1000, function(error, result) {
|
||||||
if (error) {
|
if (error) {
|
||||||
pcb(error);
|
pcb(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var workerName="";
|
var workerName="";
|
||||||
var shares = 0;
|
var shares = 0;
|
||||||
for (var i in result[1]) {
|
for (var i in result[1]) {
|
||||||
if (Math.abs(i % 2) != 1) {
|
if (Math.abs(i % 2) != 1) {
|
||||||
workerName = String(result[1][i]);
|
workerName = String(result[1][i]);
|
||||||
} else {
|
} else {
|
||||||
shares += parseFloat(result[1][i]);
|
shares += parseFloat(result[1][i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shares>0) {
|
if (shares>0) {
|
||||||
totalShares = shares;
|
totalShares = shares;
|
||||||
}
|
}
|
||||||
pcb();
|
pcb();
|
||||||
});
|
});
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
cback(0);
|
cback(0);
|
||||||
return;
|
return;
|
||||||
|
@ -272,37 +272,37 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
cback(totalShares);
|
cback(totalShares);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getBalanceByAddress = function(address, cback){
|
this.getBalanceByAddress = function(address, cback){
|
||||||
|
|
||||||
var a = address.split(".")[0];
|
var a = address.split(".")[0];
|
||||||
|
|
||||||
var client = redisClients[0].client,
|
var client = redisClients[0].client,
|
||||||
coins = redisClients[0].coins,
|
coins = redisClients[0].coins,
|
||||||
balances = [];
|
balances = [];
|
||||||
|
|
||||||
var totalHeld = parseFloat(0);
|
var totalHeld = parseFloat(0);
|
||||||
var totalPaid = parseFloat(0);
|
var totalPaid = parseFloat(0);
|
||||||
var totalImmature = parseFloat(0);
|
var totalImmature = parseFloat(0);
|
||||||
|
|
||||||
async.each(_this.stats.pools, function(pool, pcb) {
|
async.each(_this.stats.pools, function(pool, pcb) {
|
||||||
var coin = String(_this.stats.pools[pool.name].name);
|
var coin = String(_this.stats.pools[pool.name].name);
|
||||||
// get all immature balances from address
|
// get all immature balances from address
|
||||||
client.hscan(coin + ':immature', 0, "match", a+"*", "count", 10000, function(error, pends) {
|
client.hscan(coin + ':immature', 0, "match", a+"*", "count", 10000, function(error, pends) {
|
||||||
// get all balances from address
|
// get all balances from address
|
||||||
client.hscan(coin + ':balances', 0, "match", a+"*", "count", 10000, function(error, bals) {
|
client.hscan(coin + ':balances', 0, "match", a+"*", "count", 10000, function(error, bals) {
|
||||||
// get all payouts from address
|
// get all payouts from address
|
||||||
client.hscan(coin + ':payouts', 0, "match", a+"*", "count", 10000, function(error, pays) {
|
client.hscan(coin + ':payouts', 0, "match", a+"*", "count", 10000, function(error, pays) {
|
||||||
|
|
||||||
var workerName = "";
|
var workerName = "";
|
||||||
var balAmount = 0;
|
var balAmount = 0;
|
||||||
var paidAmount = 0;
|
var paidAmount = 0;
|
||||||
var pendingAmount = 0;
|
var pendingAmount = 0;
|
||||||
|
|
||||||
var workers = {};
|
var workers = {};
|
||||||
|
|
||||||
for (var i in pays[1]) {
|
for (var i in pays[1]) {
|
||||||
if (Math.abs(i % 2) != 1) {
|
if (Math.abs(i % 2) != 1) {
|
||||||
workerName = String(pays[1][i]);
|
workerName = String(pays[1][i]);
|
||||||
|
@ -333,7 +333,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
totalImmature += pendingAmount;
|
totalImmature += pendingAmount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var w in workers) {
|
for (var w in workers) {
|
||||||
balances.push({
|
balances.push({
|
||||||
worker:String(w),
|
worker:String(w),
|
||||||
|
@ -342,23 +342,23 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
immature:workers[w].immature
|
immature:workers[w].immature
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pcb();
|
pcb();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback("There was an error getting balances");
|
callback("There was an error getting balances");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_this.stats.balances = balances;
|
|
||||||
_this.stats.address = address;
|
|
||||||
|
|
||||||
cback({totalHeld:coinsRound(totalHeld), totalPaid:coinsRound(totalPaid), totalImmature:satoshisToCoins(totalImmature), balances});
|
_this.stats.balances = balances;
|
||||||
});
|
_this.stats.address = address;
|
||||||
};
|
|
||||||
|
cback({totalHeld:coinsRound(totalHeld), totalPaid:coinsRound(totalPaid), totalImmature:satoshisToCoins(totalImmature), balances});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
this.getGlobalStats = function(callback){
|
this.getGlobalStats = function(callback){
|
||||||
|
|
||||||
|
@ -377,9 +377,9 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
['scard', ':blocksPending'],
|
['scard', ':blocksPending'],
|
||||||
['scard', ':blocksConfirmed'],
|
['scard', ':blocksConfirmed'],
|
||||||
['scard', ':blocksKicked'],
|
['scard', ':blocksKicked'],
|
||||||
['smembers', ':blocksPending'],
|
['smembers', ':blocksPending'],
|
||||||
['smembers', ':blocksConfirmed'],
|
['smembers', ':blocksConfirmed'],
|
||||||
['hgetall', ':shares:roundCurrent'],
|
['hgetall', ':shares:roundCurrent'],
|
||||||
['hgetall', ':blocksPendingConfirms'],
|
['hgetall', ':blocksPendingConfirms'],
|
||||||
['zrange', ':payments', -100, -1],
|
['zrange', ':payments', -100, -1],
|
||||||
['hgetall', ':shares:timesCurrent']
|
['hgetall', ':shares:timesCurrent']
|
||||||
|
@ -401,6 +401,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
callback(err);
|
callback(err);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|
||||||
for(var i = 0; i < replies.length; i += commandsPerCoin){
|
for(var i = 0; i < replies.length; i += commandsPerCoin){
|
||||||
var coinName = client.coins[i / commandsPerCoin | 0];
|
var coinName = client.coins[i / commandsPerCoin | 0];
|
||||||
var marketStats = {};
|
var marketStats = {};
|
||||||
|
@ -409,21 +410,23 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
marketStats = replies[i + 2] ? (JSON.parse(replies[i + 2].coinmarketcap)[0] || 0) : 0;
|
marketStats = replies[i + 2] ? (JSON.parse(replies[i + 2].coinmarketcap)[0] || 0) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var coinStats = {
|
var coinStats = {
|
||||||
name: coinName,
|
name: coinName,
|
||||||
symbol: poolConfigs[coinName].coin.symbol.toUpperCase(),
|
symbol: poolConfigs[coinName].coin.symbol.toUpperCase(),
|
||||||
algorithm: poolConfigs[coinName].coin.algorithm,
|
algorithm: poolConfigs[coinName].coin.algorithm,
|
||||||
|
poolFees: poolConfigs[coinName].rewardRecipients,
|
||||||
hashrates: replies[i + 1],
|
hashrates: replies[i + 1],
|
||||||
poolStats: {
|
poolStats: {
|
||||||
validShares: replies[i + 2] ? (replies[i + 2].validShares || 0) : 0,
|
validShares: replies[i + 2] ? (replies[i + 2].validShares || 0) : 0,
|
||||||
validBlocks: replies[i + 2] ? (replies[i + 2].validBlocks || 0) : 0,
|
validBlocks: replies[i + 2] ? (replies[i + 2].validBlocks || 0) : 0,
|
||||||
invalidShares: replies[i + 2] ? (replies[i + 2].invalidShares || 0) : 0,
|
invalidShares: replies[i + 2] ? (replies[i + 2].invalidShares || 0) : 0,
|
||||||
totalPaid: replies[i + 2] ? (replies[i + 2].totalPaid || 0) : 0,
|
totalPaid: replies[i + 2] ? (replies[i + 2].totalPaid || 0) : 0,
|
||||||
networkBlocks: replies[i + 2] ? (replies[i + 2].networkBlocks || 0) : 0,
|
networkBlocks: replies[i + 2] ? (replies[i + 2].networkBlocks || 0) : 0,
|
||||||
networkSols: replies[i + 2] ? (replies[i + 2].networkSols || 0) : 0,
|
networkSols: replies[i + 2] ? (replies[i + 2].networkSols || 0) : 0,
|
||||||
networkSolsString: getReadableNetworkHashRateString(replies[i + 2] ? (replies[i + 2].networkSols || 0) : 0),
|
networkSolsString: getReadableNetworkHashRateString(replies[i + 2] ? (replies[i + 2].networkSols || 0) : 0),
|
||||||
networkDiff: replies[i + 2] ? (replies[i + 2].networkDiff || 0) : 0,
|
networkDiff: replies[i + 2] ? (replies[i + 2].networkDiff || 0) : 0,
|
||||||
networkConnections: replies[i + 2] ? (replies[i + 2].networkConnections || 0) : 0,
|
networkConnections: replies[i + 2] ? (replies[i + 2].networkConnections || 0) : 0,
|
||||||
networkVersion: replies[i + 2] ? (replies[i + 2].networkSubVersion || 0) : 0,
|
networkVersion: replies[i + 2] ? (replies[i + 2].networkSubVersion || 0) : 0,
|
||||||
networkProtocolVersion: replies[i + 2] ? (replies[i + 2].networkProtocolVersion || 0) : 0
|
networkProtocolVersion: replies[i + 2] ? (replies[i + 2].networkProtocolVersion || 0) : 0
|
||||||
},
|
},
|
||||||
|
@ -435,16 +438,16 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
orphaned: replies[i + 5]
|
orphaned: replies[i + 5]
|
||||||
},
|
},
|
||||||
/* show all pending blocks */
|
/* show all pending blocks */
|
||||||
pending: {
|
pending: {
|
||||||
blocks: replies[i + 6].sort(sortBlocks),
|
blocks: replies[i + 6].sort(sortBlocks),
|
||||||
confirms: (replies[i + 9] || {})
|
confirms: (replies[i + 9] || {})
|
||||||
},
|
},
|
||||||
/* show last 50 found blocks */
|
/* show last 50 found blocks */
|
||||||
confirmed: {
|
confirmed: {
|
||||||
blocks: replies[i + 7].sort(sortBlocks).slice(0,50)
|
blocks: replies[i + 7].sort(sortBlocks).slice(0,50)
|
||||||
},
|
},
|
||||||
payments: [],
|
payments: [],
|
||||||
currentRoundShares: (replies[i + 8] || {}),
|
currentRoundShares: (replies[i + 8] || {}),
|
||||||
currentRoundTimes: (replies[i + 11] || {}),
|
currentRoundTimes: (replies[i + 11] || {}),
|
||||||
maxRoundTime: 0,
|
maxRoundTime: 0,
|
||||||
shareCount: 0
|
shareCount: 0
|
||||||
|
@ -456,7 +459,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
jsonObj = null;
|
jsonObj = null;
|
||||||
}
|
}
|
||||||
if (jsonObj !== null) {
|
if (jsonObj !== null) {
|
||||||
coinStats.payments.push(jsonObj);
|
coinStats.payments.push(jsonObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,106 +490,106 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
Object.keys(allCoinStats).forEach(function(coin){
|
Object.keys(allCoinStats).forEach(function(coin){
|
||||||
var coinStats = allCoinStats[coin];
|
var coinStats = allCoinStats[coin];
|
||||||
coinStats.workers = {};
|
coinStats.workers = {};
|
||||||
coinStats.miners = {};
|
coinStats.miners = {};
|
||||||
coinStats.shares = 0;
|
coinStats.shares = 0;
|
||||||
coinStats.hashrates.forEach(function(ins){
|
coinStats.hashrates.forEach(function(ins){
|
||||||
var parts = ins.split(':');
|
var parts = ins.split(':');
|
||||||
var workerShares = parseFloat(parts[0]);
|
var workerShares = parseFloat(parts[0]);
|
||||||
var miner = parts[1].split('.')[0];
|
var miner = parts[1].split('.')[0];
|
||||||
var worker = parts[1];
|
var worker = parts[1];
|
||||||
var diff = Math.round(parts[0] * 8192);
|
var diff = Math.round(parts[0] * 8192);
|
||||||
if (workerShares > 0) {
|
if (workerShares > 0) {
|
||||||
coinStats.shares += workerShares;
|
coinStats.shares += workerShares;
|
||||||
// build worker stats
|
// build worker stats
|
||||||
if (worker in coinStats.workers) {
|
if (worker in coinStats.workers) {
|
||||||
coinStats.workers[worker].shares += workerShares;
|
coinStats.workers[worker].shares += workerShares;
|
||||||
coinStats.workers[worker].diff = diff;
|
coinStats.workers[worker].diff = diff;
|
||||||
} else {
|
} else {
|
||||||
coinStats.workers[worker] = {
|
coinStats.workers[worker] = {
|
||||||
name: worker,
|
name: worker,
|
||||||
diff: diff,
|
diff: diff,
|
||||||
shares: workerShares,
|
shares: workerShares,
|
||||||
invalidshares: 0,
|
invalidshares: 0,
|
||||||
currRoundShares: 0,
|
currRoundShares: 0,
|
||||||
currRoundTime: 0,
|
currRoundTime: 0,
|
||||||
hashrate: null,
|
hashrate: null,
|
||||||
hashrateString: null,
|
hashrateString: null,
|
||||||
luckDays: null,
|
luckDays: null,
|
||||||
luckHours: null,
|
luckHours: null,
|
||||||
paid: 0,
|
paid: 0,
|
||||||
balance: 0
|
balance: 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// build miner stats
|
// build miner stats
|
||||||
if (miner in coinStats.miners) {
|
if (miner in coinStats.miners) {
|
||||||
coinStats.miners[miner].shares += workerShares;
|
coinStats.miners[miner].shares += workerShares;
|
||||||
} else {
|
} else {
|
||||||
coinStats.miners[miner] = {
|
coinStats.miners[miner] = {
|
||||||
name: miner,
|
name: miner,
|
||||||
shares: workerShares,
|
shares: workerShares,
|
||||||
invalidshares: 0,
|
invalidshares: 0,
|
||||||
currRoundShares: 0,
|
currRoundShares: 0,
|
||||||
currRoundTime: 0,
|
currRoundTime: 0,
|
||||||
hashrate: null,
|
hashrate: null,
|
||||||
hashrateString: null,
|
hashrateString: null,
|
||||||
luckDays: null,
|
luckDays: null,
|
||||||
luckHours: null
|
luckHours: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// build worker stats
|
// build worker stats
|
||||||
if (worker in coinStats.workers) {
|
if (worker in coinStats.workers) {
|
||||||
coinStats.workers[worker].invalidshares -= workerShares; // workerShares is negative number!
|
coinStats.workers[worker].invalidshares -= workerShares; // workerShares is negative number!
|
||||||
coinStats.workers[worker].diff = diff;
|
coinStats.workers[worker].diff = diff;
|
||||||
} else {
|
} else {
|
||||||
coinStats.workers[worker] = {
|
coinStats.workers[worker] = {
|
||||||
name: worker,
|
name: worker,
|
||||||
diff: diff,
|
diff: diff,
|
||||||
shares: 0,
|
shares: 0,
|
||||||
invalidshares: -workerShares,
|
invalidshares: -workerShares,
|
||||||
currRoundShares: 0,
|
currRoundShares: 0,
|
||||||
currRoundTime: 0,
|
currRoundTime: 0,
|
||||||
hashrate: null,
|
hashrate: null,
|
||||||
hashrateString: null,
|
hashrateString: null,
|
||||||
luckDays: null,
|
luckDays: null,
|
||||||
luckHours: null,
|
luckHours: null,
|
||||||
paid: 0,
|
paid: 0,
|
||||||
balance: 0
|
balance: 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// build miner stats
|
// build miner stats
|
||||||
if (miner in coinStats.miners) {
|
if (miner in coinStats.miners) {
|
||||||
coinStats.miners[miner].invalidshares -= workerShares; // workerShares is negative number!
|
coinStats.miners[miner].invalidshares -= workerShares; // workerShares is negative number!
|
||||||
} else {
|
} else {
|
||||||
coinStats.miners[miner] = {
|
coinStats.miners[miner] = {
|
||||||
name: miner,
|
name: miner,
|
||||||
shares: 0,
|
shares: 0,
|
||||||
invalidshares: -workerShares,
|
invalidshares: -workerShares,
|
||||||
currRoundShares: 0,
|
currRoundShares: 0,
|
||||||
currRoundTime: 0,
|
currRoundTime: 0,
|
||||||
hashrate: null,
|
hashrate: null,
|
||||||
hashrateString: null,
|
hashrateString: null,
|
||||||
luckDays: null,
|
luckDays: null,
|
||||||
luckHours: null
|
luckHours: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// sort miners
|
// sort miners
|
||||||
coinStats.miners = sortMinersByHashrate(coinStats.miners);
|
coinStats.miners = sortMinersByHashrate(coinStats.miners);
|
||||||
|
|
||||||
var shareMultiplier = Math.pow(2, 32) / algos[coinStats.algorithm].multiplier;
|
var shareMultiplier = Math.pow(2, 32) / algos[coinStats.algorithm].multiplier;
|
||||||
coinStats.hashrate = shareMultiplier * coinStats.shares / portalConfig.website.stats.hashrateWindow;
|
coinStats.hashrate = shareMultiplier * coinStats.shares / portalConfig.website.stats.hashrateWindow;
|
||||||
coinStats.hashrateString = _this.getReadableHashRateString(coinStats.hashrate);
|
coinStats.hashrateString = _this.getReadableHashRateString(coinStats.hashrate);
|
||||||
|
|
||||||
var _blocktime = 160;
|
var _blocktime = 160;
|
||||||
var _networkHashRate = parseFloat(coinStats.poolStats.networkSols) * 1.2;
|
var _networkHashRate = parseFloat(coinStats.poolStats.networkSols) * 1.2;
|
||||||
var _myHashRate = (coinStats.hashrate / 1000000) * 2;
|
var _myHashRate = (coinStats.hashrate / 1000000) * 2;
|
||||||
coinStats.luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
|
coinStats.luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
|
||||||
coinStats.luckHours = ((_networkHashRate / _myHashRate * _blocktime) / (60 * 60)).toFixed(3);
|
coinStats.luckHours = ((_networkHashRate / _myHashRate * _blocktime) / (60 * 60)).toFixed(3);
|
||||||
coinStats.minerCount = Object.keys(coinStats.miners).length;
|
coinStats.minerCount = Object.keys(coinStats.miners).length;
|
||||||
coinStats.workerCount = Object.keys(coinStats.workers).length;
|
coinStats.workerCount = Object.keys(coinStats.workers).length;
|
||||||
portalStats.global.workers += coinStats.workerCount;
|
portalStats.global.workers += coinStats.workerCount;
|
||||||
|
|
||||||
|
@ -617,7 +620,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
for (var worker in coinStats.currentRoundTimes) {
|
for (var worker in coinStats.currentRoundTimes) {
|
||||||
var time = parseFloat(coinStats.currentRoundTimes[worker]);
|
var time = parseFloat(coinStats.currentRoundTimes[worker]);
|
||||||
if (_maxTimeShare < time) { _maxTimeShare = time; }
|
if (_maxTimeShare < time) { _maxTimeShare = time; }
|
||||||
var miner = worker.split(".")[0]; // split poolId from minerAddress
|
var miner = worker.split(".")[0]; // split poolId from minerAddress
|
||||||
if (miner in coinStats.miners && coinStats.miners[miner].currRoundTime < time) {
|
if (miner in coinStats.miners && coinStats.miners[miner].currRoundTime < time) {
|
||||||
coinStats.miners[miner].currRoundTime = time;
|
coinStats.miners[miner].currRoundTime = time;
|
||||||
}
|
}
|
||||||
|
@ -626,31 +629,31 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
coinStats.shareCount = _shareTotal;
|
coinStats.shareCount = _shareTotal;
|
||||||
coinStats.maxRoundTime = _maxTimeShare;
|
coinStats.maxRoundTime = _maxTimeShare;
|
||||||
coinStats.maxRoundTimeString = readableSeconds(_maxTimeShare);
|
coinStats.maxRoundTimeString = readableSeconds(_maxTimeShare);
|
||||||
|
|
||||||
for (var worker in coinStats.workers) {
|
for (var worker in coinStats.workers) {
|
||||||
var _workerRate = shareMultiplier * coinStats.workers[worker].shares / portalConfig.website.stats.hashrateWindow;
|
var _workerRate = shareMultiplier * coinStats.workers[worker].shares / portalConfig.website.stats.hashrateWindow;
|
||||||
var _wHashRate = (_workerRate / 1000000) * 2;
|
var _wHashRate = (_workerRate / 1000000) * 2;
|
||||||
coinStats.workers[worker].luckDays = ((_networkHashRate / _wHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
|
coinStats.workers[worker].luckDays = ((_networkHashRate / _wHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
|
||||||
coinStats.workers[worker].luckHours = ((_networkHashRate / _wHashRate * _blocktime) / (60 * 60)).toFixed(3);
|
coinStats.workers[worker].luckHours = ((_networkHashRate / _wHashRate * _blocktime) / (60 * 60)).toFixed(3);
|
||||||
coinStats.workers[worker].hashrate = _workerRate;
|
coinStats.workers[worker].hashrate = _workerRate;
|
||||||
coinStats.workers[worker].hashrateString = _this.getReadableHashRateString(_workerRate);
|
coinStats.workers[worker].hashrateString = _this.getReadableHashRateString(_workerRate);
|
||||||
var miner = worker.split('.')[0];
|
var miner = worker.split('.')[0];
|
||||||
if (miner in coinStats.miners) {
|
if (miner in coinStats.miners) {
|
||||||
coinStats.workers[worker].currRoundTime = coinStats.miners[miner].currRoundTime;
|
coinStats.workers[worker].currRoundTime = coinStats.miners[miner].currRoundTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var miner in coinStats.miners) {
|
for (var miner in coinStats.miners) {
|
||||||
var _workerRate = shareMultiplier * coinStats.miners[miner].shares / portalConfig.website.stats.hashrateWindow;
|
var _workerRate = shareMultiplier * coinStats.miners[miner].shares / portalConfig.website.stats.hashrateWindow;
|
||||||
var _wHashRate = (_workerRate / 1000000) * 2;
|
var _wHashRate = (_workerRate / 1000000) * 2;
|
||||||
coinStats.miners[miner].luckDays = ((_networkHashRate / _wHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
|
coinStats.miners[miner].luckDays = ((_networkHashRate / _wHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
|
||||||
coinStats.miners[miner].luckHours = ((_networkHashRate / _wHashRate * _blocktime) / (60 * 60)).toFixed(3);
|
coinStats.miners[miner].luckHours = ((_networkHashRate / _wHashRate * _blocktime) / (60 * 60)).toFixed(3);
|
||||||
coinStats.miners[miner].hashrate = _workerRate;
|
coinStats.miners[miner].hashrate = _workerRate;
|
||||||
coinStats.miners[miner].hashrateString = _this.getReadableHashRateString(_workerRate);
|
coinStats.miners[miner].hashrateString = _this.getReadableHashRateString(_workerRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort workers by name
|
// sort workers by name
|
||||||
coinStats.workers = sortWorkersByName(coinStats.workers);
|
coinStats.workers = sortWorkersByName(coinStats.workers);
|
||||||
|
|
||||||
delete coinStats.hashrates;
|
delete coinStats.hashrates;
|
||||||
delete coinStats.shares;
|
delete coinStats.shares;
|
||||||
});
|
});
|
||||||
|
@ -661,7 +664,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
});
|
});
|
||||||
|
|
||||||
_this.stats = portalStats;
|
_this.stats = portalStats;
|
||||||
|
|
||||||
// save historical hashrate, not entire stats!
|
// save historical hashrate, not entire stats!
|
||||||
var saveStats = JSON.parse(JSON.stringify(portalStats));
|
var saveStats = JSON.parse(JSON.stringify(portalStats));
|
||||||
Object.keys(saveStats.pools).forEach(function(pool){
|
Object.keys(saveStats.pools).forEach(function(pool){
|
||||||
|
@ -674,9 +677,9 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
});
|
});
|
||||||
_this.statsString = JSON.stringify(saveStats);
|
_this.statsString = JSON.stringify(saveStats);
|
||||||
_this.statHistory.push(saveStats);
|
_this.statHistory.push(saveStats);
|
||||||
|
|
||||||
addStatPoolHistory(portalStats);
|
addStatPoolHistory(portalStats);
|
||||||
|
|
||||||
var retentionTime = (((Date.now() / 1000) - portalConfig.website.stats.historicalRetention) | 0);
|
var retentionTime = (((Date.now() / 1000) - portalConfig.website.stats.historicalRetention) | 0);
|
||||||
|
|
||||||
for (var i = 0; i < _this.statHistory.length; i++){
|
for (var i = 0; i < _this.statHistory.length; i++){
|
||||||
|
@ -702,16 +705,16 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
};
|
};
|
||||||
|
|
||||||
function sortPoolsByName(objects) {
|
function sortPoolsByName(objects) {
|
||||||
var newObject = {};
|
var newObject = {};
|
||||||
var sortedArray = sortProperties(objects, 'name', false, false);
|
var sortedArray = sortProperties(objects, 'name', false, false);
|
||||||
for (var i = 0; i < sortedArray.length; i++) {
|
for (var i = 0; i < sortedArray.length; i++) {
|
||||||
var key = sortedArray[i][0];
|
var key = sortedArray[i][0];
|
||||||
var value = sortedArray[i][1];
|
var value = sortedArray[i][1];
|
||||||
newObject[key] = value;
|
newObject[key] = value;
|
||||||
}
|
}
|
||||||
return newObject;
|
return newObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortBlocks(a, b) {
|
function sortBlocks(a, b) {
|
||||||
var as = parseInt(a.split(":")[2]);
|
var as = parseInt(a.split(":")[2]);
|
||||||
var bs = parseInt(b.split(":")[2]);
|
var bs = parseInt(b.split(":")[2]);
|
||||||
|
@ -719,56 +722,56 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
||||||
if (as < bs) return 1;
|
if (as < bs) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortWorkersByName(objects) {
|
function sortWorkersByName(objects) {
|
||||||
var newObject = {};
|
var newObject = {};
|
||||||
var sortedArray = sortProperties(objects, 'name', false, false);
|
var sortedArray = sortProperties(objects, 'name', false, false);
|
||||||
for (var i = 0; i < sortedArray.length; i++) {
|
for (var i = 0; i < sortedArray.length; i++) {
|
||||||
var key = sortedArray[i][0];
|
var key = sortedArray[i][0];
|
||||||
var value = sortedArray[i][1];
|
var value = sortedArray[i][1];
|
||||||
newObject[key] = value;
|
newObject[key] = value;
|
||||||
}
|
}
|
||||||
return newObject;
|
return newObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortMinersByHashrate(objects) {
|
function sortMinersByHashrate(objects) {
|
||||||
var newObject = {};
|
var newObject = {};
|
||||||
var sortedArray = sortProperties(objects, 'shares', true, true);
|
var sortedArray = sortProperties(objects, 'shares', true, true);
|
||||||
for (var i = 0; i < sortedArray.length; i++) {
|
for (var i = 0; i < sortedArray.length; i++) {
|
||||||
var key = sortedArray[i][0];
|
var key = sortedArray[i][0];
|
||||||
var value = sortedArray[i][1];
|
var value = sortedArray[i][1];
|
||||||
newObject[key] = value;
|
newObject[key] = value;
|
||||||
}
|
}
|
||||||
return newObject;
|
return newObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortWorkersByHashrate(a, b) {
|
function sortWorkersByHashrate(a, b) {
|
||||||
if (a.hashrate === b.hashrate) {
|
if (a.hashrate === b.hashrate) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return (a.hashrate < b.hashrate) ? -1 : 1;
|
return (a.hashrate < b.hashrate) ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getReadableHashRateString = function(hashrate){
|
this.getReadableHashRateString = function(hashrate){
|
||||||
hashrate = (hashrate * 2);
|
hashrate = (hashrate * 2);
|
||||||
if (hashrate < 1000000) {
|
if (hashrate < 1000000) {
|
||||||
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s';
|
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s';
|
||||||
}
|
}
|
||||||
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
|
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
|
||||||
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
|
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
|
||||||
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
|
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
|
||||||
return hashrate.toFixed(2) + byteUnits[i];
|
return hashrate.toFixed(2) + byteUnits[i];
|
||||||
};
|
};
|
||||||
|
|
||||||
function getReadableNetworkHashRateString(hashrate) {
|
function getReadableNetworkHashRateString(hashrate) {
|
||||||
hashrate = (hashrate * 1000000);
|
hashrate = (hashrate * 1000000);
|
||||||
if (hashrate < 1000000)
|
if (hashrate < 1000000)
|
||||||
return '0 Sol';
|
return '0 Sol';
|
||||||
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
|
var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ];
|
||||||
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
|
var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1);
|
||||||
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
|
hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
|
||||||
return hashrate.toFixed(2) + byteUnits[i];
|
return hashrate.toFixed(2) + byteUnits[i];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue