diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index 97e9691..5a8a9f9 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -603,7 +603,10 @@ function SetupForPool(logger, poolOptions, setupFinished) { let minerAddressPrefix = address.substring(0,2); let checkPrefix = (poolOptions.minerPrefix || false); - if (privateChain && poolZAddressPrefix == 'zs' && minerAddressLength == 78 && minerAddressPrefix == 'zs') { + if (typeof poolOptions.rewardsDisabled !== 'undefined' && poolOptions.rewardsDisabled.includes(address)) { + logger.warning(logSystem, logComponent, 'Rewards disabled for this adddress: ' + address + ', convert to address ' + (poolOptions.invalidAddress || poolOptions.address)); + return (poolOptions.invalidAddress || poolOptions.address); + } else if (privateChain && poolZAddressPrefix == 'zs' && minerAddressLength == 78 && minerAddressPrefix == 'zs') { //validate as sapling return address; } else if (privateChain && poolZAddressPrefix == 'zc' && minerAddressLength == 95 && minerAddressPrefix == 'zc') { diff --git a/libs/stats.js b/libs/stats.js index b0049cd..d647db2 100644 --- a/libs/stats.js +++ b/libs/stats.js @@ -25,31 +25,31 @@ function rediscreateClient(port, host, pass) { * @returns {Array} array of items in [[key,value],[key,value],...] format. */ function sortProperties(obj, sortedBy, isNumericSort, reverse) { - sortedBy = sortedBy || 1; // by default first key - isNumericSort = isNumericSort || false; // by default text sort - reverse = reverse || false; // by default no reverse - - var reversed = (reverse) ? -1 : 1; - - var sortable = []; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - sortable.push([key, obj[key]]); - } - } - if (isNumericSort) - sortable.sort(function (a, b) { - return reversed * (a[1][sortedBy] - b[1][sortedBy]); - }); - else - sortable.sort(function (a, b) { - var x = a[1][sortedBy].toLowerCase(), - y = b[1][sortedBy].toLowerCase(); - return x < y ? reversed * -1 : x > y ? reversed : 0; - }); - return sortable; // array in format [ [ key1, val1 ], [ key2, val2 ], ... ] + sortedBy = sortedBy || 1; // by default first key + isNumericSort = isNumericSort || false; // by default text sort + reverse = reverse || false; // by default no reverse + + var reversed = (reverse) ? -1 : 1; + + var sortable = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + sortable.push([key, obj[key]]); + } + } + if (isNumericSort) + sortable.sort(function (a, b) { + return reversed * (a[1][sortedBy] - b[1][sortedBy]); + }); + else + sortable.sort(function (a, b) { + var x = a[1][sortedBy].toLowerCase(), + y = b[1][sortedBy].toLowerCase(); + return x < y ? reversed * -1 : x > y ? reversed : 0; + }); + return sortable; // array in format [ [ key1, val1 ], [ key2, val2 ], ... ] } - + module.exports = function(logger, portalConfig, poolConfigs){ var _this = this; @@ -101,19 +101,29 @@ module.exports = function(logger, portalConfig, poolConfigs){ async.each(_this.stats.pools, function(pool, pcb) { 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++) - allBlocks[pool.name+"-"+_this.stats.pools[pool.name].pending.blocks[i].split(':')[2]] = _this.stats.pools[pool.name].pending.blocks[i]; - + for (var i=0; i<_this.stats.pools[pool.name].pending.blocks.length; i++) { + let blockoutput = _this.stats.pools[pool.name].pending.blocks[i].split(':'); + blockoutput[3] = pool.name + '-miner'; + blockoutput = blockoutput.join(':'); + + allBlocks[pool.name+"-"+_this.stats.pools[pool.name].pending.blocks[i].split(':')[2]] = blockoutput; + } + 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++) - allBlocks[pool.name+"-"+_this.stats.pools[pool.name].confirmed.blocks[i].split(':')[2]] = _this.stats.pools[pool.name].confirmed.blocks[i]; - + for (var i=0; i<_this.stats.pools[pool.name].confirmed.blocks.length; i++) { + let blockoutput = _this.stats.pools[pool.name].confirmed.blocks[i].split(':'); + blockoutput[3] = pool.name + '-miner'; + blockoutput = blockoutput.join(':'); + + allBlocks[pool.name+"-"+_this.stats.pools[pool.name].confirmed.blocks[i].split(':')[2]] = blockoutput; + } + pcb(); }, function(err) { - cback(allBlocks); + cback(allBlocks); }); }; - + function gatherStatHistory(){ var retentionTime = (((Date.now() / 1000) - portalConfig.website.stats.historicalRetention) | 0).toString(); redisStats.zrangebyscore(['statHistory', retentionTime, '+inf'], function(err, replies){ @@ -133,34 +143,34 @@ module.exports = function(logger, portalConfig, poolConfigs){ }); } - function getWorkerStats(address) { - address = address.split(".")[0]; - if (address.length > 0 && address.startsWith('t')) { - for (var h in statHistory) { - for(var pool in statHistory[h].pools) { - - 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; - } - + function getWorkerStats(address) { + address = address.split(".")[0]; + if (address.length > 0 && address.startsWith('t')) { + for (var h in statHistory) { + for(var pool in statHistory[h].pools) { + + 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; + } + function addStatPoolHistory(stats){ var data = { time: stats.time, @@ -175,10 +185,10 @@ module.exports = function(logger, portalConfig, poolConfigs){ } _this.statPoolHistory.push(data); } - + var magnitude = 100000000; var coinPrecision = magnitude.toString().length - 1; - + function roundTo(n, digits) { if (digits === undefined) { digits = 0; @@ -192,7 +202,7 @@ module.exports = function(logger, portalConfig, poolConfigs){ var satoshisToCoins = function(satoshis){ return roundTo((satoshis / magnitude), coinPrecision); }; - + var coinsToSatoshies = function(coins){ return Math.round(coins * magnitude); }; @@ -200,7 +210,7 @@ module.exports = function(logger, portalConfig, poolConfigs){ function coinsRound(number) { return roundTo(number, coinPrecision); } - + function readableSeconds(t) { var seconds = Math.round(t); var minutes = Math.floor(seconds/60); @@ -219,7 +229,7 @@ module.exports = function(logger, portalConfig, poolConfigs){ _this.stats.coins = redisClients[0].coins; cback(); }; - + this.getPayout = function(address, cback){ async.waterfall([ function(callback){ @@ -231,38 +241,38 @@ module.exports = function(logger, portalConfig, poolConfigs){ cback(coinsRound(total).toFixed(8)); }); }; - - this.getTotalSharesByAddress = function(address, cback) { - var a = address.split(".")[0]; + + this.getTotalSharesByAddress = function(address, cback) { + var a = address.split(".")[0]; var client = redisClients[0].client, coins = redisClients[0].coins, shares = []; var pindex = parseInt(0); - var totalShares = parseFloat(0); - async.each(_this.stats.pools, function(pool, pcb) { + var totalShares = parseFloat(0); + async.each(_this.stats.pools, function(pool, pcb) { pindex++; - var coin = String(_this.stats.pools[pool.name].name); - client.hscan(coin + ':shares:roundCurrent', 0, "match", a+"*", "count", 1000, function(error, result) { + var coin = String(_this.stats.pools[pool.name].name); + client.hscan(coin + ':shares:roundCurrent', 0, "match", a+"*", "count", 1000, function(error, result) { if (error) { pcb(error); return; } - var workerName=""; - var shares = 0; - for (var i in result[1]) { - if (Math.abs(i % 2) != 1) { - workerName = String(result[1][i]); - } else { - shares += parseFloat(result[1][i]); - } - } + var workerName=""; + var shares = 0; + for (var i in result[1]) { + if (Math.abs(i % 2) != 1) { + workerName = String(result[1][i]); + } else { + shares += parseFloat(result[1][i]); + } + } if (shares>0) { totalShares = shares; } pcb(); - }); - }, function(err) { + }); + }, function(err) { if (err) { cback(0); return; @@ -271,37 +281,37 @@ module.exports = function(logger, portalConfig, poolConfigs){ cback(totalShares); return; } - }); - }; + }); + }; this.getBalanceByAddress = function(address, cback){ - var a = address.split(".")[0]; - + var a = address.split(".")[0]; + var client = redisClients[0].client, coins = redisClients[0].coins, balances = []; - - var totalHeld = parseFloat(0); - var totalPaid = parseFloat(0); + + var totalHeld = parseFloat(0); + var totalPaid = parseFloat(0); var totalImmature = parseFloat(0); - - async.each(_this.stats.pools, function(pool, pcb) { - var coin = String(_this.stats.pools[pool.name].name); - // get all immature balances from address - client.hscan(coin + ':immature', 0, "match", a+"*", "count", 10000, function(error, pends) { + + async.each(_this.stats.pools, function(pool, pcb) { + var coin = String(_this.stats.pools[pool.name].name); + // get all immature balances from address + client.hscan(coin + ':immature', 0, "match", a+"*", "count", 10000, function(error, pends) { // get all balances from address client.hscan(coin + ':balances', 0, "match", a+"*", "count", 10000, function(error, bals) { // get all payouts from address client.hscan(coin + ':payouts', 0, "match", a+"*", "count", 10000, function(error, pays) { - + var workerName = ""; var balAmount = 0; var paidAmount = 0; var pendingAmount = 0; - + var workers = {}; - + for (var i in pays[1]) { if (Math.abs(i % 2) != 1) { workerName = String(pays[1][i]); @@ -335,7 +345,7 @@ module.exports = function(logger, portalConfig, poolConfigs){ totalImmature += pendingAmount; } } - + for (var w in workers) { balances.push({ worker:String(w), @@ -344,23 +354,23 @@ module.exports = function(logger, portalConfig, poolConfigs){ immature:workers[w].immature }); } - + pcb(); }); }); }); - }, function(err) { - if (err) { - callback("There was an error getting balances"); - return; - } - - _this.stats.balances = balances; - _this.stats.address = address; - - cback({totalHeld:coinsRound(totalHeld), totalPaid:coinsRound(totalPaid), totalImmature:satoshisToCoins(totalImmature), balances}); - }); - }; + }, function(err) { + if (err) { + callback("There was an error getting balances"); + return; + } + + _this.stats.balances = balances; + _this.stats.address = address; + + cback({totalHeld:coinsRound(totalHeld), totalPaid:coinsRound(totalPaid), totalImmature:satoshisToCoins(totalImmature), balances}); + }); + }; this.getGlobalStats = function(callback){ @@ -379,9 +389,9 @@ module.exports = function(logger, portalConfig, poolConfigs){ ['scard', ':blocksPending'], ['scard', ':blocksConfirmed'], ['scard', ':blocksKicked'], - ['smembers', ':blocksPending'], - ['smembers', ':blocksConfirmed'], - ['hgetall', ':shares:roundCurrent'], + ['smembers', ':blocksPending'], + ['smembers', ':blocksConfirmed'], + ['hgetall', ':shares:roundCurrent'], ['hgetall', ':blocksPendingConfirms'], ['zrange', ':payments', -100, -1], ['hgetall', ':shares:timesCurrent'] @@ -411,6 +421,39 @@ module.exports = function(logger, portalConfig, poolConfigs){ marketStats = replies[i + 2] ? (JSON.parse(replies[i + 2].coinmarketcap)[0] || 0) : 0; } } + + //anonymize currentRoundShares + let currentRoundSharesIndex = 0; + for (var worker in replies[i + 8]) { + Object.defineProperty(replies[i+8], 'worker' + currentRoundSharesIndex, Object.getOwnPropertyDescriptor(replies[i+8], worker)); + delete replies[i+8][worker]; + currentRoundSharesIndex++; + } + + //anonymize currentRoundTimes + let currentRoundTimesIndex = 0; + for (var worker in replies[i + 11]) { + Object.defineProperty(replies[i+11], 'worker' + currentRoundTimesIndex, Object.getOwnPropertyDescriptor(replies[i+11], worker)); + delete replies[i+11][worker]; + currentRoundTimesIndex++; + } + + //anonymize confirmed blocks + for (var b=0; b < replies[i + 7].length; b++) { + let blockoutput = replies[i + 7][b].split(':'); + blockoutput[3] = coinName + '-miner'; + blockoutput = blockoutput.join(':'); + replies[i + 7][b] = blockoutput; + } + + //anonymize pending blocks + for (var b=0; b < replies[i + 6].length; b++) { + let blockoutput = replies[i + 6][b].split(':'); + blockoutput[3] = coinName + '-miner'; + blockoutput = blockoutput.join(':'); + replies[i + 6][b] = blockoutput; + } + var coinStats = { name: coinName, symbol: poolConfigs[coinName].coin.symbol.toUpperCase(), @@ -421,11 +464,11 @@ module.exports = function(logger, portalConfig, poolConfigs){ validBlocks: replies[i + 2] ? (replies[i + 2].validBlocks || 0) : 0, invalidShares: replies[i + 2] ? (replies[i + 2].invalidShares || 0) : 0, totalPaid: replies[i + 2] ? (replies[i + 2].totalPaid || 0) : 0, - networkBlocks: replies[i + 2] ? (replies[i + 2].networkBlocks || 0) : 0, - networkSols: 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, - networkConnections: replies[i + 2] ? (replies[i + 2].networkConnections || 0) : 0, + networkBlocks: replies[i + 2] ? (replies[i + 2].networkBlocks || 0) : 0, + networkSols: 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, + networkConnections: replies[i + 2] ? (replies[i + 2].networkConnections || 0) : 0, networkVersion: replies[i + 2] ? (replies[i + 2].networkSubVersion || 0) : 0, networkProtocolVersion: replies[i + 2] ? (replies[i + 2].networkProtocolVersion || 0) : 0 }, @@ -437,16 +480,16 @@ module.exports = function(logger, portalConfig, poolConfigs){ orphaned: replies[i + 5] }, /* show all pending blocks */ - pending: { - blocks: replies[i + 6].sort(sortBlocks), + pending: { + blocks: replies[i + 6].sort(sortBlocks), confirms: (replies[i + 9] || {}) - }, + }, /* show last 50 found blocks */ - confirmed: { - blocks: replies[i + 7].sort(sortBlocks).slice(0,50) - }, + confirmed: { + blocks: replies[i + 7].sort(sortBlocks).slice(0,50) + }, payments: [], - currentRoundShares: (replies[i + 8] || {}), + currentRoundShares: (replies[i + 8] || {}), currentRoundTimes: (replies[i + 11] || {}), maxRoundTime: 0, shareCount: 0, @@ -459,7 +502,31 @@ module.exports = function(logger, portalConfig, poolConfigs){ } catch(e) { jsonObj = null; } - if (jsonObj !== null) { + if (jsonObj !== null) { + //Anonymize paid amounts + let paymentIndex = 0; + for (var payment in jsonObj.amounts) { + Object.defineProperty(jsonObj.amounts, 'miner' + paymentIndex, Object.getOwnPropertyDescriptor(jsonObj.amounts, payment)); + delete jsonObj.amounts[payment]; + paymentIndex++; + } + + //Anonymize balances + let balanceIndex = 0; + for (var balance in jsonObj.balances) { + Object.defineProperty(jsonObj.balances, 'miner' + balanceIndex, Object.getOwnPropertyDescriptor(jsonObj.balances, balance)); + delete jsonObj.balances[balance]; + balanceIndex++; + } + + //Anonymize work + let workIndex = 0; + for (var work in jsonObj.work) { + Object.defineProperty(jsonObj.work, 'miner' + workIndex, Object.getOwnPropertyDescriptor(jsonObj.work, work)); + delete jsonObj.work[work]; + workIndex++; + } + coinStats.payments.push(jsonObj); } } @@ -491,103 +558,120 @@ module.exports = function(logger, portalConfig, poolConfigs){ Object.keys(allCoinStats).forEach(function(coin){ var coinStats = allCoinStats[coin]; coinStats.workers = {}; - coinStats.miners = {}; + coinStats.miners = {}; coinStats.shares = 0; coinStats.hashrates.forEach(function(ins){ var parts = ins.split(':'); var workerShares = parseFloat(parts[0]); - var miner = parts[1].split('.')[0]; + var miner = parts[1].split('.')[0]; var worker = parts[1]; - var diff = Math.round(parts[0] * 8192); + var diff = Math.round(parts[0] * 8192); if (workerShares > 0) { coinStats.shares += workerShares; - // build worker stats + // build worker stats if (worker in coinStats.workers) { coinStats.workers[worker].shares += workerShares; - coinStats.workers[worker].diff = diff; + coinStats.workers[worker].diff = diff; } else { coinStats.workers[worker] = { - name: worker, - diff: diff, + name: worker, + diff: diff, shares: workerShares, invalidshares: 0, - currRoundShares: 0, + currRoundShares: 0, currRoundTime: 0, - hashrate: null, + hashrate: null, hashrateString: null, - luckDays: null, - luckHours: null, - paid: 0, - balance: 0 + luckDays: null, + luckHours: null, + paid: 0, + balance: 0 }; - } - // build miner stats - if (miner in coinStats.miners) { - coinStats.miners[miner].shares += workerShares; - } else { - coinStats.miners[miner] = { - name: miner, - shares: workerShares, - invalidshares: 0, - currRoundShares: 0, + } + // build miner stats + if (miner in coinStats.miners) { + coinStats.miners[miner].shares += workerShares; + } else { + coinStats.miners[miner] = { + name: miner, + shares: workerShares, + invalidshares: 0, + currRoundShares: 0, currRoundTime: 0, - hashrate: null, - hashrateString: null, - luckDays: null, - luckHours: null - }; - } - } - else { - // build worker stats + hashrate: null, + hashrateString: null, + luckDays: null, + luckHours: null + }; + } + } else { + // build worker stats if (worker in coinStats.workers) { coinStats.workers[worker].invalidshares -= workerShares; // workerShares is negative number! - coinStats.workers[worker].diff = diff; + coinStats.workers[worker].diff = diff; } else { coinStats.workers[worker] = { - name: worker, - diff: diff, + name: worker, + diff: diff, shares: 0, - invalidshares: -workerShares, - currRoundShares: 0, + invalidshares: -workerShares, + currRoundShares: 0, currRoundTime: 0, - hashrate: null, + hashrate: null, hashrateString: null, - luckDays: null, - luckHours: null, - paid: 0, - balance: 0 + luckDays: null, + luckHours: null, + paid: 0, + balance: 0 }; - } - // build miner stats - if (miner in coinStats.miners) { - coinStats.miners[miner].invalidshares -= workerShares; // workerShares is negative number! - } else { - coinStats.miners[miner] = { - name: miner, - shares: 0, - invalidshares: -workerShares, - currRoundShares: 0, + } + // build miner stats + if (miner in coinStats.miners) { + coinStats.miners[miner].invalidshares -= workerShares; // workerShares is negative number! + } else { + coinStats.miners[miner] = { + name: miner, + shares: 0, + invalidshares: -workerShares, + currRoundShares: 0, currRoundTime: 0, - hashrate: null, - hashrateString: null, - luckDays: null, - luckHours: null - }; - } + hashrate: null, + hashrateString: null, + luckDays: null, + luckHours: null + }; + } } }); - + + //anonymize miners + let minerindex = 0; + for (var miner in coinStats.miners) { + Object.defineProperty(coinStats.miners, 'miner' + minerindex, Object.getOwnPropertyDescriptor(coinStats.miners, miner)); + coinStats.miners['miner' + minerindex].name = 'miner' + minerindex; + delete coinStats.miners[miner]; + minerindex++; + } + + //anonymize workers + let workerindex = 0; + for (var worker in coinStats.workers) { + Object.defineProperty(coinStats.workers, 'worker' + workerindex, Object.getOwnPropertyDescriptor(coinStats.workers, worker)); + coinStats.workers['worker' + workerindex].name = 'worker' + workerindex; + delete coinStats.workers[worker]; + workerindex++; + } + var shareMultiplier = Math.pow(2, 32) / algos[coinStats.algorithm].multiplier; coinStats.hashrate = shareMultiplier * coinStats.shares / portalConfig.website.stats.hashrateWindow; coinStats.hashrateString = _this.getReadableHashRateString(coinStats.hashrate); - + var _blocktime = 160; - var _networkHashRate = parseFloat(coinStats.poolStats.networkSols) * 1.2; - var _myHashRate = (coinStats.hashrate / 1000000) * 2; - coinStats.luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3); - coinStats.luckHours = ((_networkHashRate / _myHashRate * _blocktime) / (60 * 60)).toFixed(3); - coinStats.minerCount = Object.keys(coinStats.miners).length; + var _networkHashRate = parseFloat(coinStats.poolStats.networkSols) * 1.2; + var _myHashRate = (coinStats.hashrate / 1000000) * 2; + coinStats.luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3); + coinStats.luckHours = ((_networkHashRate / _myHashRate * _blocktime) / (60 * 60)).toFixed(3); + coinStats.minerCount = Object.keys(coinStats.miners).length; coinStats.workerCount = Object.keys(coinStats.workers).length; portalStats.global.workers += coinStats.workerCount; @@ -627,29 +711,29 @@ module.exports = function(logger, portalConfig, poolConfigs){ coinStats.shareCount = _shareTotal; coinStats.maxRoundTime = _maxTimeShare; coinStats.maxRoundTimeString = readableSeconds(_maxTimeShare); - + for (var worker in coinStats.workers) { - var _workerRate = shareMultiplier * coinStats.workers[worker].shares / portalConfig.website.stats.hashrateWindow; - var _wHashRate = (_workerRate / 1000000) * 2; - 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].hashrate = _workerRate; - coinStats.workers[worker].hashrateString = _this.getReadableHashRateString(_workerRate); - var miner = worker.split('.')[0]; - if (miner in coinStats.miners) { - coinStats.workers[worker].currRoundTime = coinStats.miners[miner].currRoundTime; - } + var _workerRate = shareMultiplier * coinStats.workers[worker].shares / portalConfig.website.stats.hashrateWindow; + var _wHashRate = (_workerRate / 1000000) * 2; + 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].hashrate = _workerRate; + coinStats.workers[worker].hashrateString = _this.getReadableHashRateString(_workerRate); + var miner = worker.split('.')[0]; + if (miner in coinStats.miners) { + coinStats.workers[worker].currRoundTime = coinStats.miners[miner].currRoundTime; + } } - for (var miner in coinStats.miners) { - var _workerRate = shareMultiplier * coinStats.miners[miner].shares / portalConfig.website.stats.hashrateWindow; - var _wHashRate = (_workerRate / 1000000) * 2; - 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].hashrate = _workerRate; - coinStats.miners[miner].hashrateString = _this.getReadableHashRateString(_workerRate); + for (var miner in coinStats.miners) { + var _workerRate = shareMultiplier * coinStats.miners[miner].shares / portalConfig.website.stats.hashrateWindow; + var _wHashRate = (_workerRate / 1000000) * 2; + 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].hashrate = _workerRate; + coinStats.miners[miner].hashrateString = _this.getReadableHashRateString(_workerRate); } - - // sort workers by name + + // sort workers by name coinStats.workers = sortWorkersByName(coinStats.workers); coinStats.miners = sortMinersByHashrate(coinStats.miners); @@ -666,7 +750,7 @@ module.exports = function(logger, portalConfig, poolConfigs){ portalStats.pools = sortPoolsByHashrate(portalStats.pools); _this.stats = portalStats; - + // save historical hashrate, not entire stats! var saveStats = JSON.parse(JSON.stringify(portalStats)); Object.keys(saveStats.pools).forEach(function(pool){ @@ -679,9 +763,9 @@ module.exports = function(logger, portalConfig, poolConfigs){ }); _this.statsString = JSON.stringify(saveStats); _this.statHistory.push(saveStats); - - addStatPoolHistory(portalStats); - + + addStatPoolHistory(portalStats); + var retentionTime = (((Date.now() / 1000) - portalConfig.website.stats.historicalRetention) | 0); for (var i = 0; i < _this.statHistory.length; i++){ @@ -701,42 +785,43 @@ module.exports = function(logger, portalConfig, poolConfigs){ if (err) logger.error(logSystem, 'Historics', 'Error adding stats to historics ' + JSON.stringify(err)); }); + callback(); }); }; function sortPoolsByName(objects) { - var newObject = {}; - var sortedArray = sortProperties(objects, 'name', false, false); - for (var i = 0; i < sortedArray.length; i++) { - var key = sortedArray[i][0]; - var value = sortedArray[i][1]; - newObject[key] = value; - } - return newObject; + var newObject = {}; + var sortedArray = sortProperties(objects, 'name', false, false); + for (var i = 0; i < sortedArray.length; i++) { + var key = sortedArray[i][0]; + var value = sortedArray[i][1]; + newObject[key] = value; + } + return newObject; } - + function sortPoolsByHashrate(objects) { - var newObject = {}; - var sortedArray = sortProperties(objects, 'hashrate', true, true); - for (var i = 0; i < sortedArray.length; i++) { - var key = sortedArray[i][0]; - var value = sortedArray[i][1]; - newObject[key] = value; - } - return newObject; + var newObject = {}; + var sortedArray = sortProperties(objects, 'hashrate', true, true); + for (var i = 0; i < sortedArray.length; i++) { + var key = sortedArray[i][0]; + var value = sortedArray[i][1]; + newObject[key] = value; + } + return newObject; } function sortPoolsByShares(objects) { - var newObject = {}; - var sortedArray = sortProperties(objects, 'shareSort', true, true); - for (var i = 0; i < sortedArray.length; i++) { - var key = sortedArray[i][0]; - var value = sortedArray[i][1]; - newObject[key] = value; - } - return newObject; + var newObject = {}; + var sortedArray = sortProperties(objects, 'shareSort', true, true); + for (var i = 0; i < sortedArray.length; i++) { + var key = sortedArray[i][0]; + var value = sortedArray[i][1]; + newObject[key] = value; + } + return newObject; } function sortBlocks(a, b) { @@ -746,56 +831,56 @@ module.exports = function(logger, portalConfig, poolConfigs){ if (as < bs) return 1; return 0; } - - function sortWorkersByName(objects) { - var newObject = {}; - var sortedArray = sortProperties(objects, 'name', false, false); - for (var i = 0; i < sortedArray.length; i++) { - var key = sortedArray[i][0]; - var value = sortedArray[i][1]; - newObject[key] = value; - } - return newObject; - } - - function sortMinersByHashrate(objects) { - var newObject = {}; - var sortedArray = sortProperties(objects, 'hashrate', true, true); - for (var i = 0; i < sortedArray.length; i++) { - var key = sortedArray[i][0]; - var value = sortedArray[i][1]; - newObject[key] = value; - } - return newObject; - } - - function sortWorkersByHashrate(a, b) { - if (a.hashrate === b.hashrate) { - return 0; - } - else { - return (a.hashrate < b.hashrate) ? -1 : 1; - } - } - + + function sortWorkersByName(objects) { + var newObject = {}; + var sortedArray = sortProperties(objects, 'name', false, false); + for (var i = 0; i < sortedArray.length; i++) { + var key = sortedArray[i][0]; + var value = sortedArray[i][1]; + newObject[key] = value; + } + return newObject; + } + + function sortMinersByHashrate(objects) { + var newObject = {}; + var sortedArray = sortProperties(objects, 'hashrate', true, true); + for (var i = 0; i < sortedArray.length; i++) { + var key = sortedArray[i][0]; + var value = sortedArray[i][1]; + newObject[key] = value; + } + return newObject; + } + + function sortWorkersByHashrate(a, b) { + if (a.hashrate === b.hashrate) { + return 0; + } + else { + return (a.hashrate < b.hashrate) ? -1 : 1; + } + } + this.getReadableHashRateString = function(hashrate){ - hashrate = (hashrate * 2); - if (hashrate < 1000000) { - return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s'; - } + hashrate = (hashrate * 2); + if (hashrate < 1000000) { + 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 i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1); hashrate = (hashrate/1000) / Math.pow(1000, i + 1); return hashrate.toFixed(2) + byteUnits[i]; }; - - function getReadableNetworkHashRateString(hashrate) { - hashrate = (hashrate * 1000000); - if (hashrate < 1000000) - return '0 Sol'; - 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); - hashrate = (hashrate/1000) / Math.pow(1000, i + 1); - return hashrate.toFixed(2) + byteUnits[i]; - } + + function getReadableNetworkHashRateString(hashrate) { + hashrate = (hashrate * 1000000); + if (hashrate < 1000000) + return '0 Sol'; + 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); + hashrate = (hashrate/1000) / Math.pow(1000, i + 1); + return hashrate.toFixed(2) + byteUnits[i]; + } }; diff --git a/website/default/static/miner_stats.js b/website/default/static/miner_stats.js index 36b53c3..3f23ffd 100644 --- a/website/default/static/miner_stats.js +++ b/website/default/static/miner_stats.js @@ -10,14 +10,14 @@ var totalPaid; var totalShares; function getReadableHashRateString(hashrate){ - hashrate = (hashrate * 2); - if (hashrate < 1000000) { - 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 i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1); - hashrate = (hashrate/1000) / Math.pow(1000, i + 1); - return hashrate.toFixed(2) + byteUnits[i]; + hashrate = (hashrate * 2); + if (hashrate < 1000000) { + 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 i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1); + hashrate = (hashrate/1000) / Math.pow(1000, i + 1); + return hashrate.toFixed(2) + byteUnits[i]; } function timeOfDayFormat(timestamp){ @@ -27,95 +27,95 @@ function timeOfDayFormat(timestamp){ } function getWorkerNameFromAddress(w) { - var worker = w; - if (w.split(".").length > 1) { - worker = w.split(".")[1]; - if (worker == null || worker.length < 1) { - worker = "noname"; - } - } else { - worker = "noname"; - } - return worker; + var worker = w; + if (w.split(".").length > 1) { + worker = w.split(".")[1]; + if (worker == null || worker.length < 1) { + worker = "noname"; + } + } else { + worker = "noname"; + } + return worker; } function buildChartData(){ var workers = {}; - for (var w in statData.history) { - var worker = getWorkerNameFromAddress(w); - var a = workers[worker] = (workers[worker] || { - hashrate: [] - }); - for (var wh in statData.history[w]) { - a.hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]); - } - if (a.hashrate.length > workerHistoryMax) { - workerHistoryMax = a.hashrate.length; - } - } - - var i=0; + for (var w in statData.history) { + var worker = getWorkerNameFromAddress(w); + var a = workers[worker] = (workers[worker] || { + hashrate: [] + }); + for (var wh in statData.history[w]) { + a.hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]); + } + if (a.hashrate.length > workerHistoryMax) { + workerHistoryMax = a.hashrate.length; + } + } + + var i=0; workerHashrateData = []; for (var worker in workers){ workerHashrateData.push({ key: worker, - disabled: (i > Math.min((_workerCount-1), 3)), + disabled: (i > Math.min((_workerCount-1), 3)), values: workers[worker].hashrate }); - i++; + i++; } } function updateChartData(){ var workers = {}; - for (var w in statData.history) { - var worker = getWorkerNameFromAddress(w); - // get a reference to lastest workerhistory - for (var wh in statData.history[w]) { } - //var wh = statData.history[w][statData.history[w].length - 1]; - var foundWorker = false; - for (var i = 0; i < workerHashrateData.length; i++) { - if (workerHashrateData[i].key === worker) { - foundWorker = true; - if (workerHashrateData[i].values.length >= workerHistoryMax) { - workerHashrateData[i].values.shift(); - } - workerHashrateData[i].values.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]); - break; - } - } - if (!foundWorker) { - var hashrate = []; - hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]); - workerHashrateData.push({ - key: worker, - values: hashrate - }); - rebuildWorkerDisplay(); - return true; - } - } - triggerChartUpdates(); - return false; + for (var w in statData.history) { + var worker = getWorkerNameFromAddress(w); + // get a reference to lastest workerhistory + for (var wh in statData.history[w]) { } + //var wh = statData.history[w][statData.history[w].length - 1]; + var foundWorker = false; + for (var i = 0; i < workerHashrateData.length; i++) { + if (workerHashrateData[i].key === worker) { + foundWorker = true; + if (workerHashrateData[i].values.length >= workerHistoryMax) { + workerHashrateData[i].values.shift(); + } + workerHashrateData[i].values.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]); + break; + } + } + if (!foundWorker) { + var hashrate = []; + hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]); + workerHashrateData.push({ + key: worker, + values: hashrate + }); + rebuildWorkerDisplay(); + return true; + } + } + triggerChartUpdates(); + return false; } function calculateAverageHashrate(worker) { - var count = 0; - var total = 1; - var avg = 0; - for (var i = 0; i < workerHashrateData.length; i++) { - count = 0; - for (var ii = 0; ii < workerHashrateData[i].values.length; ii++) { - if (worker == null || workerHashrateData[i].key === worker) { - count++; - avg += parseFloat(workerHashrateData[i].values[ii][1]); - } - } - if (count > total) - total = count; - } - avg = avg / total; - return avg; + var count = 0; + var total = 1; + var avg = 0; + for (var i = 0; i < workerHashrateData.length; i++) { + count = 0; + for (var ii = 0; ii < workerHashrateData[i].values.length; ii++) { + if (worker == null || workerHashrateData[i].key === worker) { + count++; + avg += parseFloat(workerHashrateData[i].values[ii][1]); + } + } + if (count > total) + total = count; + } + avg = avg / total; + return avg; } function triggerChartUpdates(){ @@ -141,67 +141,67 @@ function displayCharts() { } function updateStats() { - totalHash = statData.totalHash; - totalPaid = statData.paid; - totalBal = statData.balance; - totalImmature = statData.immature; - totalShares = statData.totalShares; - // do some calculations - var _blocktime = 250; - var _networkHashRate = parseFloat(statData.networkSols) * 1.2; - var _myHashRate = (totalHash / 1000000) * 2; - var luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3); - // update miner stats - $("#statsHashrate").text(getReadableHashRateString(totalHash)); - $("#statsHashrateAvg").text(getReadableHashRateString(calculateAverageHashrate(null))); - $("#statsLuckDays").text(luckDays); - $("#statsTotalImmature").text(totalImmature); - $("#statsTotalBal").text(totalBal); - $("#statsTotalPaid").text(totalPaid); - $("#statsTotalShares").text(totalShares.toFixed(2)); + totalHash = statData.totalHash; + totalPaid = statData.paid; + totalBal = statData.balance; + totalImmature = statData.immature; + totalShares = statData.totalShares; + // do some calculations + var _blocktime = 250; + var _networkHashRate = parseFloat(statData.networkSols) * 1.2; + var _myHashRate = (totalHash / 1000000) * 2; + var luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3); + // update miner stats + $("#statsHashrate").text(getReadableHashRateString(totalHash)); + $("#statsHashrateAvg").text(getReadableHashRateString(calculateAverageHashrate(null))); + $("#statsLuckDays").text(luckDays); + $("#statsTotalImmature").text(totalImmature); + $("#statsTotalBal").text(totalBal); + $("#statsTotalPaid").text(totalPaid); + $("#statsTotalShares").text(totalShares.toFixed(2)); } function updateWorkerStats() { - // update worker stats - var i=0; - for (var w in statData.workers) { i++; - var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, ''); - var saneWorkerName = getWorkerNameFromAddress(w); - $("#statsHashrate"+htmlSafeWorkerName).text(getReadableHashRateString(statData.workers[w].hashrate)); - $("#statsHashrateAvg"+htmlSafeWorkerName).text(getReadableHashRateString(calculateAverageHashrate(saneWorkerName))); - $("#statsLuckDays"+htmlSafeWorkerName).text(statData.workers[w].luckDays); - $("#statsPaid"+htmlSafeWorkerName).text(statData.workers[w].paid); - $("#statsBalance"+htmlSafeWorkerName).text(statData.workers[w].balance); - $("#statsShares"+htmlSafeWorkerName).text(Math.round(statData.workers[w].currRoundShares * 100) / 100); - $("#statsDiff"+htmlSafeWorkerName).text(statData.workers[w].diff); - } + // update worker stats + var i=0; + for (var w in statData.workers) { i++; + var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, ''); + var saneWorkerName = getWorkerNameFromAddress(w); + $("#statsHashrate"+htmlSafeWorkerName).text(getReadableHashRateString(statData.workers[w].hashrate)); + $("#statsHashrateAvg"+htmlSafeWorkerName).text(getReadableHashRateString(calculateAverageHashrate(saneWorkerName))); + $("#statsLuckDays"+htmlSafeWorkerName).text(statData.workers[w].luckDays); + $("#statsPaid"+htmlSafeWorkerName).text(statData.workers[w].paid); + $("#statsBalance"+htmlSafeWorkerName).text(statData.workers[w].balance); + $("#statsShares"+htmlSafeWorkerName).text(Math.round(statData.workers[w].currRoundShares * 100) / 100); + $("#statsDiff"+htmlSafeWorkerName).text(statData.workers[w].diff); + } } function addWorkerToDisplay(name, htmlSafeName, workerObj) { - var htmlToAdd = ""; - htmlToAdd = '
'; - if (htmlSafeName.indexOf("_") >= 0) { - htmlToAdd+= '
'+htmlSafeName.substr(htmlSafeName.indexOf("_")+1,htmlSafeName.length)+'
'; - } else { - htmlToAdd+= '
noname
'; - } - htmlToAdd+='
'+getReadableHashRateString(workerObj.hashrate)+' (Now)
'; - htmlToAdd+='
'+getReadableHashRateString(calculateAverageHashrate(name))+' (Avg)
'; - htmlToAdd+='
Diff: '+workerObj.diff+'
'; - htmlToAdd+='
Shares: '+(Math.round(workerObj.currRoundShares * 100) / 100)+'
'; - htmlToAdd+='
Luck '+workerObj.luckDays+' Days
'; - htmlToAdd+='
Bal: '+workerObj.balance+'
'; - htmlToAdd+='
Paid: '+workerObj.paid+'
'; - htmlToAdd+='
'; - $("#boxesWorkers").html($("#boxesWorkers").html()+htmlToAdd); + var htmlToAdd = ""; + htmlToAdd = '
'; + if (htmlSafeName.indexOf("_") >= 0) { + htmlToAdd+= '
'+htmlSafeName.substr(htmlSafeName.indexOf("_")+1,htmlSafeName.length)+'
'; + } else { + htmlToAdd+= '
noname
'; + } + htmlToAdd+='
'+getReadableHashRateString(workerObj.hashrate)+' (Now)
'; + htmlToAdd+='
'+getReadableHashRateString(calculateAverageHashrate(name))+' (Avg)
'; + htmlToAdd+='
Diff: '+workerObj.diff+'
'; + htmlToAdd+='
Shares: '+(Math.round(workerObj.currRoundShares * 100) / 100)+'
'; + htmlToAdd+='
Luck '+workerObj.luckDays+' Days
'; + htmlToAdd+='
Bal: '+workerObj.balance+'
'; + htmlToAdd+='
Paid: '+workerObj.paid+'
'; + htmlToAdd+='
'; + $("#boxesWorkers").html($("#boxesWorkers").html()+htmlToAdd); } function rebuildWorkerDisplay() { - $("#boxesWorkers").html(""); - var i=0; - for (var w in statData.workers) { i++; - var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, ''); - var saneWorkerName = getWorkerNameFromAddress(w); - addWorkerToDisplay(saneWorkerName, htmlSafeWorkerName, statData.workers[w]); - } + $("#boxesWorkers").html(""); + var i=0; + for (var w in statData.workers) { i++; + var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, ''); + var saneWorkerName = getWorkerNameFromAddress(w); + addWorkerToDisplay(saneWorkerName, htmlSafeWorkerName, statData.workers[w]); + } } // resize chart on window resize @@ -210,37 +210,37 @@ nv.utils.windowResize(triggerChartUpdates); // grab initial stats $.getJSON('/api/worker_stats?'+_miner, function(data){ statData = data; - for (var w in statData.workers) { _workerCount++; } - buildChartData(); - displayCharts(); - rebuildWorkerDisplay(); + for (var w in statData.workers) { _workerCount++; } + buildChartData(); + displayCharts(); + rebuildWorkerDisplay(); updateStats(); }); // live stat updates statsSource.addEventListener('message', function(e){ - // TODO, create miner_live_stats... - // miner_live_stats will return the same josn except without the worker history - // FOR NOW, use this to grab updated stats - $.getJSON('/api/worker_stats?'+_miner, function(data){ - statData = data; - // check for missing workers - var wc = 0; - var rebuilt = false; - // update worker stats - for (var w in statData.workers) { wc++; } - // TODO, this isn't 100% fool proof! - if (_workerCount != wc) { - if (_workerCount > wc) { - rebuildWorkerDisplay(); - rebuilt = true; - } - _workerCount = wc; - } - rebuilt = (rebuilt || updateChartData()); - updateStats(); - if (!rebuilt) { - updateWorkerStats(); - } - }); + // TODO, create miner_live_stats... + // miner_live_stats will return the same josn except without the worker history + // FOR NOW, use this to grab updated stats + $.getJSON('/api/worker_stats?'+_miner, function(data){ + statData = data; + // check for missing workers + var wc = 0; + var rebuilt = false; + // update worker stats + for (var w in statData.workers) { wc++; } + // TODO, this isn't 100% fool proof! + if (_workerCount != wc) { + if (_workerCount > wc) { + rebuildWorkerDisplay(); + rebuilt = true; + } + _workerCount = wc; + } + rebuilt = (rebuilt || updateChartData()); + updateStats(); + if (!rebuilt) { + updateWorkerStats(); + } + }); }); diff --git a/website/piratepool.io/index.html b/website/piratepool.io/index.html index 4e4c8d5..1f71b6f 100644 --- a/website/piratepool.io/index.html +++ b/website/piratepool.io/index.html @@ -7,7 +7,7 @@ piratepool.io - mining pool for PirateChain (ARRR) - the most private and anonymous mineable cryptocurrency - Pirate - + @@ -15,20 +15,21 @@ - + + - + - + @@ -93,9 +94,9 @@ {{=it.page}} diff --git a/website/piratepool.io/pages/getting_started.html b/website/piratepool.io/pages/getting_started.html index 411a82b..5885ff3 100644 --- a/website/piratepool.io/pages/getting_started.html +++ b/website/piratepool.io/pages/getting_started.html @@ -110,20 +110,20 @@

Optiminer

- optiminer-zcash -s {{=it.portalConfig.website.stratumHost}}:{{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} -u zs1nrn7h684wq4429pz8a20r49dmmhd3ey07u38f8m2n9du33ashd0xcnls3lfz0spdvn26z3r4jrv.myrigname -p x + optiminer-zcash -s {{=it.portalConfig.website.stratumHost}}:{{= Object.keys(it.poolsConfigs[Object.keys(it.poolsConfigs)[0]].ports)[0] }} -u zs1nrn7h684wq4429pz8a20r49dmmhd3ey07u38f8m2n9du33ashd0xcnls3lfz0spdvn26z3r4jrv.myrigname -p x
{{ } }}

Payments

-

Payouts are currently scheduled once every 4 hours with a minimum payout of 42 ARRR.

+

Payouts are currently scheduled once every 4 hours with a minimum payout of 21 ARRR.

There is a limit of ~200 recipients that can be included in a single payout, so the pool payouts are monitored and the min payout adjusted accordingly to ensure a constant flow of payments.

-

If payments stop going out, do not worry! Funds are safu! Blocks can still be found and will be credited to your worker! Please check the #pools-and-operators channel in discord to see if it's already being worked on.

+

If payments stop going out, do not worry! Funds are safu! Blocks can still be found and will be credited to your worker! Please check #piratepool in discord to see if it's already being worked on.

Pending blocks have not yet been scanned by the payment processor. After being scanned, blocks will need to receive both dPoW notarization and 10 confirmations before being actually paid out.

-

On your worker stats page, pending balance is the remaining estimated amount to be paid for blocks that - were scanned but not yet eligible for payout either because of - dPoW or min confirmations. +

On your worker stats page, pending balance is the remaining estimated amount to be paid for blocks that + were scanned but not yet eligible for payout either because of + dPoW or min confirmations. Balance includes blocks that were scanned and already paid out but you have not yet met the min payout.*

*Please note these 2 stats will only update when the payment processor runs which is currently every 4 hours.

Payments that show up on the payments page initially are in the process of constructing the z transaction. Once the transaction actually broadcasts to the network, the blocks paid out will become hyperlinked to the explorer and then should arrive in your wallet in the next block or two.

@@ -131,7 +131,7 @@

Generate Wallet and Address

-

The Agama GUI Wallet for PIRATE is available. For Agama support please visit #newpirates on Discord

+

The PirateOceanQT for PIRATE is available. For wallet support please visit #newpirates on Discord

CLI Wallet:

    @@ -172,7 +172,7 @@
  1. Bminer Lite
  2. Claymore's ZCash/BTG AMD GPU Miner
  3. Optiminer AMD
  4. - +
diff --git a/website/piratepool.io/pages/home.html b/website/piratepool.io/pages/home.html index f1a751f..60e3ce5 100644 --- a/website/piratepool.io/pages/home.html +++ b/website/piratepool.io/pages/home.html @@ -2,8 +2,11 @@
- 300K+ ARRR donated to Onboarding/Dev and Marketing funds, made possible via KMD notary node income.
- Thank you for all who voted me into KMD notary node for 2019 in SH! ❤ 🐸
+ + + Payout strategy changed to PPLNT with 1 hour payout frequency! Join #piratepool for support and discussion! 🐸 +
piratepool.io - knomp @@ -11,8 +14,15 @@

piratepool.io

Mining Pool For PirateChain (ARRR)

+

+ Donating 66% of the pool fee to the PirateChain project!
+ 33% to PIRATE dev and onboarding fund +
+ 33% to PIRATE Marketing!
+

+ @@ -36,19 +46,15 @@

- 1/3rd of the pool fee is donated to the PIRATE onboarding fund and
- 1/3rd is donated to PIRATE Marketing!
-

-

- Sprout stratum has been retired! Final Sprout Payouts Report + Download the latest PirateOcean wallet and create a sapling address (starts with zs1) and connect to the new stratum ports labeled as arrr on Getting Started.

- Download the latest Agama wallet and create a sapling address (starts with zs1) and connect to the new stratum ports labeled as arrr on Getting Started. + {{ /* Sprout stratum has been retired! Final Sprout Payouts Report */ }}

-

+

diff --git a/website/piratepool.io/pages/miner_stats.html b/website/piratepool.io/pages/miner_stats.html index 535439d..8ff9fe8 100644 --- a/website/piratepool.io/pages/miner_stats.html +++ b/website/piratepool.io/pages/miner_stats.html @@ -1,5 +1,11 @@ {{ function middleEllipsis(x) { return x.length > 40 ? x.substring(0, 20) + '...' + x.substring(x.length-20, x.length): x; } }} +{{ function checkCompromised(m) { var compromised = ['zs10jprfefpt2ra88u2ml96nzh3dmlqqqfeha5l7g0x0s0d2awme0eqfyt4w7r7pee0na8tcz6ezzj', 'zs12urwtysy5rkqzy3xgaxeu9g3ezf4fr0wfq44xrnf48uq6ug8qfxp059lms06khekppquvzadxyf', 'zs16sk9n6lyc8ulzkrf5xc72cr07hkyjvvj2emeqjel7xmn90qaf9mj2m8vt34yw45l7syqxlmfe5v', 'zs16xlsu48grwgsr29c9ztcn8jl0s47rtyucv3dw0n2e6y00w0wtt3d4ukqk4sq4sycrdhtxxg7g3k', 'zs19whs7s29a2kn5d4s8mpdad0m4setz86sq64kpv0t2v263mrqvuducp6nlmlwvynltam9zm9mr0p', 'zs1au66ft2gyu8ylgkw70vy4we2ktzum52esl94875w44mu8cmw2dcwfc29kahgmvfwcagwy39ctee', 'zs1c83zjak7ealmn92hejmqmjc7h3ysvglc9n95z79dhajth4fmhmrnv5zxdkufzg6l489y6hwf694', 'zs1d9myt9rpvu6grsl3ntg9wv0dfuj4vhp4rr0m3f940tt6fpxy8adpx4uzs7hgtclqtqe4wq2sjr8', 'zs1df3t2wpdmsjmzd7pwet67grfgr900fg6hjy97hl9vv0tkf7w5eye2zur6xhhzhfxdceu740g04g', 'zs1g342mavfn70xf5pycn8xwu2zsc4vq3fe8zzg99dfkdsdr39rqszvnuzxdp238d3uaqg96mmrclq', 'zs1gp9egrus6zrjqmea23nae7pzpxdy9jt3w65j8netsrcctl3g9e0lrag4tgvctw3r7rhryj4f4ua', 'zs1jttxxfwurarqw3cmkf94ygfs8skh7xxjf83wuh4awq6zjcee9p804p6aurmxv5q02f2uxc3qm93', 'zs1kqaakh9tw8uj039e9hzkh0444rw533uh8r5http8mfjuakmglqyqrjvd2ertnk8j9jlvvnzne9r', 'zs1lpp9qdtj9tkqjfj64wkcprvp2kflpu8cxz8fgclx80uuu4ajsmslkxkx0fh49cpw2yyhxwk0yzg', 'zs1pd047rvjf6es3ypx6vnl7vgnngmt3mkegn4vjtymfy26rxzp97mpjw5y2gkmyljmk99qs2wa4c0', 'zs1qsr5r8fp9scdz4wt08h4uxnlmefl0dmukuzxzs3f8wx6tk6ged399c9taphhx0asagryjkqgya7', 'zs1r4kfr08dm5yx60yg535dzhnpg8m8s4dl8ap42exkwm6699prpw9zu8sgj6xjd5efmrnj6p4u0an', 'zs1sfj20kyt95sfvll20lraw5q22q2aagw2r3pcdgtlaw4epc9sdwymxzdsge8c84f707ytqpjlnx4', 'zs1stzrmj7rfwr8g0hcsgs7aln0vxwcss6h7qfvzkyf9f6vuupeq6eqhrx7kwa0kmm5dawf7f9j8hr', 'zs1u7sy6prj270ucxwcwh9sh7vr33lnlgs6a95nt4hzgwxwvtcesu240px90822mffc0epf2kjlrjq', 'zs1ued52v4gv83yrguw4gpp4j85mtz9euedmwlszqmldl99cgefz8tz4y60ttjgm4avpqegyhnesns', 'zs1uhnyckurr2x4e8ak6ffqes4ggth8n2vxlzyksd8ufv9zltdhggdnxcx4q2jfn8tuea3f7w4yevs', 'zs1v569xvf7klgw8ylgf0dvtd92dtmu669xcqv05qvxud78nt4zwwcjdz046ghq7lvs4r0d227sgrv', 'zs1xl7l6sn0r5nsa6cex87yp3z7j2mj9jgf32dng6qqp7ym66s8wkx9lykmd896uq62e5xlq2mkaqq', 'zs1yxspuhm7fd5ffrjlmxtsyuryaj983paurt794rg87ln98ekdsugexl7kfvjw97ejhv66ytd3454', 'zs1yyeyhf856aag8vxlq4mkhjs8qjrlxfzz67s4jgjazpedrqfj62tr4zkp3tsj6cgc3hggq4t5raf', 'zs1z4aqxzy2krpvu45mfqes74a20yjmeuxlj0s4x89zr932panatzsfh8wf90qulh5683cgg9q0u2v']; return compromised.indexOf(m) > -1; } }}
+ {{ if (checkCompromised(it.stats.address)) { }} +
+ Your wallet address was possibly comporomised! Please visit discord for more details! +
+ {{ } }}
@@ -25,4 +31,4 @@ var _workerCount = 0; document.querySelector('main').appendChild(document.createElement('script')).src = '/static/miner_stats.js'; -
\ No newline at end of file +
diff --git a/website/piratepool.io/pages/payments.html b/website/piratepool.io/pages/payments.html index ea1c5af..02986ae 100644 --- a/website/piratepool.io/pages/payments.html +++ b/website/piratepool.io/pages/payments.html @@ -1,11 +1,11 @@ -{{ -function readableDate(a){ - return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC'; +{{ +function readableDate(a){ + return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC'; } -function bigNumber(x){ - return (x > 1000000000000) ? (x / 1000000000000).toFixed(1) + 'T' : (x > 1000000000) ? (x / 1000000000).toFixed(1) + 'B' : (x > 1000000) ? (x / 1000000).toFixed(1) + 'M' : (x > 1000) ? (x / 1000).toFixed(1) + 'K' : x.toFixed(1); +function bigNumber(x){ + return (x > 1000000000000) ? (x / 1000000000000).toFixed(1) + 'T' : (x > 1000000000) ? (x / 1000000000).toFixed(1) + 'B' : (x > 1000000) ? (x / 1000000).toFixed(1) + 'M' : (x > 1000) ? (x / 1000).toFixed(1) + 'K' : x.toFixed(1); } -function timeTil(x){ +function timeTil(x){ return (x < 0) ? 'Now' : (x > 86400) ? (x/86400).toFixed(1) + ' Days' : (x > 3600) ? (x/3600).toFixed(1) + ' Hours' : (x > 60) ? (x / 60).toFixed(1) + ' Minutes' : x + ' Seconds'; } function timeTilNumbers(timestamp) { @@ -13,7 +13,11 @@ function timeTilNumbers(timestamp) { } }}
-
Payout frequency has been changed to 4 hours because miners have been mining to exchange addresses…
+
+ + + Payout strategy changed to PPLNT with 1 hour payout frequency! Join #piratepool for support and discussion! 🐸 +
{{ for(var pool in it.stats.pools) { }}
{{=it.stats.pools[pool].name}} Payments   
@@ -37,7 +41,7 @@ function timeTilNumbers(timestamp) {
{{ for(var p in it.stats.pools[pool].payments) { }} -
Algorithm: Equihash
Payout Strategy: PPLNT
Payout Frequency: {{=it.poolsConfigs['arrr'].paymentProcessing.paymentInterval/60/60}} Hours
Min Payout: {{=it.poolsConfigs['arrr'].paymentProcessing.minimumPayment}} ARRR
Pool Fee: 1%
+ Blocks: [{{=it.stats.pools[pool].payments[p].blocks.length}}] {{if (String(it.stats.pools[pool].name) == "KMD") { }} {{=it.stats.pools[pool].payments[p].blocks}} @@ -57,8 +61,8 @@ function timeTilNumbers(timestamp) {
{{ } }} - + -
\ No newline at end of file +
diff --git a/website/piratepool.io/pages/stats.html b/website/piratepool.io/pages/stats.html index 4828ae4..9a389ad 100644 --- a/website/piratepool.io/pages/stats.html +++ b/website/piratepool.io/pages/stats.html @@ -3,6 +3,10 @@ {{ function bigNumber(x){ return (x > 1000000000000) ? (x / 1000000000000).toFixed(1) + 'T' : (x > 1000000000) ? (x / 1000000000).toFixed(1) + 'B' : (x > 1000000) ? (x / 1000000).toFixed(1) + 'M' : (x > 1000) ? (x / 1000).toFixed(1) + 'K' : x.toFixed(1); } }} {{ function middleEllipsis(x) { return x.length > 40 ? x.substring(0, 15) + '...' + x.substring(x.length-15, x.length): x; } }}
+
+ + Payout strategy changed to PPLNT with 1 hour payout frequency! Join #piratepool for support and discussion! 🐸 +

Pool Hashrate

@@ -35,7 +39,7 @@
  • Block Height: {{=it.stats.pools[pool].poolStats.networkBlocks}}
  • Network Hash/s: {{=it.stats.pools[pool].poolStats.networkSolsString}}
  • Difficulty: {{=bigNumber(it.stats.pools[pool].poolStats.networkDiff)}}
  • -
  • Total Supply: {{=(it.stats.pools[pool].poolStats.networkBlocks*256).toLocaleString('en')}}
  • +
  • Total Supply: {{=(99554304+(it.stats.pools[pool].poolStats.networkBlocks-388884)*128).toLocaleString('en')}}
  • Node Connections: {{=it.stats.pools[pool].poolStats.networkConnections}}
  • @@ -79,7 +83,6 @@ Pending {{ } }}
    -
    Mined By: {{=middleEllipsis(block[3])}}
    {{ } }} @@ -95,7 +98,6 @@ {{ } }} Paid
    -
    Mined By: {{=middleEllipsis(block[3])}}
    {{ } }} diff --git a/website/piratepool.io/pages/workers.html b/website/piratepool.io/pages/workers.html index 8bdd7f4..966149d 100644 --- a/website/piratepool.io/pages/workers.html +++ b/website/piratepool.io/pages/workers.html @@ -6,7 +6,7 @@
    - Miner Lookup: + Miner Lookup: @@ -24,22 +24,24 @@ - + + {{ var minerindex = 0; }} {{ for(var worker in it.stats.pools[pool].miners) { }} + {{ minerindex++; }} {{var workerstat = it.stats.pools[pool].miners[worker];}} - - + + - {{ } }} + {{ } }}
    AddressMiner Shares Efficiency Hashrate
    Address: {{=middleEllipsis(worker)}}
    Miner #{{=minerindex}} Shares: {{=bigNumber(workerstat.currRoundShares)}} Efficiency: {{? workerstat.shares > 0}} {{=Math.floor(10000 * workerstat.shares / (workerstat.shares + workerstat.invalidshares)) / 100}}% {{??}} 0% {{?}} Hashrate: {{=workerstat.hashrateString}}
    @@ -48,4 +50,4 @@ -
    \ No newline at end of file + diff --git a/website/piratepool.io/static/payments.js b/website/piratepool.io/static/payments.js index 0cad5b2..f9f275a 100644 --- a/website/piratepool.io/static/payments.js +++ b/website/piratepool.io/static/payments.js @@ -49,12 +49,11 @@ $(function() { console.log('Added new payment!'); } } else { - //Update existing (txid) for private chains + //Update existing (txid) for private chains if (typeof paymentstat.txid !== 'undefined' && (String(stats.pools[pool].name).startsWith("pirate") || String(stats.pools[pool].name).startsWith("arrr")) ) { - var explorer = 'https://explorer.pirate.black/tx/'; var paymentblock = document.querySelector('#payment' + pool + paymentstat.time + ' .paymentblocks a'); - paymentblock.setAttribute('href', explorer + paymentstat.txid); + paymentblock.setAttribute('href', explorerURL + 'tx/' + paymentstat.txid); paymentblock.setAttribute('target', '_blank'); paymentblock.setAttribute('rel', 'noopener noreferrer'); } @@ -81,4 +80,4 @@ $(function() { } } }); -}); \ No newline at end of file +}); diff --git a/website/piratepool.io/static/stats.js b/website/piratepool.io/static/stats.js index e64c284..95f6d21 100644 --- a/website/piratepool.io/static/stats.js +++ b/website/piratepool.io/static/stats.js @@ -58,7 +58,7 @@ $(function() { insertPendingBlock.setAttribute('title', 'Waiting for payment processor to review'); insertPendingBlock.style.opacity = 0; insertPendingBlock.style.transition = 'opacity 1s ease-in'; - insertPendingBlock.innerHTML = '
    Block: ' + checkblock[2] + '' + readableDate(checkblock[4]) + 'Pending
    Mined By: ' + middleEllipsis(checkblock[3]) + '
    '; + insertPendingBlock.innerHTML = '
    Block: ' + checkblock[2] + '' + readableDate(checkblock[4]) + 'Pending
    '; if (parseInt(checkblock[2]) > prevHeight) { poolFoundList.insertBefore(insertPendingBlock, poolFoundList.firstChild); @@ -85,7 +85,7 @@ $(function() { insertPendingBlock.id = 'blocksFoundPaid' + checkblock[0]; insertPendingBlock.setAttribute('class', 'blocksFoundPaid'); insertPendingBlock.setAttribute('title', 'Payment sent, please check payments page'); - insertPendingBlock.innerHTML = '
    Block: ' + checkblock[2] + '' + readableDate(checkblock[4]) + 'Pending
    Mined By: ' + middleEllipsis(checkblock[3]) + '
    '; + insertPendingBlock.innerHTML = '
    Block: ' + checkblock[2] + '' + readableDate(checkblock[4]) + 'Pending
    '; poolFoundList.insertBefore(insertPendingBlock, document.querySelectorAll('.blocksFoundList .blocksFoundPaid')[0]); } @@ -146,4 +146,4 @@ function displayCharts(){ function triggerChartUpdates(){ poolHashrateChart.update(); -} \ No newline at end of file +} diff --git a/website/piratepool.io/static/style.css b/website/piratepool.io/static/style.css index a208032..ccb268a 100644 --- a/website/piratepool.io/static/style.css +++ b/website/piratepool.io/static/style.css @@ -13,7 +13,7 @@ } html, body, button, input, select, textarea, -.pure-g [class *= "pure-u"] { +.pure-g [class *= "pure-u"] { font-family: 'Roboto', sans-serif; line-height: 1.4em; } @@ -99,8 +99,8 @@ footer a { } .highlight { - color:var(--gold); - font-weight:900; + color:var(--gold); + font-weight:900; } .muted { @@ -117,11 +117,11 @@ br.responsiveonly { } .alertbar { - color:var(--gold); + color:var(--gold); font-weight:900; text-shadow: -3px -3px 0px #000; text-align:center; - padding:10px 0; + padding:10px 0; background-color:var(--dark-blue); } @@ -134,7 +134,7 @@ header .pure-menu { } header .home-menu, -header .home-menu .pure-menu-list, +header .home-menu .pure-menu-list, header .home-menu .pure-menu-list li { display: flex; align-items: center; @@ -151,7 +151,7 @@ header .home-menu a { transition:background-color 0.33s ease-out, color 0.33s ease-out; } -header .home-menu a:hover, +header .home-menu a:hover, header .home-menu .pure-menu-selected a { color: #FFF!important; background-color: var(--gold); @@ -162,7 +162,7 @@ header .home-menu li a i { margin-right:5px; } -.pure-menu.pure-menu-open, +.pure-menu.pure-menu-open, .pure-menu.pure-menu-horizontal li .pure-menu-children { border:none; } @@ -208,7 +208,7 @@ header .home-menu li a i { background-color: var(--dark-blue); color: white; max-width:640px; - margin:15px auto 10px auto; + margin:15px auto 10px auto; padding:5px 10px 10px; box-shadow: -1px -1px 0 #000; } @@ -265,7 +265,7 @@ header .home-menu li a i { } .blocksFoundList .countLabel { - float:right; + float:right; font-size:0.8em; line-height:1em; } @@ -298,7 +298,7 @@ header .home-menu li a i { } .blocksFoundHeader > div:nth-child(2) { - font-size:0.8em; + font-size:0.8em; text-align:right; } @@ -349,6 +349,11 @@ header .home-menu li a i { } .paymentblocks .fade { + display:none; +} + +.paymentblocksexpand .fade { + display:block; z-index: 10; background-image: linear-gradient(to bottom, rgba(20, 20, 20, 0), rgba(20, 20, 20, 1) 90%); width: 95%; @@ -370,11 +375,11 @@ header .home-menu li a i { transition: max-height 0.2s ease-out 0.33s; } -.paymentblocks a:hover { +.paymentblocksexpand a:hover { max-height: 1000px; } -.paymentblocks a:hover + .fade { +.paymentblocksexpand a:hover + .fade { opacity:0; } @@ -444,9 +449,9 @@ header .home-menu li a i { .nv-group.nv-series-0, .nv-series:first-of-type .nv-legend-symbol { - stroke-opacity: 1; - fill-opacity: 0.5; - fill: var(--gold)!important; + stroke-opacity: 1; + fill-opacity: 0.5; + fill: var(--gold)!important; stroke: var(--gold)!important; } @@ -468,32 +473,32 @@ header .home-menu li a i { font-size: 1em; line-height: 1em; } - + .home-menu li a i { margin-right:0; } - .pure-table { + .pure-table { border-top: 1px solid var(--grey); } - table, thead, tbody, th, td, tr { - display: block; + table, thead, tbody, th, td, tr { + display: block; } - thead tr { + thead tr { display:none; visiblity:hidden; } - tr { + tr { border-bottom: 1px solid var(--grey); } - td { + td { border: none; position: relative; - + } .pure-table td { @@ -508,11 +513,11 @@ header .home-menu li a i { br.responsiveonly { display:initial; } - + .responsivehide { display:none; } - + .boxWelcome h1, .boxWelcome h2 { text-align:center!important; @@ -525,7 +530,7 @@ header .home-menu li a i { .blocksFoundHeader > div { text-align:center!important; } - + .blocksFoundList > div { flex: 1; } @@ -534,17 +539,17 @@ header .home-menu li a i { display:inline-block; visibility:visible; } - + .pure-responsive-disable, .flex-responsive-disable { width: 100%; } - + .paymentblocks a { display:inline; } - + .paymentblocks .fade { display:none; } -} \ No newline at end of file +} diff --git a/website/piratepool.io/static/workers.js b/website/piratepool.io/static/workers.js index 4ec41aa..7cecee4 100644 --- a/website/piratepool.io/static/workers.js +++ b/website/piratepool.io/static/workers.js @@ -12,32 +12,34 @@ $(function() { for (var f = 0; f < poolKeys.length; f++) { var pool = poolKeys[f]; var sharesTotal = 0; + var minerIndex = 0; for (var addr in stats.pools[pool].miners) { + minerIndex++; var workerstat = stats.pools[pool].miners[addr]; sharesTotal += parseFloat(workerstat.shares); - var existingRow = document.querySelector('#workers' + pool + ' #worker' + addr); + var existingRow = document.querySelector('#workers' + pool + ' #worker' + minerIndex); var minerEfficiency = ( workerstat.shares > 0 ) ? Math.floor(10000 * workerstat.shares / (workerstat.shares + workerstat.invalidshares)) / 100 : 0; - + if (existingRow == null) { //Add new var insertMinerTr = document.createElement('tr'); - insertMinerTr.id = 'worker' + addr; + insertMinerTr.id = 'worker' + minerIndex; insertMinerTr.setAttribute('data-hashrate', workerstat.hashrate); - insertMinerTr.innerHTML = ' Address: '+ middleEllipsis(addr, 20) + ''; + insertMinerTr.innerHTML = 'Miner #'+ minerIndex +''; insertMinerTr.innerHTML += ' Shares: ' + bigNumber(workerstat.shares) + ''; insertMinerTr.innerHTML += ' Efficiency: ' + minerEfficiency + '%'; insertMinerTr.innerHTML += ' Hashrate: ' + workerstat.hashrateString + ''; document.querySelector('#workers' + pool + ' .poolMinerTable tbody').appendChild(insertMinerTr); - console.log('Added new miner! [' + addr + ']'); + console.log('Added new miner! [' + minerIndex + ']'); } else { //Update existing - document.querySelector('#workers' + pool + ' #worker' + addr + ' td:nth-child(2) span:nth-child(2)').innerHTML = bigNumber(workerstat.shares); - document.querySelector('#workers' + pool + ' #worker' + addr + ' td:nth-child(3) span:nth-child(2)').innerHTML = minerEfficiency + '%'; - document.querySelector('#workers' + pool + ' #worker' + addr + ' td:nth-child(4) span:nth-child(2)').innerHTML = workerstat.hashrateString; - document.querySelector('#workers' + pool + ' #worker' + addr).setAttribute('data-hashrate', workerstat.hashrate); + document.querySelector('#workers' + pool + ' #worker' + minerIndex + ' td:nth-child(2) span:nth-child(2)').innerHTML = bigNumber(workerstat.shares); + document.querySelector('#workers' + pool + ' #worker' + minerIndex + ' td:nth-child(3) span:nth-child(2)').innerHTML = minerEfficiency + '%'; + document.querySelector('#workers' + pool + ' #worker' + minerIndex + ' td:nth-child(4) span:nth-child(2)').innerHTML = workerstat.hashrateString; + document.querySelector('#workers' + pool + ' #worker' + minerIndex).setAttribute('data-hashrate', workerstat.hashrate); } } @@ -76,4 +78,4 @@ function searchKeyPress(e) return false; } return true; -} \ No newline at end of file +}