diff --git a/coins/zcash.json b/coins/zcash.json index 415f716..4573970 100644 --- a/coins/zcash.json +++ b/coins/zcash.json @@ -2,7 +2,7 @@ "name": "zcash", "symbol": "zec", "algorithm": "equihash", - + "requireShielding": true, "payFoundersReward": true, "percentFoundersReward": 20, "maxFoundersRewardBlockHeight": 849999, diff --git a/coins/zcash_testnet.json b/coins/zcash_testnet.json index dd3c8e5..3c087dc 100644 --- a/coins/zcash_testnet.json +++ b/coins/zcash_testnet.json @@ -2,23 +2,23 @@ "name": "zcash_testnet", "symbol": "taz", "algorithm": "equihash", - + "requireShielding": true, "payFoundersReward": true, "percentFoundersReward": 20, "maxFoundersRewardBlockHeight": 849999, "foundersRewardAddressChangeInterval": 17709.3125, - "vFoundersRewardAddress": [ - "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543", "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2", "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy", - "t2BkYdVCHzvTJJUTx4yZB8qeegD8QsPx8bo", "t2J8q1xH1EuigJ52MfExyyjYtN3VgvshKDf", "t2Crq9mydTm37kZokC68HzT6yez3t2FBnFj", "t2EaMPUiQ1kthqcP5UEkF42CAFKJqXCkXC9", - "t2F9dtQc63JDDyrhnfpzvVYTJcr57MkqA12", "t2LPirmnfYSZc481GgZBa6xUGcoovfytBnC", "t26xfxoSw2UV9Pe5o3C8V4YybQD4SESfxtp", "t2D3k4fNdErd66YxtvXEdft9xuLoKD7CcVo", - "t2DWYBkxKNivdmsMiivNJzutaQGqmoRjRnL", "t2C3kFF9iQRxfc4B9zgbWo4dQLLqzqjpuGQ", "t2MnT5tzu9HSKcppRyUNwoTp8MUueuSGNaB", "t2AREsWdoW1F8EQYsScsjkgqobmgrkKeUkK", - "t2Vf4wKcJ3ZFtLj4jezUUKkwYR92BLHn5UT", "t2K3fdViH6R5tRuXLphKyoYXyZhyWGghDNY", "t2VEn3KiKyHSGyzd3nDw6ESWtaCQHwuv9WC", "t2F8XouqdNMq6zzEvxQXHV1TjwZRHwRg8gC", - "t2BS7Mrbaef3fA4xrmkvDisFVXVrRBnZ6Qj", "t2FuSwoLCdBVPwdZuYoHrEzxAb9qy4qjbnL", "t2SX3U8NtrT6gz5Db1AtQCSGjrpptr8JC6h", "t2V51gZNSoJ5kRL74bf9YTtbZuv8Fcqx2FH", - "t2FyTsLjjdm4jeVwir4xzj7FAkUidbr1b4R", "t2EYbGLekmpqHyn8UBF6kqpahrYm7D6N1Le", "t2NQTrStZHtJECNFT3dUBLYA9AErxPCmkka", "t2GSWZZJzoesYxfPTWXkFn5UaxjiYxGBU2a", - "t2RpffkzyLRevGM3w9aWdqMX6bd8uuAK3vn", "t2JzjoQqnuXtTGSN7k7yk5keURBGvYofh1d", "t2AEefc72ieTnsXKmgK2bZNckiwvZe3oPNL", "t2NNs3ZGZFsNj2wvmVd8BSwSfvETgiLrD8J", - "t2ECCQPVcxUCSSQopdNquguEPE14HsVfcUn", "t2JabDUkG8TaqVKYfqDJ3rqkVdHKp6hwXvG", "t2FGzW5Zdc8Cy98ZKmRygsVGi6oKcmYir9n", "t2DUD8a21FtEFn42oVLp5NGbogY13uyjy9t", - "t2UjVSd3zheHPgAkuX8WQW2CiC9xHQ8EvWp", "t2TBUAhELyHUn8i6SXYsXz5Lmy7kDzA1uT5", "t2Tz3uCyhP6eizUWDc3bGH7XUC9GQsEyQNc", "t2NysJSZtLwMLWEJ6MH3BsxRh6h27mNcsSy", - "t2KXJVVyyrjVxxSeazbY9ksGyft4qsXUNm9", "t2J9YYtH31cveiLZzjaE4AcuwVho6qjTNzp", "t2QgvW4sP9zaGpPMH1GRzy7cpydmuRfB4AZ", "t2NDTJP9MosKpyFPHJmfjc5pGCvAU58XGa4", - "t29pHDBWq7qN4EjwSEHg8wEqYe9pkmVrtRP", "t2Ez9KM8VJLuArcxuEkNRAkhNvidKkzXcjJ", "t2D5y7J5fpXajLbGrMBQkFg2mFN8fo3n8cX", "t2UV2wr1PTaUiybpkV3FdSdGxUJeZdZztyt" - ] + "vFoundersRewardAddress": [ + "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543", "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2", "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy", + "t2BkYdVCHzvTJJUTx4yZB8qeegD8QsPx8bo", "t2J8q1xH1EuigJ52MfExyyjYtN3VgvshKDf", "t2Crq9mydTm37kZokC68HzT6yez3t2FBnFj", "t2EaMPUiQ1kthqcP5UEkF42CAFKJqXCkXC9", + "t2F9dtQc63JDDyrhnfpzvVYTJcr57MkqA12", "t2LPirmnfYSZc481GgZBa6xUGcoovfytBnC", "t26xfxoSw2UV9Pe5o3C8V4YybQD4SESfxtp", "t2D3k4fNdErd66YxtvXEdft9xuLoKD7CcVo", + "t2DWYBkxKNivdmsMiivNJzutaQGqmoRjRnL", "t2C3kFF9iQRxfc4B9zgbWo4dQLLqzqjpuGQ", "t2MnT5tzu9HSKcppRyUNwoTp8MUueuSGNaB", "t2AREsWdoW1F8EQYsScsjkgqobmgrkKeUkK", + "t2Vf4wKcJ3ZFtLj4jezUUKkwYR92BLHn5UT", "t2K3fdViH6R5tRuXLphKyoYXyZhyWGghDNY", "t2VEn3KiKyHSGyzd3nDw6ESWtaCQHwuv9WC", "t2F8XouqdNMq6zzEvxQXHV1TjwZRHwRg8gC", + "t2BS7Mrbaef3fA4xrmkvDisFVXVrRBnZ6Qj", "t2FuSwoLCdBVPwdZuYoHrEzxAb9qy4qjbnL", "t2SX3U8NtrT6gz5Db1AtQCSGjrpptr8JC6h", "t2V51gZNSoJ5kRL74bf9YTtbZuv8Fcqx2FH", + "t2FyTsLjjdm4jeVwir4xzj7FAkUidbr1b4R", "t2EYbGLekmpqHyn8UBF6kqpahrYm7D6N1Le", "t2NQTrStZHtJECNFT3dUBLYA9AErxPCmkka", "t2GSWZZJzoesYxfPTWXkFn5UaxjiYxGBU2a", + "t2RpffkzyLRevGM3w9aWdqMX6bd8uuAK3vn", "t2JzjoQqnuXtTGSN7k7yk5keURBGvYofh1d", "t2AEefc72ieTnsXKmgK2bZNckiwvZe3oPNL", "t2NNs3ZGZFsNj2wvmVd8BSwSfvETgiLrD8J", + "t2ECCQPVcxUCSSQopdNquguEPE14HsVfcUn", "t2JabDUkG8TaqVKYfqDJ3rqkVdHKp6hwXvG", "t2FGzW5Zdc8Cy98ZKmRygsVGi6oKcmYir9n", "t2DUD8a21FtEFn42oVLp5NGbogY13uyjy9t", + "t2UjVSd3zheHPgAkuX8WQW2CiC9xHQ8EvWp", "t2TBUAhELyHUn8i6SXYsXz5Lmy7kDzA1uT5", "t2Tz3uCyhP6eizUWDc3bGH7XUC9GQsEyQNc", "t2NysJSZtLwMLWEJ6MH3BsxRh6h27mNcsSy", + "t2KXJVVyyrjVxxSeazbY9ksGyft4qsXUNm9", "t2J9YYtH31cveiLZzjaE4AcuwVho6qjTNzp", "t2QgvW4sP9zaGpPMH1GRzy7cpydmuRfB4AZ", "t2NDTJP9MosKpyFPHJmfjc5pGCvAU58XGa4", + "t29pHDBWq7qN4EjwSEHg8wEqYe9pkmVrtRP", "t2Ez9KM8VJLuArcxuEkNRAkhNvidKkzXcjJ", "t2D5y7J5fpXajLbGrMBQkFg2mFN8fo3n8cX", "t2UV2wr1PTaUiybpkV3FdSdGxUJeZdZztyt" + ] } diff --git a/coins/zclassic.json b/coins/zclassic.json index 42a0f51..443025d 100644 --- a/coins/zclassic.json +++ b/coins/zclassic.json @@ -2,5 +2,6 @@ "name": "zclassic", "symbol": "zcl", "algorithm": "equihash", + "requireShielding": true, "peerMagic": "24e92764" } diff --git a/libs/api.js b/libs/api.js index 8d6a6c5..e2da111 100644 --- a/libs/api.js +++ b/libs/api.js @@ -19,6 +19,13 @@ module.exports = function(logger, portalConfig, poolConfigs){ return; case 'pool_stats': res.end(JSON.stringify(portalStats.statPoolHistory)); + return; + case 'payments': + var poolBlocks = []; + for(var pool in portalStats.stats.pools) { + poolBlocks.push({name: pool, pending: portalStats.stats.pools[pool].pending, payments: portalStats.stats.pools[pool].payments}); + } + res.end(JSON.stringify(poolBlocks)); return; case 'worker_stats': if (req.url.indexOf("?")>0) { @@ -56,7 +63,6 @@ module.exports = function(logger, portalConfig, poolConfigs){ //console.log(portalStats.statHistory[h].time); } } - // note, h is the last record from above loop, which is latest for(var pool in portalStats.stats.pools) { for(var w in portalStats.stats.pools[pool].workers){ if (w.startsWith(address)) { diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index d7186fc..26c01d0 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -1,4 +1,5 @@ var fs = require('fs'); +var request = require("request"); var redis = require('redis'); var async = require('async'); @@ -50,6 +51,13 @@ function SetupForPool(logger, poolOptions, setupFinished){ var logSystem = 'Payments'; var logComponent = coin; var opidCount = 0; + + var minConfShield = 3; + var minConfPayout = 10; + + var requireShielding = poolOptions.coin.requireShielding === true; + + logger.special(logSystem, logComponent, logComponent + ' requireShielding: ' + requireShielding); var daemon = new Stratum.daemon.interface([processingConfig.daemon], function(severity, message){ logger[severity](logSystem, logComponent, message); @@ -279,111 +287,122 @@ function SetupForPool(logger, poolOptions, setupFinished){ ); } - function cacheZCashNetworkStats () { + + function cacheNetworkStats () { var params = null; daemon.cmd('getmininginfo', params, function (result) { + var finalRedisCommands = []; + var coin = logComponent; + if (result.error) { - logger.error(logSystem, logComponent, 'Error getting stats from zcashd' + logger.error(logSystem, logComponent, 'Error with RPC call `getmininginfo`' + JSON.stringify(result.error)); + return; } else { - logger.special(logSystem, logComponent, "Updating "+logComponent+" network stats..."); - var coin = logComponent; - var finalRedisCommands = []; - finalRedisCommands.push(['hset', coin + ':stats', 'networkBlocks', result[0].response.blocks]); - finalRedisCommands.push(['hset', coin + ':stats', 'networkDiff', result[0].response.difficulty]); - finalRedisCommands.push(['hset', coin + ':stats', 'networkSols', result[0].response.networksolps]); - redisClient.multi(finalRedisCommands).exec(function(error, results){ - if (error){ - logger.error(logSystem, logComponent, 'Could not update zcash stats to redis ' + JSON.stringify(error)); - return; - } - }); + if (result[0].response.blocks !== null) { + finalRedisCommands.push(['hset', coin + ':stats', 'networkBlocks', result[0].response.blocks]); + finalRedisCommands.push(['hset', coin + ':stats', 'networkDiff', result[0].response.difficulty]); + finalRedisCommands.push(['hset', coin + ':stats', 'networkSols', result[0].response.networksolps]); + } else { + logger.error(logSystem, logComponent, "Error parse RPC call reponse.blocks tp `getmininginfo`." + JSON.stringify(result[0].response)); + } } - daemon.cmd('getinfo', params, + + daemon.cmd('getnetworkinfo', params, function (result) { if (result.error) { - logger.error(logSystem, logComponent, 'Error getting stats from zcashd' + logger.error(logSystem, logComponent, 'Error with RPC call `getnetworkinfo`' + JSON.stringify(result.error)); + return; } else { - var coin = logComponent; - var finalRedisCommands = []; - finalRedisCommands.push(['hset', coin + ':stats', 'networkConnections', result[0].response.connections]); - redisClient.multi(finalRedisCommands).exec(function(error, results){ - if (error){ - logger.error(logSystem, logComponent, 'Could not update zcash stats to redis ' + JSON.stringify(error)); - return; - } - }); + if (result[0].response !== null) { + finalRedisCommands.push(['hset', coin + ':stats', 'networkConnections', result[0].response.connections]); + finalRedisCommands.push(['hset', coin + ':stats', 'networkVersion', result[0].response.version]); + finalRedisCommands.push(['hset', coin + ':stats', 'networkSubVersion', result[0].response.subversion]); + finalRedisCommands.push(['hset', coin + ':stats', 'networkProtocolVersion', result[0].response.protocolversion]); + } else { + logger.error(logSystem, logComponent, "Error parse RPC call response to `getnetworkinfo`." + JSON.stringify(result[0].response)); + } } + redisClient.multi(finalRedisCommands).exec(function(error, results){ + if (error){ + logger.error(logSystem, logComponent, 'Error update coin stats to redis ' + JSON.stringify(error)); + return; + } + }); } - ); + ); } ); } - + // run coinbase coin transfers every x minutes var intervalState = 0; // do not send ZtoT and TtoZ and same time, this results in operation failed! var interval = poolOptions.walletInterval * 60 * 1000; // run every x minutes setInterval(function() { - intervalState++; - switch (intervalState){ - case 1: - listUnspent(poolOptions.address, null, 1, false, sendTToZ); - break; - default: - listUnspentZ(poolOptions.zAddress, 1, false, sendZToT); - //listUnspent(null, poolOptions.address, 1, true, function (){}); - intervalState = 0; - break; + // shielding not required for some equihash coins + if (requireShielding === true) { + intervalState++; + switch (intervalState) { + case 1: + listUnspent(poolOptions.address, null, minConfShield, false, sendTToZ); + break; + default: + listUnspentZ(poolOptions.zAddress, minConfShield, false, sendZToT); + intervalState = 0; + break; + } } - // update zcash stats - cacheZCashNetworkStats(); + // update network stats using coin daemon + cacheNetworkStats(); }, interval); - + // check operation statuses every x seconds var opid_interval = poolOptions.walletInterval * 1000; - setInterval(function(){ - var checkOpIdSuccessAndGetResult = function(ops) { - ops.forEach(function(op, i){ - if (op.status == "success" || op.status == "failed") { - daemon.cmd('z_getoperationresult', [[op.id]], function (result) { - if (result.error) { - logger.warning(logSystem, logComponent, 'Unable to get payment operation id result ' + JSON.stringify(result)); - } - if (result.response) { - if (opidCount > 0) { - opidCount = 0; + // shielding not required for some equihash coins + if (requireShielding === true) { + setInterval(function(){ + var checkOpIdSuccessAndGetResult = function(ops) { + ops.forEach(function(op, i){ + if (op.status == "success" || op.status == "failed") { + daemon.cmd('z_getoperationresult', [[op.id]], function (result) { + if (result.error) { + logger.warning(logSystem, logComponent, 'Unable to get payment operation id result ' + JSON.stringify(result)); } - if (op.status == "failed") { - if (op.error) { - logger.error(logSystem, logComponent, "Payment operation failed " + op.id + " " + op.error.code +", " + op.error.message); - } else { - logger.error(logSystem, logComponent, "Payment operation failed " + op.id); + if (result.response) { + if (opidCount > 0) { + opidCount = 0; + } + if (op.status == "failed") { + if (op.error) { + logger.error(logSystem, logComponent, "Payment operation failed " + op.id + " " + op.error.code +", " + op.error.message); + } else { + logger.error(logSystem, logComponent, "Payment operation failed " + op.id); + } + } else { + logger.special(logSystem, logComponent, 'Payment operation success ' + op.id + ' txid: ' + op.result.txid); } - } else { - logger.special(logSystem, logComponent, 'Payment operation success ' + op.id + ' txid: ' + op.result.txid); } + }, true, true); + } else if (op.status == "executing") { + if (opidCount == 0) { + opidCount++; + logger.special(logSystem, logComponent, 'Payment operation in progress ' + op.id ); } - }, true, true); - } else if (op.status == "executing") { - if (opidCount == 0) { - opidCount++; - logger.special(logSystem, logComponent, 'Payment operation in progress ' + op.id ); } - } - }); - }; - daemon.cmd('z_getoperationstatus', null, function (result) { - if (result.error) { - logger.warning(logSystem, logComponent, 'Unable to get operation ids for clearing.'); - } - if (result.response) { - checkOpIdSuccessAndGetResult(result.response); - } - }, true, true); - }, opid_interval); - + }); + }; + daemon.cmd('z_getoperationstatus', null, function (result) { + if (result.error) { + logger.warning(logSystem, logComponent, 'Unable to get operation ids for clearing.'); + } + if (result.response) { + checkOpIdSuccessAndGetResult(result.response); + } + }, true, true); + }, opid_interval); + } var satoshisToCoins = function(satoshis){ return parseFloat((satoshis / magnitude).toFixed(coinPrecision)); @@ -478,7 +497,7 @@ function SetupForPool(logger, poolOptions, setupFinished){ } // update confirmations in redis for pending blocks - var confirmsUpdate = blockDetails.map(function(b){ + var confirmsUpdate = blockDetails.map(function(b) { if (b.result != null && b.result.confirmations > 0) { if (b.result.confirmations > 100) { return ['hdel', logComponent + ':blocksPendingConfirms', b.result.hash]; @@ -609,10 +628,16 @@ function SetupForPool(logger, poolOptions, setupFinished){ + round.txHash); return; } - + + // TODO, estimate transaction fees, make dynamic + var fee = 0.00005; // komodo + if (logComponent != "komodo") { + fee = 0.0004; // all other coins + } + round.category = generationTx.category; if (round.category === 'generate') { - round.reward = generationTx.amount - 0.0004 || generationTx.value - 0.0004; // TODO: Adjust fees to be dynamic + round.reward = balanceRound(generationTx.amount - fee) || balanceRound(generationTx.value - fee); // TODO: Adjust fees to be dynamic } }); @@ -643,18 +668,32 @@ function SetupForPool(logger, poolOptions, setupFinished){ } }); - // check if we have enough tAddress funds to send payments - var totalOwed = 0; - for (var i = 0; i < rounds.length; i++) { - totalOwed = totalOwed + (rounds[i].reward * magnitude) - 4000; // TODO: make tx fees dynamic + // TODO, estimate transaction fees, make dynamic + var fee = 500; // komodo + if (logComponent != "komodo") { + fee = 4000; // all other coins } - listUnspent(null, poolOptions.address, 1, false, function (error, tBalance){ - if (tBalance < totalOwed) { - logger.error(logSystem, logComponent, (tBalance / magnitude).toFixed(8) + ' is not enough payment funds to process ' + (totalOwed / magnitude).toFixed(8) + ' of payments. (Possibly due to pending txs)'); + // calculate what the pool owes its miners + var totalOwed = parseInt(0); + for (var i = 0; i < rounds.length; i++) { + totalOwed = totalOwed + Math.round(rounds[i].reward * magnitude) - fee; // TODO: make tx fees dynamic + } + + var notAddr = null; + if (requireShielding === true) { + notAddr = poolOptions.address; + } + + // check if we have enough tAddress funds to brgin payment processing + listUnspent(null, notAddr, minConfPayout, false, function (error, tBalance){ + if (error) { + logger.error(logSystem, logComponent, 'Error checking pool balance before payouts. (Unable to begin payment process)'); + return callback(true); + } else if (tBalance < totalOwed) { + logger.error(logSystem, logComponent, 'Insufficient pool funds to being payment process; '+(tBalance / magnitude).toFixed(8) + ' < ' + (totalOwed / magnitude).toFixed(8)+'. (Possibly due to pending txs) '); return callback(true); - } - else { + } else { // zcash daemon does not support account feature addressAccount = ""; callback(null, workers, rounds, addressAccount); @@ -851,7 +890,7 @@ function SetupForPool(logger, poolOptions, setupFinished){ return parseInt(r.height); }); var paymentsUpdate = []; - var paymentsData = [{txid:txid, paid:balanceRound(totalSent / magnitude), shares:totalShares, miners:Object.keys(addressAmounts).length}, {blocks: paymentBlocks}, addressAmounts]; + var paymentsData = {time:Date.now(), txid:txid, shares:totalShares, paid:balanceRound(totalSent / magnitude), miners:Object.keys(addressAmounts).length, blocks: paymentBlocks, amounts: addressAmounts}; paymentsUpdate.push(['zadd', logComponent + ':payments', Date.now(), JSON.stringify(paymentsData)]); startRedisTimer(); redisClient.multi(paymentsUpdate).exec(function(error, payments){ @@ -882,11 +921,12 @@ function SetupForPool(logger, poolOptions, setupFinished){ }, function(workers, rounds, callback){ - var totalPaid = 0; + var totalPaid = parseFloat(0); var balanceUpdateCommands = []; var workerPayoutsCommand = []; + // update worker paid/balance stats for (var w in workers) { var worker = workers[w]; if (worker.balanceChange !== 0){ @@ -916,6 +956,7 @@ function SetupForPool(logger, poolOptions, setupFinished){ } }; + // handle the round rounds.forEach(function(r){ switch(r.category){ case 'kicked': @@ -994,5 +1035,4 @@ function SetupForPool(logger, poolOptions, setupFinished){ else return address; }; - } diff --git a/libs/stats.js b/libs/stats.js index 7b0227d..f8e80cf 100644 --- a/libs/stats.js +++ b/libs/stats.js @@ -2,7 +2,6 @@ var zlib = require('zlib'); var redis = require('redis'); var async = require('async'); -//var fancyTimestamp = require('fancy-timestamp'); var os = require('os'); @@ -176,11 +175,18 @@ module.exports = function(logger, portalConfig, poolConfigs){ var client = redisClients[0].client, coins = redisClients[0].coins, shares = []; - var totalShares = 0; + + var pindex = parseInt(0); + 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+"*", function(error, result) { - var workerName = ""; + if (error) { + pcb(error); + return; + } + var workerName=""; var shares = 0; for (var i in result[1]) { if (Math.abs(i % 2) != 1) { @@ -189,15 +195,20 @@ module.exports = function(logger, portalConfig, poolConfigs){ shares += parseFloat(result[1][i]); } } - totalShares = shares; - pcb(); + if (shares>0) { + totalShares = shares; + } + pcb(); }); }, function(err) { - if (err) { - cback(0); - return; - } - cback(totalShares); + if (err) { + cback(0); + return; + } + if (totalShares > 0 || (pindex >= Object.keys(_this.stats.pools).length)) { + cback(totalShares); + return; + } }); }; @@ -285,7 +296,7 @@ module.exports = function(logger, portalConfig, poolConfigs){ ['smembers', ':blocksConfirmed'], ['hgetall', ':shares:roundCurrent'], ['hgetall', ':blocksPendingConfirms'], - ['hgetall', ':payments'] + ['zrange', ':payments', -100, -1] ]; var commandsPerCoin = redisCommandTemplates.length; @@ -320,23 +331,31 @@ module.exports = function(logger, portalConfig, poolConfigs){ 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 + 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 }, + /* block stat counts */ blocks: { pending: replies[i + 3], confirmed: replies[i + 4], orphaned: replies[i + 5] }, + /* show all pending blocks */ pending: { blocks: replies[i + 6].sort(sortBlocks), confirms: replies[i + 9] }, + /* show last 5 found blocks */ confirmed: { - blocks: replies[i + 7].sort(sortBlocks) + blocks: replies[i + 7].sort(sortBlocks).slice(0,5) }, - payments: replies[i + 10], + payments: [], currentRoundShares: replies[i + 8] }; + for(var j = replies[i + 10].length; j > 0; j--){ + coinStats.payments.push(JSON.parse(replies[i + 10][j-1])); + } /* for (var b in coinStats.confirmed.blocks) { var parms = coinStats.confirmed.blocks[b].split(':'); @@ -460,7 +479,8 @@ module.exports = function(logger, portalConfig, poolConfigs){ 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 = 250; + + 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); @@ -481,7 +501,7 @@ module.exports = function(logger, portalConfig, poolConfigs){ portalStats.algos[algo].hashrate += coinStats.hashrate; portalStats.algos[algo].workers += Object.keys(coinStats.workers).length; - var _shareTotal = 0; + var _shareTotal = parseFloat(0); for (var worker in coinStats.currentRoundShares) { var miner = worker.split(".")[0]; if (miner in coinStats.miners) { @@ -492,10 +512,9 @@ module.exports = function(logger, portalConfig, poolConfigs){ } _shareTotal += parseFloat(coinStats.currentRoundShares[worker]); } - coinStats.shareCount = Math.round(_shareTotal * 100) / 100; + coinStats.shareCount = _shareTotal; for (var worker in coinStats.workers) { - var _blocktime = 250; 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); @@ -504,7 +523,6 @@ module.exports = function(logger, portalConfig, poolConfigs){ coinStats.workers[worker].hashrateString = _this.getReadableHashRateString(_workerRate); } for (var miner in coinStats.miners) { - var _blocktime = 250; 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); @@ -524,13 +542,20 @@ module.exports = function(logger, portalConfig, poolConfigs){ var algoStats = portalStats.algos[algo]; algoStats.hashrateString = _this.getReadableHashRateString(algoStats.hashrate); }); - - // TODO, create stats object and copy elements from portalStats we want to display... - var showStats = portalStats; - + _this.stats = portalStats; - _this.statsString = JSON.stringify(portalStats); - _this.statHistory.push(portalStats); + + // save historical hashrate, not entire stats! + var saveStats = JSON.parse(JSON.stringify(portalStats)); + Object.keys(saveStats.pools).forEach(function(pool){ + delete saveStats.pools[pool].pending; + delete saveStats.pools[pool].confirmed; + delete saveStats.pools[pool].currentRoundShares; + delete saveStats.pools[pool].payments; + delete saveStats.pools[pool].miners; + }); + _this.statsString = JSON.stringify(saveStats); + _this.statHistory.push(saveStats); addStatPoolHistory(portalStats); diff --git a/libs/website.js b/libs/website.js index 7c8f964..a59e58b 100644 --- a/libs/website.js +++ b/libs/website.js @@ -230,7 +230,6 @@ module.exports = function(logger){ var payout = function(req, res, next){ var address = req.params.address || null; - if (address != null){ portalStats.getPayout(address, function(data){ res.write(data.toString()); @@ -241,26 +240,20 @@ module.exports = function(logger){ next(); }; - var shares = function(req, res, next){ portalStats.getCoins(function(){ processTemplates(); - res.end(indexesProcessed['user_shares']); }); }; var usershares = function(req, res, next){ - var coin = req.params.coin || null; - if(coin != null){ portalStats.getCoinTotals(coin, null, function(){ processTemplates(); - res.end(indexesProcessed['user_shares']); - }); } else diff --git a/pool_configs/komodo_example.json b/pool_configs/komodo_example.json new file mode 100644 index 0000000..acbcda3 --- /dev/null +++ b/pool_configs/komodo_example.json @@ -0,0 +1,82 @@ +{ + "enabled":false, + "coin": "komodo.json", + + "address": "", + "_comment_address": "pools komodo address; ex, RSXGTHQSqwcMw1vowKfEE7sQ8fAmv1tmso", + + "zAddress": "", + "_comment_zAddress": "shielding not required in komodo, not used", + + "tAddress": "", + "_comment_tAddress": "set to same as pools komodo address; ex, RSXGTHQSqwcMw1vowKfEE7sQ8fAmv1tmso", + + "walletInterval": 1, + "_comment_walletInterval": "Used to cache komodo coin stats, shielding not performed.", + + "rewardRecipients": { + "": 1.0 + }, + + "tlsOptions": { + "enabled": false, + "serverKey":"", + "serverCert":"", + "ca":"" + }, + + "paymentProcessing": { + "enabled": true, + "paymentInterval": 57, + "_comment_paymentInterval": "Interval in seconds to check and perform payments.", + "minimumPayment": 0.1, + "daemon": { + "host": "127.0.0.1", + "port": 8232, + "user": "username", + "password": "password" + } + }, + + "ports": { + "3857": { + "tls":false, + "diff": 0.05, + "varDiff": { + "minDiff": 0.04, + "maxDiff": 16, + "targetTime": 15, + "retargetTime": 60, + "variancePercent": 30 + } + } + }, + + "daemons": [ + { + "host": "127.0.0.1", + "port": 8232, + "user": "username", + "password": "password" + } + ], + + "p2p": { + "enabled": false, + "host": "127.0.0.1", + "port": 19333, + "disableTransactions": true + }, + + "mposMode": { + "enabled": false, + "host": "127.0.0.1", + "port": 3306, + "user": "me", + "password": "mypass", + "database": "kmd", + "checkPassword": true, + "autoCreateWorker": false + } + +} diff --git a/website/pages/miner_stats.html b/website/pages/miner_stats.html index 7a79e6b..328db5d 100644 --- a/website/pages/miner_stats.html +++ b/website/pages/miner_stats.html @@ -88,8 +88,8 @@
Shares: ...
-
Bal: ... ZEC
-
Paid: ... ZEC
+
Bal: ...
+
Paid: ...